"use strict";
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
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());
    });
};
Object.defineProperty(exports, "__esModule", { value: true });
const internal_1 = require("../../../internal");
const Storage_1 = require("../../../Storage");
const testHelper_1 = require("../../testHelper");
const projectionTestUtils_1 = require("../../Utilities/projectionTestUtils");
/**
 * A test class for testing the ArrayExpansion operation in a projection as well as Expansion in a resolution guidance
 */
describe('Cdm/Projection/ProjectionExpansionTest', () => {
    /**
     * All possible combinations of the different resolution directives
     */
    const resOptsCombinations = [
        [],
        ['referenceOnly'],
        ['normalized'],
        ['structured'],
        ['referenceOnly', 'normalized'],
        ['referenceOnly', 'structured'],
        ['normalized', 'structured'],
        ['referenceOnly', 'normalized', 'structured']
    ];
    /**
     * The path between TestDataPath and TestName.
     */
    const testsSubpath = 'Cdm/Projection/ProjectionExpansionTest';
    /**
     * Test for creating a projection with an ArrayExpansion operation on an entity attribute using the object model
     */
    it('TestEntityAttributeProjUsingObjectModel', () => __awaiter(void 0, void 0, void 0, function* () {
        const corpus = testHelper_1.testHelper.getLocalCorpus(testsSubpath, 'TestEntityAttributeProjUsingObjectModel');
        corpus.storage.mount('local', new Storage_1.LocalAdapter(testHelper_1.testHelper.getActualOutputFolderPath(testsSubpath, 'TestEntityAttributeProjUsingObjectModel')));
        const localRoot = corpus.storage.fetchRootFolder('local');
        // Create an entity
        const entity = projectionTestUtils_1.projectionTestUtils.createEntity(corpus, localRoot);
        // Create a projection
        const projection = projectionTestUtils_1.projectionTestUtils.createProjection(corpus, localRoot);
        // Create an ArrayExpansion operation
        const arrayExpansionOp = corpus.MakeObject(internal_1.cdmObjectType.operationArrayExpansionDef);
        arrayExpansionOp.startOrdinal = 1;
        arrayExpansionOp.endOrdinal = 2;
        projection.operations.push(arrayExpansionOp);
        // Create an entity reference to hold this projection
        const projectionEntityRef = corpus.MakeObject(internal_1.cdmObjectType.entityRef, undefined);
        projectionEntityRef.explicitReference = projection;
        // Create another projection that does a rename so that we can see the expanded attributes in the final resolved entity
        const projection2 = corpus.MakeObject(internal_1.cdmObjectType.projectionDef);
        projection2.source = projectionEntityRef;
        // Create a RenameAttributes operation
        const renameAttrsOp = corpus.MakeObject(internal_1.cdmObjectType.operationRenameAttributesDef);
        renameAttrsOp.renameFormat = '{m}{o}';
        projection2.operations.push(renameAttrsOp);
        // Create an entity reference to hold this projection
        const projectionEntityRef2 = corpus.MakeObject(internal_1.cdmObjectType.entityRef, undefined);
        projectionEntityRef2.explicitReference = projection2;
        // Create an entity attribute that contains this projection and add this to the entity
        const entityAttribute = corpus.MakeObject(internal_1.cdmObjectType.entityAttributeDef, 'TestEntityAttribute');
        entityAttribute.entity = projectionEntityRef2;
        entity.attributes.push(entityAttribute);
        // Resolve the entity
        const resolvedEntity = yield entity.createResolvedEntityAsync(`Resolved_${entity.entityName}.cdm.json`, undefined, localRoot);
        // Verify correctness of the resolved attributes after running the projections
        // Original set of attributes: ["id", "name", "value", "date"]
        // Expand 1...2, renameFormat = {m}{o}
        expect(resolvedEntity.attributes.length)
            .toEqual(8);
        expect(resolvedEntity.attributes.allItems[0].name)
            .toEqual('id1');
        expect(resolvedEntity.attributes.allItems[1].name)
            .toEqual('name1');
        expect(resolvedEntity.attributes.allItems[2].name)
            .toEqual('value1');
        expect(resolvedEntity.attributes.allItems[3].name)
            .toEqual('date1');
        expect(resolvedEntity.attributes.allItems[4].name)
            .toEqual('id2');
        expect(resolvedEntity.attributes.allItems[5].name)
            .toEqual('name2');
        expect(resolvedEntity.attributes.allItems[6].name)
            .toEqual('value2');
        expect(resolvedEntity.attributes.allItems[7].name)
            .toEqual('date2');
    }));
    /**
     * Test for creating a projection with an ArrayExpansion operation on an entity definition using the object model
     */
    it('TestEntityProjUsingObjectModel', () => __awaiter(void 0, void 0, void 0, function* () {
        const corpus = testHelper_1.testHelper.getLocalCorpus(testsSubpath, 'TestEntityProjUsingObjectModel');
        corpus.storage.mount('local', new Storage_1.LocalAdapter(testHelper_1.testHelper.getActualOutputFolderPath(testsSubpath, 'TestEntityProjUsingObjectModel')));
        const localRoot = corpus.storage.fetchRootFolder('local');
        // Create an entity
        const entity = projectionTestUtils_1.projectionTestUtils.createEntity(corpus, localRoot);
        // Create a projection
        const projection = projectionTestUtils_1.projectionTestUtils.createProjection(corpus, localRoot);
        // Create an ArrayExpansion operation
        const arrayExpansionOp = corpus.MakeObject(internal_1.cdmObjectType.operationArrayExpansionDef);
        arrayExpansionOp.startOrdinal = 1;
        arrayExpansionOp.endOrdinal = 2;
        projection.operations.push(arrayExpansionOp);
        // Create an entity reference to hold this projection
        const projectionEntityRef = corpus.MakeObject(internal_1.cdmObjectType.entityRef, undefined);
        projectionEntityRef.explicitReference = projection;
        // Create another projection that does a rename so that we can see the expanded attributes in the final resolved entity
        const projection2 = corpus.MakeObject(internal_1.cdmObjectType.projectionDef);
        projection2.source = projectionEntityRef;
        // Create a RenameAttributes operation
        const renameAttrsOp = corpus.MakeObject(internal_1.cdmObjectType.operationRenameAttributesDef);
        renameAttrsOp.renameFormat = '{m}{o}';
        projection2.operations.push(renameAttrsOp);
        // Create an entity reference to hold this projection
        const projectionEntityRef2 = corpus.MakeObject(internal_1.cdmObjectType.entityRef, undefined);
        projectionEntityRef2.explicitReference = projection2;
        // Set the entity's ExtendEntity to be the projection
        entity.extendsEntity = projectionEntityRef2;
        // Resolve the entity
        const resolvedEntity = yield entity.createResolvedEntityAsync(`Resolved_${entity.entityName}.cdm.json`, undefined, localRoot);
        // Verify correctness of the resolved attributes after running the projections
        // Original set of attributes: ["id", "name", "value", "date"]
        // Expand 1...2, renameFormat = {m}{o}
        expect(resolvedEntity.attributes.length)
            .toEqual(8);
        expect(resolvedEntity.attributes.allItems[0].name)
            .toEqual('id1');
        expect(resolvedEntity.attributes.allItems[1].name)
            .toEqual('name1');
        expect(resolvedEntity.attributes.allItems[2].name)
            .toEqual('value1');
        expect(resolvedEntity.attributes.allItems[3].name)
            .toEqual('date1');
        expect(resolvedEntity.attributes.allItems[4].name)
            .toEqual('id2');
        expect(resolvedEntity.attributes.allItems[5].name)
            .toEqual('name2');
        expect(resolvedEntity.attributes.allItems[6].name)
            .toEqual('value2');
        expect(resolvedEntity.attributes.allItems[7].name)
            .toEqual('date2');
    }));
    /**
     * Test for creating a projection with an ArrayExpansion operation and a condition using the object model
     */
    it('TestConditionalProjUsingObjectModel', () => __awaiter(void 0, void 0, void 0, function* () {
        const corpus = testHelper_1.testHelper.getLocalCorpus(testsSubpath, 'TestConditionalProjUsingObjectModel');
        corpus.storage.mount('local', new Storage_1.LocalAdapter(testHelper_1.testHelper.getActualOutputFolderPath(testsSubpath, 'TestConditionalProjUsingObjectModel')));
        const localRoot = corpus.storage.fetchRootFolder('local');
        // Create an entity
        const entity = projectionTestUtils_1.projectionTestUtils.createEntity(corpus, localRoot);
        // Create a projection with a condition that states the operation should only execute when the resolution directive is 'referenceOnly'
        const projection = projectionTestUtils_1.projectionTestUtils.createProjection(corpus, localRoot);
        projection.condition = 'referenceOnly==true';
        // Create an ArrayExpansion operation
        const arrayExpansionOp = corpus.MakeObject(internal_1.cdmObjectType.operationArrayExpansionDef);
        arrayExpansionOp.startOrdinal = 1;
        arrayExpansionOp.endOrdinal = 2;
        projection.operations.push(arrayExpansionOp);
        // Create an entity reference to hold this projection
        const projectionEntityRef = corpus.MakeObject(internal_1.cdmObjectType.entityRef, undefined);
        projectionEntityRef.explicitReference = projection;
        // Create another projection that does a rename so that we can see the expanded attributes in the final resolved entity
        const projection2 = corpus.MakeObject(internal_1.cdmObjectType.projectionDef);
        projection2.source = projectionEntityRef;
        // Create a RenameAttributes operation
        const renameAttrsOp = corpus.MakeObject(internal_1.cdmObjectType.operationRenameAttributesDef);
        renameAttrsOp.renameFormat = '{m}{o}';
        projection2.operations.push(renameAttrsOp);
        // Create an entity reference to hold this projection
        const projectionEntityRef2 = corpus.MakeObject(internal_1.cdmObjectType.entityRef, undefined);
        projectionEntityRef2.explicitReference = projection2;
        // Create an entity attribute that contains this projection and add this to the entity
        const entityAttribute = corpus.MakeObject(internal_1.cdmObjectType.entityAttributeDef, 'TestEntityAttribute');
        entityAttribute.entity = projectionEntityRef2;
        entity.attributes.push(entityAttribute);
        // Create resolution options with the 'referenceOnly' directive
        const resOpt = new internal_1.resolveOptions(entity.inDocument);
        resOpt.directives = new internal_1.AttributeResolutionDirectiveSet(new Set(['referenceOnly']));
        // Resolve the entity with 'referenceOnly'
        const resolvedEntityWithReferenceOnly = yield entity.createResolvedEntityAsync(`Resolved_${entity.entityName}.cdm.json`, resOpt, localRoot);
        // Verify correctness of the resolved attributes after running the projections
        // Original set of attributes: ["id", "name", "value", "date"]
        // Expand 1...2, renameFormat = {m}{o}
        expect(resolvedEntityWithReferenceOnly.attributes.length)
            .toEqual(8);
        expect(resolvedEntityWithReferenceOnly.attributes.allItems[0].name)
            .toEqual('id1');
        expect(resolvedEntityWithReferenceOnly.attributes.allItems[1].name)
            .toEqual('name1');
        expect(resolvedEntityWithReferenceOnly.attributes.allItems[2].name)
            .toEqual('value1');
        expect(resolvedEntityWithReferenceOnly.attributes.allItems[3].name)
            .toEqual('date1');
        expect(resolvedEntityWithReferenceOnly.attributes.allItems[4].name)
            .toEqual('id2');
        expect(resolvedEntityWithReferenceOnly.attributes.allItems[5].name)
            .toEqual('name2');
        expect(resolvedEntityWithReferenceOnly.attributes.allItems[6].name)
            .toEqual('value2');
        expect(resolvedEntityWithReferenceOnly.attributes.allItems[7].name)
            .toEqual('date2');
        // Now resolve the entity with the default directives
        resOpt.directives = new internal_1.AttributeResolutionDirectiveSet(new Set([]));
        const resolvedEntityWithStructured = yield entity.createResolvedEntityAsync(`Resolved_${entity.entityName}.cdm.json`, resOpt, localRoot);
        // Verify correctness of the resolved attributes after running the projections
        // Original set of attributes: ["id", "name", "value", "date"]
        // Expand 1...2, renameFormat = {m}{o}
        expect(resolvedEntityWithStructured.attributes.length)
            .toEqual(4);
        expect(resolvedEntityWithStructured.attributes.allItems[0].name)
            .toEqual('id');
        expect(resolvedEntityWithStructured.attributes.allItems[1].name)
            .toEqual('name');
        expect(resolvedEntityWithStructured.attributes.allItems[2].name)
            .toEqual('value');
        expect(resolvedEntityWithStructured.attributes.allItems[3].name)
            .toEqual('date');
    }));
    /**
     * Expansion on an entity attribute
     */
    it('TestExpansion', () => __awaiter(void 0, void 0, void 0, function* () {
        const testName = 'TestExpansion';
        const entityName = 'ThreeMusketeers';
        const corpus = testHelper_1.testHelper.getLocalCorpus(testsSubpath, testName);
        for (const resOpt of resOptsCombinations) {
            yield projectionTestUtils_1.projectionTestUtils.loadEntityForResolutionOptionAndSave(corpus, testName, testsSubpath, entityName, resOpt);
        }
        const entity = yield corpus.fetchObjectAsync(`local:/${entityName}.cdm.json/${entityName}`);
        const resolvedEntity = yield projectionTestUtils_1.projectionTestUtils.getResolvedEntity(corpus, entity, []);
        // Original set of attributes: ["name", "age", "address"]
        // Expand 1...3, renameFormat = {m}{o}
        expect(resolvedEntity.attributes.length)
            .toEqual(10);
        expect(resolvedEntity.attributes.allItems[0].name)
            .toEqual('count');
        expect(resolvedEntity.attributes.allItems[1].name)
            .toEqual('name1');
        expect(resolvedEntity.attributes.allItems[2].name)
            .toEqual('age1');
        expect(resolvedEntity.attributes.allItems[3].name)
            .toEqual('address1');
        expect(resolvedEntity.attributes.allItems[4].name)
            .toEqual('name2');
        expect(resolvedEntity.attributes.allItems[5].name)
            .toEqual('age2');
        expect(resolvedEntity.attributes.allItems[6].name)
            .toEqual('address2');
        expect(resolvedEntity.attributes.allItems[7].name)
            .toEqual('name3');
        expect(resolvedEntity.attributes.allItems[8].name)
            .toEqual('age3');
        expect(resolvedEntity.attributes.allItems[9].name)
            .toEqual('address3');
    }));
    /**
     * ArrayExpansion on an entity attribute
     */
    it('TestEntityAttribute', () => __awaiter(void 0, void 0, void 0, function* () {
        const testName = 'TestEntityAttribute';
        const entityName = 'ThreeMusketeers';
        const corpus = testHelper_1.testHelper.getLocalCorpus(testsSubpath, testName);
        for (const resOpt of resOptsCombinations) {
            yield projectionTestUtils_1.projectionTestUtils.loadEntityForResolutionOptionAndSave(corpus, testName, testsSubpath, entityName, resOpt);
        }
        const entity = yield corpus.fetchObjectAsync(`local:/${entityName}.cdm.json/${entityName}`);
        const resolvedEntity = yield projectionTestUtils_1.projectionTestUtils.getResolvedEntity(corpus, entity, []);
        // Original set of attributes: ["name", "age", "address"]
        // Expand 1...3, renameFormat = {m}{o}
        expect(resolvedEntity.attributes.length)
            .toEqual(9);
        expect(resolvedEntity.attributes.allItems[0].name)
            .toEqual('name1');
        expect(resolvedEntity.attributes.allItems[1].name)
            .toEqual('age1');
        expect(resolvedEntity.attributes.allItems[2].name)
            .toEqual('address1');
        expect(resolvedEntity.attributes.allItems[3].name)
            .toEqual('name2');
        expect(resolvedEntity.attributes.allItems[4].name)
            .toEqual('age2');
        expect(resolvedEntity.attributes.allItems[5].name)
            .toEqual('address2');
        expect(resolvedEntity.attributes.allItems[6].name)
            .toEqual('name3');
        expect(resolvedEntity.attributes.allItems[7].name)
            .toEqual('age3');
        expect(resolvedEntity.attributes.allItems[8].name)
            .toEqual('address3');
    }));
    /**
     * ArrayExpansion on an entity attribute without a RenameAttributes
     */
    it('TestProjNoRename', () => __awaiter(void 0, void 0, void 0, function* () {
        const testName = 'TestProjNoRename';
        const entityName = 'ThreeMusketeers';
        const corpus = testHelper_1.testHelper.getLocalCorpus(testsSubpath, testName);
        for (const resOpt of resOptsCombinations) {
            yield projectionTestUtils_1.projectionTestUtils.loadEntityForResolutionOptionAndSave(corpus, testName, testsSubpath, entityName, resOpt);
        }
        const entity = yield corpus.fetchObjectAsync(`local:/${entityName}.cdm.json/${entityName}`);
        const resolvedEntity = yield projectionTestUtils_1.projectionTestUtils.getResolvedEntity(corpus, entity, []);
        // Original set of attributes: ["name", "age", "address"]
        // Expand 1...3
        // Since there's no rename, the expanded attributes just get merged together
        expect(resolvedEntity.attributes.length)
            .toEqual(3);
        expect(resolvedEntity.attributes.allItems[0].name)
            .toEqual('name');
        expect(resolvedEntity.attributes.allItems[1].name)
            .toEqual('age');
        expect(resolvedEntity.attributes.allItems[2].name)
            .toEqual('address');
    }));
    /**
     * Expansion on an entity definition
     * NOTE: This is not supported in resolution guidance
     */
    it('TestExtendsEntity', () => __awaiter(void 0, void 0, void 0, function* () {
        const testName = 'TestExtendsEntity';
        const entityName = 'ThreeMusketeers';
        const corpus = testHelper_1.testHelper.getLocalCorpus(testsSubpath, testName);
        for (const resOpt of resOptsCombinations) {
            yield projectionTestUtils_1.projectionTestUtils.loadEntityForResolutionOptionAndSave(corpus, testName, testsSubpath, entityName, resOpt);
        }
        const entity = yield corpus.fetchObjectAsync(`local:/${entityName}.cdm.json/${entityName}`);
        const resolvedEntity = yield projectionTestUtils_1.projectionTestUtils.getResolvedEntity(corpus, entity, []);
        // Original set of attributes: ["name", "age", "address"]
        // Expand 1...3, renameFormat = {m}{o}
        // ExtendsEntityResolutionGuidance doesn't support doing expansions, so we only get "count" here
        expect(resolvedEntity.attributes.length)
            .toEqual(1);
        expect(resolvedEntity.attributes.allItems[0].name)
            .toEqual('count');
    }));
    /**
     * ArrayExpansion on an entity definition
     */
    it('TestExtendsEntityProj', () => __awaiter(void 0, void 0, void 0, function* () {
        const testName = 'TestExtendsEntityProj';
        const entityName = 'ThreeMusketeers';
        const corpus = testHelper_1.testHelper.getLocalCorpus(testsSubpath, testName);
        for (const resOpt of resOptsCombinations) {
            yield projectionTestUtils_1.projectionTestUtils.loadEntityForResolutionOptionAndSave(corpus, testName, testsSubpath, entityName, resOpt);
        }
        const entity = yield corpus.fetchObjectAsync(`local:/${entityName}.cdm.json/${entityName}`);
        const resolvedEntity = yield projectionTestUtils_1.projectionTestUtils.getResolvedEntity(corpus, entity, []);
        // Original set of attributes: ["name", "age", "address"]
        // Expand 1...3, renameFormat = {m}{o}
        expect(resolvedEntity.attributes.length)
            .toEqual(9);
        expect(resolvedEntity.attributes.allItems[0].name)
            .toEqual('name1');
        expect(resolvedEntity.attributes.allItems[1].name)
            .toEqual('age1');
        expect(resolvedEntity.attributes.allItems[2].name)
            .toEqual('address1');
        expect(resolvedEntity.attributes.allItems[3].name)
            .toEqual('name2');
        expect(resolvedEntity.attributes.allItems[4].name)
            .toEqual('age2');
        expect(resolvedEntity.attributes.allItems[5].name)
            .toEqual('address2');
        expect(resolvedEntity.attributes.allItems[6].name)
            .toEqual('name3');
        expect(resolvedEntity.attributes.allItems[7].name)
            .toEqual('age3');
        expect(resolvedEntity.attributes.allItems[8].name)
            .toEqual('address3');
    }));
    /**
     * Nested projections with ArrayExpansion
     */
    it('TestNestedProj', () => __awaiter(void 0, void 0, void 0, function* () {
        const testName = 'TestNestedProj';
        const entityName = 'ThreeMusketeers';
        const corpus = testHelper_1.testHelper.getLocalCorpus(testsSubpath, testName);
        for (const resOpt of resOptsCombinations) {
            yield projectionTestUtils_1.projectionTestUtils.loadEntityForResolutionOptionAndSave(corpus, testName, testsSubpath, entityName, resOpt);
        }
        const entity = yield corpus.fetchObjectAsync(`local:/${entityName}.cdm.json/${entityName}`);
        const resolvedEntity = yield projectionTestUtils_1.projectionTestUtils.getResolvedEntity(corpus, entity, []);
        // Original set of attributes: ["name", "age", "address"]
        // Expand 1...3 and then 1...2, renameFormat = {m}_{o}
        expect(resolvedEntity.attributes.length)
            .toEqual(18);
        expect(resolvedEntity.attributes.allItems[0].name)
            .toEqual('name_1_1');
        expect(resolvedEntity.attributes.allItems[1].name)
            .toEqual('age_1_1');
        expect(resolvedEntity.attributes.allItems[2].name)
            .toEqual('address_1_1');
        expect(resolvedEntity.attributes.allItems[3].name)
            .toEqual('name_2_1');
        expect(resolvedEntity.attributes.allItems[4].name)
            .toEqual('age_2_1');
        expect(resolvedEntity.attributes.allItems[5].name)
            .toEqual('address_2_1');
        expect(resolvedEntity.attributes.allItems[6].name)
            .toEqual('name_3_1');
        expect(resolvedEntity.attributes.allItems[7].name)
            .toEqual('age_3_1');
        expect(resolvedEntity.attributes.allItems[8].name)
            .toEqual('address_3_1');
        expect(resolvedEntity.attributes.allItems[9].name)
            .toEqual('name_1_2');
        expect(resolvedEntity.attributes.allItems[10].name)
            .toEqual('age_1_2');
        expect(resolvedEntity.attributes.allItems[11].name)
            .toEqual('address_1_2');
        expect(resolvedEntity.attributes.allItems[12].name)
            .toEqual('name_2_2');
        expect(resolvedEntity.attributes.allItems[13].name)
            .toEqual('age_2_2');
        expect(resolvedEntity.attributes.allItems[14].name)
            .toEqual('address_2_2');
        expect(resolvedEntity.attributes.allItems[15].name)
            .toEqual('name_3_2');
        expect(resolvedEntity.attributes.allItems[16].name)
            .toEqual('age_3_2');
        expect(resolvedEntity.attributes.allItems[17].name)
            .toEqual('address_3_2');
    }));
    /**
     * Start and end ordinals of -2...2
     */
    it('TestNegativeStartOrdinal', () => __awaiter(void 0, void 0, void 0, function* () {
        const testName = 'TestNegativeStartOrdinal';
        const entityName = 'ThreeMusketeers';
        const corpus = testHelper_1.testHelper.getLocalCorpus(testsSubpath, testName);
        for (const resOpt of resOptsCombinations) {
            yield projectionTestUtils_1.projectionTestUtils.loadEntityForResolutionOptionAndSave(corpus, testName, testsSubpath, entityName, resOpt);
        }
        const entity = yield corpus.fetchObjectAsync(`local:/${entityName}.cdm.json/${entityName}`);
        const resolvedEntity = yield projectionTestUtils_1.projectionTestUtils.getResolvedEntity(corpus, entity, []);
        // Original set of attributes: ["name", "age", "address"]
        // Expand -2...2, renameFormat = {m}{o}
        // Since we don't allow negative ordinals, output should be 0...2
        expect(resolvedEntity.attributes.length)
            .toEqual(9);
        expect(resolvedEntity.attributes.allItems[0].name)
            .toEqual('name0');
        expect(resolvedEntity.attributes.allItems[1].name)
            .toEqual('age0');
        expect(resolvedEntity.attributes.allItems[2].name)
            .toEqual('address0');
        expect(resolvedEntity.attributes.allItems[3].name)
            .toEqual('name1');
        expect(resolvedEntity.attributes.allItems[4].name)
            .toEqual('age1');
        expect(resolvedEntity.attributes.allItems[5].name)
            .toEqual('address1');
        expect(resolvedEntity.attributes.allItems[6].name)
            .toEqual('name2');
        expect(resolvedEntity.attributes.allItems[7].name)
            .toEqual('age2');
        expect(resolvedEntity.attributes.allItems[8].name)
            .toEqual('address2');
    }));
    /**
     * Start ordinal greater than end ordinal
     */
    it('TestStartGTEndOrdinal', () => __awaiter(void 0, void 0, void 0, function* () {
        const testName = 'TestStartGTEndOrdinal';
        const entityName = 'ThreeMusketeers';
        const corpus = testHelper_1.testHelper.getLocalCorpus(testsSubpath, testName);
        // A warning should be logged when startOrdinal > endOrdinal
        corpus.setEventCallback((statusLevel, message) => {
            if (message.indexOf('startOrdinal 2 should not be greater than endOrdinal 0') === -1) {
                fail(`Some unexpected failure - ${message}!`);
            }
        }, internal_1.cdmStatusLevel.warning);
        for (const resOpt of resOptsCombinations) {
            yield projectionTestUtils_1.projectionTestUtils.loadEntityForResolutionOptionAndSave(corpus, testName, testsSubpath, entityName, resOpt);
        }
        const entity = yield corpus.fetchObjectAsync(`local:/${entityName}.cdm.json/${entityName}`);
        const resolvedEntity = yield projectionTestUtils_1.projectionTestUtils.getResolvedEntity(corpus, entity, []);
        // Original set of attributes: ["name", "age", "address"]
        // Expand 2...0, renameFormat = {m}{o}
        // No array expansion happens here so the input just passes through
        expect(resolvedEntity.attributes.length)
            .toEqual(3);
        expect(resolvedEntity.attributes.allItems[0].name)
            .toEqual('name');
        expect(resolvedEntity.attributes.allItems[1].name)
            .toEqual('age');
        expect(resolvedEntity.attributes.allItems[2].name)
            .toEqual('address');
    }));
    /**
     * Same start and end ordinals
     */
    it('TestSameStartEndOrdinals', () => __awaiter(void 0, void 0, void 0, function* () {
        const testName = 'TestSameStartEndOrdinals';
        const entityName = 'ThreeMusketeers';
        const corpus = testHelper_1.testHelper.getLocalCorpus(testsSubpath, testName);
        for (const resOpt of resOptsCombinations) {
            yield projectionTestUtils_1.projectionTestUtils.loadEntityForResolutionOptionAndSave(corpus, testName, testsSubpath, entityName, resOpt);
        }
        const entity = yield corpus.fetchObjectAsync(`local:/${entityName}.cdm.json/${entityName}`);
        const resolvedEntity = yield projectionTestUtils_1.projectionTestUtils.getResolvedEntity(corpus, entity, []);
        // Original set of attributes: ["name", "age", "address"]
        // Expand 1...1, renameFormat = {m}{o}
        expect(resolvedEntity.attributes.length)
            .toEqual(3);
        expect(resolvedEntity.attributes.allItems[0].name)
            .toEqual('name1');
        expect(resolvedEntity.attributes.allItems[1].name)
            .toEqual('age1');
        expect(resolvedEntity.attributes.allItems[2].name)
            .toEqual('address1');
    }));
    /**
     * Combine ArrayExpansion, RenameAttributes, and IncludeAttributes in a single projection
     */
    it('TestCombineOps', () => __awaiter(void 0, void 0, void 0, function* () {
        const testName = 'TestCombineOps';
        const entityName = 'ThreeMusketeers';
        const corpus = testHelper_1.testHelper.getLocalCorpus(testsSubpath, testName);
        for (const resOpt of resOptsCombinations) {
            yield projectionTestUtils_1.projectionTestUtils.loadEntityForResolutionOptionAndSave(corpus, testName, testsSubpath, entityName, resOpt);
        }
        const entity = yield corpus.fetchObjectAsync(`local:/${entityName}.cdm.json/${entityName}`);
        const resolvedEntity = yield projectionTestUtils_1.projectionTestUtils.getResolvedEntity(corpus, entity, []);
        // Original set of attributes: ["name", "age", "address"]
        // Expand 1...3, renameFormat = {m}{o}, include [name, age1]
        expect(resolvedEntity.attributes.length)
            .toEqual(4);
        expect(resolvedEntity.attributes.allItems[0].name)
            .toEqual('name1');
        expect(resolvedEntity.attributes.allItems[1].name)
            .toEqual('name2');
        expect(resolvedEntity.attributes.allItems[2].name)
            .toEqual('name3');
        expect(resolvedEntity.attributes.allItems[3].name)
            .toEqual('age1');
    }));
    /**
     * Expansion on a polymorphic source
     */
    it('TestPolymorphic', () => __awaiter(void 0, void 0, void 0, function* () {
        const testName = 'TestPolymorphic';
        const entityName = 'BusinessPerson';
        const corpus = testHelper_1.testHelper.getLocalCorpus(testsSubpath, testName);
        for (const resOpt of resOptsCombinations) {
            yield projectionTestUtils_1.projectionTestUtils.loadEntityForResolutionOptionAndSave(corpus, testName, testsSubpath, entityName, resOpt);
        }
        const entity = yield corpus.fetchObjectAsync(`local:/${entityName}.cdm.json/${entityName}`);
        const resolvedEntity = yield projectionTestUtils_1.projectionTestUtils.getResolvedEntity(corpus, entity, []);
        // Original set of attributes: ["emailId", "address", "isPrimary", "phoneId", "number"]
        // Expand 1...2, renameFormat = {m}{o}
        expect(resolvedEntity.attributes.length)
            .toEqual(11);
        expect(resolvedEntity.attributes.allItems[0].name)
            .toEqual('count');
        expect(resolvedEntity.attributes.allItems[1].name)
            .toEqual('emailId1');
        expect(resolvedEntity.attributes.allItems[2].name)
            .toEqual('address1');
        expect(resolvedEntity.attributes.allItems[3].name)
            .toEqual('isPrimary1');
        expect(resolvedEntity.attributes.allItems[4].name)
            .toEqual('phoneId1');
        expect(resolvedEntity.attributes.allItems[5].name)
            .toEqual('number1');
        expect(resolvedEntity.attributes.allItems[6].name)
            .toEqual('emailId2');
        expect(resolvedEntity.attributes.allItems[7].name)
            .toEqual('address2');
        expect(resolvedEntity.attributes.allItems[8].name)
            .toEqual('isPrimary2');
        expect(resolvedEntity.attributes.allItems[9].name)
            .toEqual('phoneId2');
        expect(resolvedEntity.attributes.allItems[10].name)
            .toEqual('number2');
    }));
    /**
     * ArrayExpansion on a polymorphic source
     */
    it('TestPolymorphicProj', () => __awaiter(void 0, void 0, void 0, function* () {
        const testName = 'TestPolymorphicProj';
        const entityName = 'BusinessPerson';
        const corpus = testHelper_1.testHelper.getLocalCorpus(testsSubpath, testName);
        for (const resOpt of resOptsCombinations) {
            if (resOpt.includes('structured')) {
                // Array expansion is not supported on an attribute group yet.
                continue;
            }
            yield projectionTestUtils_1.projectionTestUtils.loadEntityForResolutionOptionAndSave(corpus, testName, testsSubpath, entityName, resOpt);
        }
        const entity = yield corpus.fetchObjectAsync(`local:/${entityName}.cdm.json/${entityName}`);
        const resolvedEntity = yield projectionTestUtils_1.projectionTestUtils.getResolvedEntity(corpus, entity, []);
        // Original set of attributes: ["emailId", "address", "isPrimary", "phoneId", "number"]
        // Expand 1...2, renameFormat = {m}{o}
        expect(resolvedEntity.attributes.length)
            .toEqual(10);
        expect(resolvedEntity.attributes.allItems[0].name)
            .toEqual('emailId1');
        expect(resolvedEntity.attributes.allItems[1].name)
            .toEqual('address1');
        expect(resolvedEntity.attributes.allItems[2].name)
            .toEqual('isPrimary1');
        expect(resolvedEntity.attributes.allItems[3].name)
            .toEqual('phoneId1');
        expect(resolvedEntity.attributes.allItems[4].name)
            .toEqual('number1');
        expect(resolvedEntity.attributes.allItems[5].name)
            .toEqual('emailId2');
        expect(resolvedEntity.attributes.allItems[6].name)
            .toEqual('address2');
        expect(resolvedEntity.attributes.allItems[7].name)
            .toEqual('isPrimary2');
        expect(resolvedEntity.attributes.allItems[8].name)
            .toEqual('phoneId2');
        expect(resolvedEntity.attributes.allItems[9].name)
            .toEqual('number2');
    }));
    /**
     * Expansion on an array source
     * NOTE: This is not supported in resolution guidance due to ordinals from a previous resolution guidance
     * not being removed for the next resolution guidance, resulting in ordinals being skipped over in the new
     * resolution guidance as it thinks it has already done that round
     */
    it('TestArraySource', () => __awaiter(void 0, void 0, void 0, function* () {
        const testName = 'TestArraySource';
        const entityName = 'FriendGroup';
        const corpus = testHelper_1.testHelper.getLocalCorpus(testsSubpath, testName);
        for (const resOpt of resOptsCombinations) {
            yield projectionTestUtils_1.projectionTestUtils.loadEntityForResolutionOptionAndSave(corpus, testName, testsSubpath, entityName, resOpt);
        }
        const entity = yield corpus.fetchObjectAsync(`local:/${entityName}.cdm.json/${entityName}`);
        const resolvedEntity = yield projectionTestUtils_1.projectionTestUtils.getResolvedEntity(corpus, entity, []);
        // Original set of attributes: ["personCount", "name1", "age1", "address1", "name2", "age2", "address2"]
        // Expand 1...2, renameFormat = {m}_{o}
        // Since resolution guidance doesn't support doing an expansion on an array source, we end up with the
        // following result where it skips expanding attributes with the same ordinal (ex. name1_1, name2_2)
        expect(resolvedEntity.attributes.length)
            .toEqual(9);
        expect(resolvedEntity.attributes.allItems[0].name)
            .toEqual('count_');
        expect(resolvedEntity.attributes.allItems[1].name)
            .toEqual('personCount_1');
        expect(resolvedEntity.attributes.allItems[2].name)
            .toEqual('name2_1');
        expect(resolvedEntity.attributes.allItems[3].name)
            .toEqual('age2_1');
        expect(resolvedEntity.attributes.allItems[4].name)
            .toEqual('address2_1');
        expect(resolvedEntity.attributes.allItems[5].name)
            .toEqual('personCount_2');
        expect(resolvedEntity.attributes.allItems[6].name)
            .toEqual('name1_2');
        expect(resolvedEntity.attributes.allItems[7].name)
            .toEqual('age1_2');
        expect(resolvedEntity.attributes.allItems[8].name)
            .toEqual('address1_2');
    }));
    /**
     * ArrayExpansion on an array source
     */
    it('TestArraySourceProj', () => __awaiter(void 0, void 0, void 0, function* () {
        const testName = 'TestArraySourceProj';
        const entityName = 'FriendGroup';
        const corpus = testHelper_1.testHelper.getLocalCorpus(testsSubpath, testName);
        for (const resOpt of resOptsCombinations) {
            yield projectionTestUtils_1.projectionTestUtils.loadEntityForResolutionOptionAndSave(corpus, testName, testsSubpath, entityName, resOpt);
        }
        const entity = yield corpus.fetchObjectAsync(`local:/${entityName}.cdm.json/${entityName}`);
        const resolvedEntity = yield projectionTestUtils_1.projectionTestUtils.getResolvedEntity(corpus, entity, []);
        // Original set of attributes: ["personCount", "name1", "age1", "address1", "name2", "age2", "address2"]
        // Expand 1...2, renameFormat = {m}_{o}
        expect(resolvedEntity.attributes.length)
            .toEqual(14);
        expect(resolvedEntity.attributes.allItems[0].name)
            .toEqual('personCount_1');
        expect(resolvedEntity.attributes.allItems[1].name)
            .toEqual('name1_1');
        expect(resolvedEntity.attributes.allItems[2].name)
            .toEqual('age1_1');
        expect(resolvedEntity.attributes.allItems[3].name)
            .toEqual('address1_1');
        expect(resolvedEntity.attributes.allItems[4].name)
            .toEqual('name2_1');
        expect(resolvedEntity.attributes.allItems[5].name)
            .toEqual('age2_1');
        expect(resolvedEntity.attributes.allItems[6].name)
            .toEqual('address2_1');
        expect(resolvedEntity.attributes.allItems[7].name)
            .toEqual('personCount_2');
        expect(resolvedEntity.attributes.allItems[8].name)
            .toEqual('name1_2');
        expect(resolvedEntity.attributes.allItems[9].name)
            .toEqual('age1_2');
        expect(resolvedEntity.attributes.allItems[10].name)
            .toEqual('address1_2');
        expect(resolvedEntity.attributes.allItems[11].name)
            .toEqual('name2_2');
        expect(resolvedEntity.attributes.allItems[12].name)
            .toEqual('age2_2');
        expect(resolvedEntity.attributes.allItems[13].name)
            .toEqual('address2_2');
    }));
    /**
     * Expansion on an entity with an attribute group
     */
    it('TestGroup', () => __awaiter(void 0, void 0, void 0, function* () {
        const testName = 'TestGroup';
        const entityName = 'ThreeMusketeers';
        const corpus = testHelper_1.testHelper.getLocalCorpus(testsSubpath, testName);
        for (const resOpt of resOptsCombinations) {
            yield projectionTestUtils_1.projectionTestUtils.loadEntityForResolutionOptionAndSave(corpus, testName, testsSubpath, entityName, resOpt);
        }
        const entity = yield corpus.fetchObjectAsync(`local:/${entityName}.cdm.json/${entityName}`);
        const resolvedEntity = yield projectionTestUtils_1.projectionTestUtils.getResolvedEntity(corpus, entity, []);
        // Original set of attributes: ["name", "age", "address"]
        // Expand 1...3, renameFormat = {m}{o}
        expect(resolvedEntity.attributes.length)
            .toEqual(10);
        expect(resolvedEntity.attributes.allItems[0].name)
            .toEqual('count');
        expect(resolvedEntity.attributes.allItems[1].name)
            .toEqual('name1');
        expect(resolvedEntity.attributes.allItems[2].name)
            .toEqual('age1');
        expect(resolvedEntity.attributes.allItems[3].name)
            .toEqual('address1');
        expect(resolvedEntity.attributes.allItems[4].name)
            .toEqual('name2');
        expect(resolvedEntity.attributes.allItems[5].name)
            .toEqual('age2');
        expect(resolvedEntity.attributes.allItems[6].name)
            .toEqual('address2');
        expect(resolvedEntity.attributes.allItems[7].name)
            .toEqual('name3');
        expect(resolvedEntity.attributes.allItems[8].name)
            .toEqual('age3');
        expect(resolvedEntity.attributes.allItems[9].name)
            .toEqual('address3');
    }));
    /**
     * ArrayExpansion on an entity with an attribute group
     */
    it('TestGroupProj', () => __awaiter(void 0, void 0, void 0, function* () {
        const testName = 'TestGroupProj';
        const entityName = 'ThreeMusketeers';
        const corpus = testHelper_1.testHelper.getLocalCorpus(testsSubpath, testName);
        for (const resOpt of resOptsCombinations) {
            yield projectionTestUtils_1.projectionTestUtils.loadEntityForResolutionOptionAndSave(corpus, testName, testsSubpath, entityName, resOpt);
        }
        const entity = yield corpus.fetchObjectAsync(`local:/${entityName}.cdm.json/${entityName}`);
        const resolvedEntity = yield projectionTestUtils_1.projectionTestUtils.getResolvedEntity(corpus, entity, []);
        // Original set of attributes: ["name", "age", "address"]
        // Expand 1...3, renameFormat = {m}{o}
        expect(resolvedEntity.attributes.length)
            .toEqual(9);
        expect(resolvedEntity.attributes.allItems[0].name)
            .toEqual('name1');
        expect(resolvedEntity.attributes.allItems[1].name)
            .toEqual('age1');
        expect(resolvedEntity.attributes.allItems[2].name)
            .toEqual('address1');
        expect(resolvedEntity.attributes.allItems[3].name)
            .toEqual('name2');
        expect(resolvedEntity.attributes.allItems[4].name)
            .toEqual('age2');
        expect(resolvedEntity.attributes.allItems[5].name)
            .toEqual('address2');
        expect(resolvedEntity.attributes.allItems[6].name)
            .toEqual('name3');
        expect(resolvedEntity.attributes.allItems[7].name)
            .toEqual('age3');
        expect(resolvedEntity.attributes.allItems[8].name)
            .toEqual('address3');
    }));
    /**
     * ArrayExpansion with a condition
     */
    it('TestConditionalProj', () => __awaiter(void 0, void 0, void 0, function* () {
        const testName = 'TestConditionalProj';
        const entityName = 'ThreeMusketeers';
        const corpus = testHelper_1.testHelper.getLocalCorpus(testsSubpath, testName);
        for (const resOpt of resOptsCombinations) {
            yield projectionTestUtils_1.projectionTestUtils.loadEntityForResolutionOptionAndSave(corpus, testName, testsSubpath, entityName, resOpt);
        }
        const entity = yield corpus.fetchObjectAsync(`local:/${entityName}.cdm.json/${entityName}`);
        const resolvedEntity = yield projectionTestUtils_1.projectionTestUtils.getResolvedEntity(corpus, entity, []);
        // Original set of attributes: ["name", "age", "address"]
        // Expand 1...3, renameFormat = {m}{o}
        // No array expansion, condition was false
        expect(resolvedEntity.attributes.length)
            .toEqual(3);
        expect(resolvedEntity.attributes.allItems[0].name)
            .toEqual('name');
        expect(resolvedEntity.attributes.allItems[1].name)
            .toEqual('age');
        expect(resolvedEntity.attributes.allItems[2].name)
            .toEqual('address');
    }));
});
//# sourceMappingURL=ProjectionExpansion.test.js.map