"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const bignumber_js_1 = __importDefault(require("bignumber.js"));
const sinon_1 = __importDefault(require("sinon"));
const internal_1 = require("../../../../internal");
const queries_1 = require("../../../../middleware/queries");
const types_1 = require("../../../../middleware/types");
const mocks_1 = require("../../../../testUtils/mocks");
const types_2 = require("../../../../types");
const utils_1 = require("../../../../types/utils");
const constants_1 = require("../../../../utils/constants");
const utilsConversionModule = __importStar(require("../../../../utils/conversion"));
const utilsInternalModule = __importStar(require("../../../../utils/internal"));
const TokenPermissions_1 = require("../TokenPermissions");
jest.mock('~/base/Procedure', require("../../../../testUtils/mocks/procedure").mockProcedureModule('~/base/Procedure'));
describe('TokenPermissions class', () => {
    const did = 'someDid';
    const ticker = 'SOMETICKER';
    let token;
    let context;
    let tokenPermissions;
    let identity;
    beforeAll(() => {
        mocks_1.dsMockUtils.initMocks();
        mocks_1.entityMockUtils.initMocks();
        mocks_1.procedureMockUtils.initMocks();
    });
    beforeEach(() => {
        context = mocks_1.dsMockUtils.getContextInstance();
        identity = mocks_1.entityMockUtils.getIdentityInstance({ did });
        token = mocks_1.entityMockUtils.getSecurityTokenInstance({ ticker });
        tokenPermissions = new TokenPermissions_1.TokenPermissions(identity, context);
    });
    afterEach(() => {
        mocks_1.entityMockUtils.reset();
        mocks_1.dsMockUtils.reset();
        mocks_1.procedureMockUtils.reset();
    });
    afterAll(() => {
        mocks_1.entityMockUtils.cleanup();
        mocks_1.dsMockUtils.cleanup();
        mocks_1.procedureMockUtils.cleanup();
    });
    test('should extend namespace', () => {
        expect(TokenPermissions_1.TokenPermissions.prototype instanceof internal_1.Namespace).toBe(true);
    });
    describe('method: getGroup', () => {
        test('should throw an error if the Identity is no longer an Agent', () => __awaiter(void 0, void 0, void 0, function* () {
            mocks_1.dsMockUtils.createQueryStub('externalAgents', 'groupOfAgent', {
                returnValue: mocks_1.dsMockUtils.createMockOption(),
            });
            let error;
            try {
                yield tokenPermissions.getGroup({ token });
            }
            catch (err) {
                error = err;
            }
            expect(error.message).toBe('This Identity is no longer an Agent for this Security Token');
        }));
        test('should return the permission group associated with the Agent', () => __awaiter(void 0, void 0, void 0, function* () {
            mocks_1.dsMockUtils.createQueryStub('externalAgents', 'groupOfAgent', {
                returnValue: mocks_1.dsMockUtils.createMockOption(mocks_1.dsMockUtils.createMockAgentGroup('Full')),
            });
            const result = yield tokenPermissions.getGroup({ token });
            expect(result instanceof internal_1.KnownPermissionGroup).toEqual(true);
            expect(result.type).toEqual(types_2.PermissionGroupType.Full);
        }));
    });
    describe('method: enabledAt', () => {
        test('should return the event identifier object of the agent added', () => __awaiter(void 0, void 0, void 0, function* () {
            const blockNumber = new bignumber_js_1.default(1234);
            const blockDate = new Date('4/14/2020');
            const eventIdx = 1;
            const variables = {
                moduleId: types_1.ModuleIdEnum.Externalagents,
                eventId: types_1.EventIdEnum.AgentAdded,
                eventArg1: utilsInternalModule.padString(ticker, constants_1.MAX_TICKER_LENGTH),
            };
            const fakeResult = { blockNumber, blockDate, eventIndex: eventIdx };
            mocks_1.dsMockUtils.createApolloQueryStub(queries_1.eventByIndexedArgs(variables), {
                /* eslint-disable @typescript-eslint/naming-convention */
                eventByIndexedArgs: {
                    block_id: blockNumber.toNumber(),
                    block: { datetime: blockDate },
                    event_idx: eventIdx,
                },
                /* eslint-enable @typescript-eslint/naming-convention */
            });
            const result = yield tokenPermissions.enabledAt({ token });
            expect(result).toEqual(fakeResult);
        }));
        test('should return null if the query result is empty', () => __awaiter(void 0, void 0, void 0, function* () {
            const variables = {
                moduleId: types_1.ModuleIdEnum.Externalagents,
                eventId: types_1.EventIdEnum.AgentAdded,
                eventArg1: utilsInternalModule.padString(ticker, constants_1.MAX_TICKER_LENGTH),
            };
            mocks_1.dsMockUtils.createApolloQueryStub(queries_1.eventByIndexedArgs(variables), {});
            const result = yield tokenPermissions.enabledAt({ token });
            expect(result).toBeNull();
        }));
    });
    describe('method: setGroup', () => {
        test('should prepare the procedure and return the resulting transaction queue', () => __awaiter(void 0, void 0, void 0, function* () {
            const group = {
                transactions: {
                    type: types_2.PermissionType.Include,
                    values: [],
                },
                token,
            };
            const expectedQueue = 'someQueue';
            mocks_1.procedureMockUtils
                .getPrepareStub()
                .withArgs({ args: { identity, group }, transformer: undefined }, context)
                .resolves(expectedQueue);
            const queue = yield tokenPermissions.setGroup({ group });
            expect(queue).toBe(expectedQueue);
        }));
    });
    describe('method: checkPermissions', () => {
        beforeAll(() => {
            mocks_1.entityMockUtils.initMocks();
        });
        afterEach(() => {
            mocks_1.entityMockUtils.reset();
        });
        afterAll(() => {
            mocks_1.entityMockUtils.cleanup();
        });
        test('should check whether the Identity has the appropriate permissions for the token', () => __awaiter(void 0, void 0, void 0, function* () {
            mocks_1.dsMockUtils.createQueryStub('externalAgents', 'groupOfAgent', {
                returnValue: mocks_1.dsMockUtils.createMockOption(),
            });
            let result = yield tokenPermissions.checkPermissions({ token, transactions: null });
            expect(result).toEqual({
                result: false,
                missingPermissions: null,
                message: 'The Identity is not an Agent for the Security Token',
            });
            mocks_1.dsMockUtils.createQueryStub('externalAgents', 'groupOfAgent', {
                returnValue: mocks_1.dsMockUtils.createMockOption(mocks_1.dsMockUtils.createMockAgentGroup('Full')),
            });
            result = yield tokenPermissions.checkPermissions({ token, transactions: null });
            expect(result).toEqual({ result: true });
            mocks_1.dsMockUtils.createQueryStub('externalAgents', 'groupOfAgent', {
                returnValue: mocks_1.dsMockUtils.createMockOption(mocks_1.dsMockUtils.createMockAgentGroup('ExceptMeta')),
            });
            result = yield tokenPermissions.checkPermissions({ token, transactions: null });
            expect(result).toEqual({ result: false, missingPermissions: null });
            result = yield tokenPermissions.checkPermissions({
                token,
                transactions: [types_2.TxTags.externalAgents.RemoveAgent],
            });
            expect(result).toEqual({
                result: false,
                missingPermissions: [types_2.TxTags.externalAgents.RemoveAgent],
            });
            result = yield tokenPermissions.checkPermissions({
                token,
                transactions: [types_2.TxTags.asset.ControllerTransfer],
            });
            expect(result).toEqual({ result: true });
            mocks_1.dsMockUtils.createQueryStub('externalAgents', 'groupOfAgent', {
                returnValue: mocks_1.dsMockUtils.createMockOption(mocks_1.dsMockUtils.createMockAgentGroup('PolymeshV1Pia')),
            });
            result = yield tokenPermissions.checkPermissions({
                token,
                transactions: [types_2.TxTags.asset.CreateAsset],
            });
            expect(result).toEqual({
                result: false,
                missingPermissions: [types_2.TxTags.asset.CreateAsset],
            });
            result = yield tokenPermissions.checkPermissions({
                token,
                transactions: [types_2.TxTags.asset.ControllerTransfer, types_2.TxTags.sto.Invest],
            });
            expect(result).toEqual({
                result: false,
                missingPermissions: [types_2.TxTags.sto.Invest],
            });
            result = yield tokenPermissions.checkPermissions({
                token,
                transactions: [types_2.TxTags.asset.ControllerTransfer, types_2.TxTags.sto.FreezeFundraiser],
            });
            expect(result).toEqual({
                result: true,
            });
            mocks_1.dsMockUtils.createQueryStub('externalAgents', 'groupOfAgent', {
                returnValue: mocks_1.dsMockUtils.createMockOption(mocks_1.dsMockUtils.createMockAgentGroup('PolymeshV1Caa')),
            });
            result = yield tokenPermissions.checkPermissions({
                token,
                transactions: [types_2.TxTags.asset.CreateAsset],
            });
            expect(result).toEqual({
                result: false,
                missingPermissions: [types_2.TxTags.asset.CreateAsset],
            });
            result = yield tokenPermissions.checkPermissions({
                token,
                transactions: [types_2.TxTags.corporateAction.ChangeRecordDate],
            });
            expect(result).toEqual({
                result: true,
            });
            mocks_1.dsMockUtils.createQueryStub('externalAgents', 'groupOfAgent', {
                returnValue: mocks_1.dsMockUtils.createMockOption(mocks_1.dsMockUtils.createMockAgentGroup({ Custom: mocks_1.dsMockUtils.createMockU32(1) })),
            });
            mocks_1.dsMockUtils.createQueryStub('externalAgents', 'groupPermissions', {
                returnValue: mocks_1.dsMockUtils.createMockOption(mocks_1.dsMockUtils.createMockExtrinsicPermissions('Whole')),
            });
            result = yield tokenPermissions.checkPermissions({
                token,
                transactions: [types_2.TxTags.corporateAction.ChangeRecordDate],
            });
            expect(result).toEqual({
                result: true,
            });
            /* eslint-disable @typescript-eslint/naming-convention */
            mocks_1.dsMockUtils.createQueryStub('externalAgents', 'groupPermissions', {
                returnValue: mocks_1.dsMockUtils.createMockOption(mocks_1.dsMockUtils.createMockExtrinsicPermissions({
                    These: [
                        mocks_1.dsMockUtils.createMockPalletPermissions({
                            pallet_name: 'asset',
                            dispatchable_names: {
                                Except: [mocks_1.dsMockUtils.createMockDispatchableName('createAsset')],
                            },
                        }),
                    ],
                })),
            });
            result = yield tokenPermissions.checkPermissions({
                token,
                transactions: null,
            });
            expect(result).toEqual({
                result: false,
                missingPermissions: null,
            });
            result = yield tokenPermissions.checkPermissions({
                token,
                transactions: [types_2.TxTags.asset.CreateAsset],
            });
            expect(result).toEqual({
                result: false,
                missingPermissions: [types_2.TxTags.asset.CreateAsset],
            });
            mocks_1.dsMockUtils.createQueryStub('externalAgents', 'groupPermissions', {
                returnValue: mocks_1.dsMockUtils.createMockOption(mocks_1.dsMockUtils.createMockExtrinsicPermissions({
                    Except: [
                        mocks_1.dsMockUtils.createMockPalletPermissions({
                            pallet_name: 'asset',
                            dispatchable_names: 'Whole',
                        }),
                    ],
                })),
            });
            result = yield tokenPermissions.checkPermissions({
                token,
                transactions: [types_2.TxTags.identity.AddClaim],
            });
            expect(result).toEqual({
                result: true,
            });
            /* eslint-enable @typescript-eslint/naming-convention */
        }));
        test('should throw an error if the transaction array is empty', () => __awaiter(void 0, void 0, void 0, function* () {
            expect(tokenPermissions.checkPermissions({ token, transactions: [] })).rejects.toThrow('Cannot check Permissions for an empty transaction array');
        }));
    });
    describe('method: hasPermissions', () => {
        beforeAll(() => {
            mocks_1.entityMockUtils.initMocks();
        });
        afterEach(() => {
            mocks_1.entityMockUtils.reset();
        });
        afterAll(() => {
            mocks_1.entityMockUtils.cleanup();
        });
        test('should check whether the Identity has the appropriate permissions for the token', () => __awaiter(void 0, void 0, void 0, function* () {
            mocks_1.dsMockUtils.createQueryStub('externalAgents', 'groupOfAgent', {
                returnValue: mocks_1.dsMockUtils.createMockOption(),
            });
            const result = yield tokenPermissions.hasPermissions({ token, transactions: null });
            expect(result).toBe(false);
        }));
    });
    describe('method: waive', () => {
        test('should prepare the procedure with the correct arguments and context, and return the resulting transaction queue', () => __awaiter(void 0, void 0, void 0, function* () {
            const args = {
                token,
                identity,
            };
            const expectedQueue = 'someQueue';
            mocks_1.procedureMockUtils
                .getPrepareStub()
                .withArgs({ args, transformer: undefined }, context)
                .resolves(expectedQueue);
            const queue = yield tokenPermissions.waive(args);
            expect(queue).toBe(expectedQueue);
        }));
    });
    describe('method: get', () => {
        let rawDid;
        let rawTicker;
        let stringToIdentityIdStub;
        beforeAll(() => {
            stringToIdentityIdStub = sinon_1.default.stub(utilsConversionModule, 'stringToIdentityId');
            rawDid = mocks_1.dsMockUtils.createMockIdentityId(did);
            rawTicker = mocks_1.dsMockUtils.createMockTicker(ticker);
        });
        beforeEach(() => {
            stringToIdentityIdStub.withArgs(did, context).returns(rawDid);
        });
        afterAll(() => {
            sinon_1.default.restore();
        });
        test('should return a list of AgentWithGroup', () => __awaiter(void 0, void 0, void 0, function* () {
            const group = mocks_1.entityMockUtils.getKnownPermissionGroupInstance({
                ticker,
                type: types_2.PermissionGroupType.Full,
                getPermissions: {
                    transactions: null,
                    transactionGroups: [],
                },
            });
            mocks_1.entityMockUtils.configureMocks({
                securityTokenOptions: {
                    ticker,
                },
            });
            sinon_1.default.stub(tokenPermissions, 'getGroup').resolves(group);
            mocks_1.dsMockUtils.createQueryStub('externalAgents', 'agentOf', {
                entries: [utils_1.tuple([rawDid, rawTicker], {})],
            });
            const result = yield tokenPermissions.get();
            expect(result.length).toEqual(1);
            expect(result[0].token.ticker).toEqual(ticker);
            expect(result[0].group instanceof internal_1.KnownPermissionGroup).toEqual(true);
        }));
    });
    describe('method: getOperationHistory', () => {
        test('should return the Events triggered by Operations the Identity has performed on a specific Security Token', () => __awaiter(void 0, void 0, void 0, function* () {
            const blockId = new bignumber_js_1.default(1);
            const blockHash = 'someHash';
            const eventIndex = 1;
            const datetime = '2020-10-10';
            mocks_1.dsMockUtils.createQueryStub('system', 'blockHash', {
                multi: [mocks_1.dsMockUtils.createMockHash(blockHash)],
            });
            /* eslint-disable @typescript-eslint/naming-convention */
            mocks_1.dsMockUtils.createApolloQueryStub(queries_1.tickerExternalAgentActions({
                ticker,
                caller_did: did,
                pallet_name: undefined,
                event_id: undefined,
                count: undefined,
                skip: undefined,
            }), {
                tickerExternalAgentActions: {
                    totalCount: 1,
                    items: [
                        {
                            block_id: blockId.toNumber(),
                            datetime,
                            event_idx: eventIndex,
                        },
                    ],
                },
            });
            /* eslint-enable @typescript-eslint/naming-convention */
            let result = yield tokenPermissions.getOperationHistory({
                token: ticker,
            });
            expect(result.next).toEqual(null);
            expect(result.count).toEqual(1);
            expect(result.data).toEqual([
                {
                    blockNumber: blockId,
                    blockHash,
                    blockDate: new Date(`${datetime}Z`),
                    eventIndex,
                },
            ]);
            /* eslint-disable @typescript-eslint/naming-convention */
            mocks_1.dsMockUtils.createApolloQueryStub(queries_1.tickerExternalAgentActions({
                ticker,
                caller_did: did,
                pallet_name: undefined,
                event_id: undefined,
                count: undefined,
                skip: undefined,
            }), {
                tickerExternalAgentActions: {
                    totalCount: 0,
                    items: [],
                },
            });
            /* eslint-enable @typescript-eslint/naming-convention */
            result = yield tokenPermissions.getOperationHistory({
                token: ticker,
            });
            expect(result.next).toEqual(null);
            expect(result.count).toEqual(0);
            expect(result.data).toEqual([]);
        }));
    });
});
//# sourceMappingURL=TokenPermissions.js.map