"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 testHelper_1 = require("../../testHelper");
const projectionTestUtils_1 = require("../../Utilities/projectionTestUtils");
/**
 *  Class to handle AddAttributeGroup operations
 */
describe('Cdm/Projection/ProjectionAddAttributeGroupTest', () => {
    /**
     * The path between TestDataPath and TestName.
     */
    const testsSubpath = 'Cdm/Projection/ProjectionAddAttributeGroupTest';
    /**
     * All possible combinations of the different resolution directives
     */
    const resOptsCombinations = [
        [],
        ['referenceOnly'],
        ['normalized'],
        ['structured'],
        ['referenceOnly', 'normalized'],
        ['referenceOnly', 'structured'],
        ['normalized', 'structured'],
        ['referenceOnly', 'normalized', 'structured']
    ];
    /**
     * Test AddAttributeGroup operation nested with ExcludeAttributes
     */
    it('testCombineOpsNestedProj', () => __awaiter(void 0, void 0, void 0, function* () {
        const testName = 'TestCombineOpsNestedProj';
        const entityName = 'NewPerson';
        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', 'phoneNumber', 'email']
        // Exclude attributes: ['age', 'phoneNumber']
        const attGroupDefinition = projectionTestUtils_1.projectionTestUtils.validateAttributeGroup(resolvedEntity.attributes, 'PersonAttributeGroup');
        expect(attGroupDefinition.members.length)
            .toEqual(3);
        expect(attGroupDefinition.members.allItems[0].name)
            .toEqual('name');
        expect(attGroupDefinition.members.allItems[1].name)
            .toEqual('address');
        expect(attGroupDefinition.members.allItems[2].name)
            .toEqual('email');
    }));
    /**
     * Test AddAttributeGroup and IncludeAttributes operations in the same projection
     */
    it('testCombineOpsProj', () => __awaiter(void 0, void 0, void 0, function* () {
        const testName = 'TestCombineOpsProj';
        const entityName = 'NewPerson';
        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', 'phoneNumber', 'email']
        // Included attributes: ['age', 'phoneNumber']
        const attGroupDefinition = projectionTestUtils_1.projectionTestUtils.validateAttributeGroup(resolvedEntity.attributes, 'PersonAttributeGroup', 3);
        expect(attGroupDefinition.members.length)
            .toEqual(5);
        expect(attGroupDefinition.members.allItems[0].name)
            .toEqual('name');
        expect(attGroupDefinition.members.allItems[1].name)
            .toEqual('age');
        expect(attGroupDefinition.members.allItems[2].name)
            .toEqual('address');
        expect(attGroupDefinition.members.allItems[3].name)
            .toEqual('phoneNumber');
        expect(attGroupDefinition.members.allItems[4].name)
            .toEqual('email');
        // Check the attributes coming from the IncludeAttribute operation
        expect(resolvedEntity.attributes.allItems[1].name)
            .toEqual('age');
        expect(resolvedEntity.attributes.allItems[2].name)
            .toEqual('phoneNumber');
    }));
    /**
     * Test AddAttributeGroup operation with a 'structured' condition
     */
    it('testConditionalProj', () => __awaiter(void 0, void 0, void 0, function* () {
        const testName = 'TestConditionalProj';
        const entityName = 'NewPerson';
        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, ['referenceOnly']);
        // Original set of attributes: ['name', 'age', 'address', 'phoneNumber', 'email']
        // condition not met, keep attributes in flat list
        expect(resolvedEntity.attributes.length)
            .toEqual(5);
        expect(resolvedEntity.attributes.allItems[0].name)
            .toEqual('name');
        expect(resolvedEntity.attributes.allItems[1].name)
            .toEqual('age');
        expect(resolvedEntity.attributes.allItems[2].name)
            .toEqual('address');
        expect(resolvedEntity.attributes.allItems[3].name)
            .toEqual('phoneNumber');
        expect(resolvedEntity.attributes.allItems[4].name)
            .toEqual('email');
        const resolvedEntity2 = yield projectionTestUtils_1.projectionTestUtils.getResolvedEntity(corpus, entity, ['structured']);
        // Original set of attributes: ['name', 'age', 'address', 'phoneNumber', 'email']
        // condition met, put all attributes in an attribute group
        const attGroupDefinition = projectionTestUtils_1.projectionTestUtils.validateAttributeGroup(resolvedEntity2.attributes, 'PersonAttributeGroup');
        expect(attGroupDefinition.members.length)
            .toEqual(5);
        expect(attGroupDefinition.members.allItems[0].name)
            .toEqual('name');
        expect(attGroupDefinition.members.allItems[1].name)
            .toEqual('age');
        expect(attGroupDefinition.members.allItems[2].name)
            .toEqual('address');
        expect(attGroupDefinition.members.allItems[3].name)
            .toEqual('phoneNumber');
        expect(attGroupDefinition.members.allItems[4].name)
            .toEqual('email');
    }));
    /**
     * Test for creating a projection with an AddAttributeGroup operation and a condition using the object model
     */
    it('testConditionalProjUsingObjectModel', () => __awaiter(void 0, void 0, void 0, function* () {
        const testName = 'TestConditionalProjUsingObjectModel';
        const corpus = testHelper_1.testHelper.getLocalCorpus(testsSubpath, testName);
        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 'structured'.
        const projection = projectionTestUtils_1.projectionTestUtils.createProjection(corpus, localRoot);
        projection.condition = 'structured==true';
        // Create an AddAttributeGroup operation
        const addAttGroupOp = corpus.MakeObject(internal_1.cdmObjectType.operationAddAttributeGroupDef);
        addAttGroupOp.attributeGroupName = 'PersonAttributeGroup';
        projection.operations.push(addAttGroupOp);
        // Create an entity reference to hold this projection.
        const projectionEntityRef = corpus.MakeObject(internal_1.cdmObjectType.entityRef, null);
        projectionEntityRef.explicitReference = projection;
        // 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 = projectionEntityRef;
        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 AddAttributeGroup operation
        // Original set of attributes: ['id', 'name', 'value', 'date']
        // condition not met, keep attributes in flat list
        expect(resolvedEntityWithReferenceOnly.attributes.length)
            .toEqual(4);
        expect(resolvedEntityWithReferenceOnly.attributes.allItems[0].name)
            .toEqual('id');
        expect(resolvedEntityWithReferenceOnly.attributes.allItems[1].name)
            .toEqual('name');
        expect(resolvedEntityWithReferenceOnly.attributes.allItems[2].name)
            .toEqual('value');
        expect(resolvedEntityWithReferenceOnly.attributes.allItems[3].name)
            .toEqual('date');
        // Now resolve the entity with the 'structured' directive
        resOpt.directives = new internal_1.AttributeResolutionDirectiveSet(new Set(['structured']));
        const resolvedEntityWithStructured = yield entity.createResolvedEntityAsync(`Resolved_${entity.entityName}.cdm.json`, resOpt, localRoot);
        // Verify correctness of the resolved attributes after running the AddAttributeGroup operation
        // Original set of attributes: ['id', 'name', 'value', 'date']
        // condition met, put all attributes in an attribute group
        const attGroupDefinition = projectionTestUtils_1.projectionTestUtils.validateAttributeGroup(resolvedEntityWithStructured.attributes, 'PersonAttributeGroup');
        expect(attGroupDefinition.members.length)
            .toEqual(4);
        expect(attGroupDefinition.members.allItems[0].name)
            .toEqual('id');
        expect(attGroupDefinition.members.allItems[1].name)
            .toEqual('name');
        expect(attGroupDefinition.members.allItems[2].name)
            .toEqual('value');
        expect(attGroupDefinition.members.allItems[3].name)
            .toEqual('date');
    }));
    /**
     * Test resolving an entity attribute using resolution guidance
     */
    it('testEntityAttribute', () => __awaiter(void 0, void 0, void 0, function* () {
        const testName = 'TestEntityAttribute';
        const entityName = 'NewPerson';
        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, ['structured']);
        // Original set of attributes: ['name', 'age', 'address', 'phoneNumber', 'email']
        const attGroupDefinition = projectionTestUtils_1.projectionTestUtils.validateAttributeGroup(resolvedEntity.attributes, 'PersonInfo');
        expect(attGroupDefinition.members.length)
            .toEqual(5);
        expect(attGroupDefinition.members.allItems[0].name)
            .toEqual('name');
        expect(attGroupDefinition.members.allItems[1].name)
            .toEqual('age');
        expect(attGroupDefinition.members.allItems[2].name)
            .toEqual('address');
        expect(attGroupDefinition.members.allItems[3].name)
            .toEqual('phoneNumber');
        expect(attGroupDefinition.members.allItems[4].name)
            .toEqual('email');
    }));
    /**
     * Test for creating a projection with an AddAttributeGroup operation on an entity attribute using the object model
     */
    it('testEntityAttributeProjUsingObjectModel', () => __awaiter(void 0, void 0, void 0, function* () {
        const testName = 'TestEntityAttributeProjUsingObjectModel';
        const corpus = testHelper_1.testHelper.getLocalCorpus(testsSubpath, testName);
        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 AddAttributeGroup operation
        const addAttGroupOp = corpus.MakeObject(internal_1.cdmObjectType.operationAddAttributeGroupDef);
        addAttGroupOp.attributeGroupName = 'PersonAttributeGroup';
        projection.operations.push(addAttGroupOp);
        // Create an entity reference to hold this projection
        const projectionEntityRef = corpus.MakeObject(internal_1.cdmObjectType.entityRef, null);
        projectionEntityRef.explicitReference = projection;
        // 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 = projectionEntityRef;
        entity.attributes.push(entityAttribute);
        // Resolve the entity.
        const resolvedEntity = yield entity.createResolvedEntityAsync(`Resolved_${entity.entityName}.cdm.json`, null, localRoot);
        // Verify correctness of the resolved attributes after running the AddAttributeGroup operation
        // Original set of attributes: ['id', 'name', 'value', 'date']
        const attGroupDefinition = projectionTestUtils_1.projectionTestUtils.validateAttributeGroup(resolvedEntity.attributes, 'PersonAttributeGroup');
        expect(attGroupDefinition.members.length)
            .toEqual(4);
        expect(attGroupDefinition.members.allItems[0].name)
            .toEqual('id');
        expect(attGroupDefinition.members.allItems[1].name)
            .toEqual('name');
        expect(attGroupDefinition.members.allItems[2].name)
            .toEqual('value');
        expect(attGroupDefinition.members.allItems[3].name)
            .toEqual('date');
    }));
    /**
     * Test for creating a projection with an AddAttributeGroup operation on an entity definition using the object model
     */
    it('testEntityProjUsingObjectModel', () => __awaiter(void 0, void 0, void 0, function* () {
        const testName = 'TestEntityProjUsingObjectModel';
        const corpus = testHelper_1.testHelper.getLocalCorpus(testsSubpath, testName);
        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 AddAttributeGroup operation
        const addAttGroupOp = corpus.MakeObject(internal_1.cdmObjectType.operationAddAttributeGroupDef);
        addAttGroupOp.attributeGroupName = 'PersonAttributeGroup';
        projection.operations.push(addAttGroupOp);
        // Create an entity reference to hold this projection
        const projectionEntityRef = corpus.MakeObject(internal_1.cdmObjectType.entityRef, null);
        projectionEntityRef.explicitReference = projection;
        // Set the entity's ExtendEntity to be the projection
        entity.extendsEntity = projectionEntityRef;
        // Resolve the entity
        const resolvedEntity = yield entity.createResolvedEntityAsync(`Resolved_${entity.entityName}.cdm.json`, null, localRoot);
        // Verify correctness of the resolved attributes after running the AddAttributeGroup operation
        // Original set of attributes: ['id', 'name', 'value', 'date']
        const attGroupDefinition = projectionTestUtils_1.projectionTestUtils.validateAttributeGroup(resolvedEntity.attributes, 'PersonAttributeGroup');
        expect(attGroupDefinition.members.length)
            .toEqual(4);
        expect(attGroupDefinition.members.allItems[0].name)
            .toEqual('id');
        expect(attGroupDefinition.members.allItems[1].name)
            .toEqual('name');
        expect(attGroupDefinition.members.allItems[2].name)
            .toEqual('value');
        expect(attGroupDefinition.members.allItems[3].name)
            .toEqual('date');
    }));
    /**
     * Test AddAttributeGroup operation on an entity definition
     */
    it('testExtendsEntityProj', () => __awaiter(void 0, void 0, void 0, function* () {
        const testName = 'TestExtendsEntityProj';
        const entityName = 'Child';
        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', 'phoneNumber', 'email']
        const attGroupDefinition = projectionTestUtils_1.projectionTestUtils.validateAttributeGroup(resolvedEntity.attributes, 'ChildAttributeGroup');
        expect(attGroupDefinition.members.length)
            .toEqual(5);
        expect(attGroupDefinition.members.allItems[0].name)
            .toEqual('name');
        expect(attGroupDefinition.members.allItems[1].name)
            .toEqual('age');
        expect(attGroupDefinition.members.allItems[2].name)
            .toEqual('address');
        expect(attGroupDefinition.members.allItems[3].name)
            .toEqual('phoneNumber');
        expect(attGroupDefinition.members.allItems[4].name)
            .toEqual('email');
    }));
    /**
     * Multiple AddAttributeGroup operations on the same projection
     */
    it('testMultipleOpProj', () => __awaiter(void 0, void 0, void 0, function* () {
        const testName = 'TestMultipleOpProj';
        const entityName = 'NewPerson';
        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', 'phoneNumber', 'email']
        // This will result in two attribute groups with the same set of attributes being generated
        const attGroup1 = projectionTestUtils_1.projectionTestUtils.validateAttributeGroup(resolvedEntity.attributes, 'PersonAttributeGroup', 2);
        expect(attGroup1.members.length)
            .toEqual(5);
        expect(attGroup1.members.allItems[0].name)
            .toEqual('name');
        expect(attGroup1.members.allItems[1].name)
            .toEqual('age');
        expect(attGroup1.members.allItems[2].name)
            .toEqual('address');
        expect(attGroup1.members.allItems[3].name)
            .toEqual('phoneNumber');
        expect(attGroup1.members.allItems[4].name)
            .toEqual('email');
        const attGroup2 = projectionTestUtils_1.projectionTestUtils.validateAttributeGroup(resolvedEntity.attributes, 'SecondAttributeGroup', 2, 1);
        expect(attGroup2.members.length)
            .toEqual(5);
        expect(attGroup2.members.allItems[0].name)
            .toEqual('name');
        expect(attGroup2.members.allItems[1].name)
            .toEqual('age');
        expect(attGroup2.members.allItems[2].name)
            .toEqual('address');
        expect(attGroup2.members.allItems[3].name)
            .toEqual('phoneNumber');
        expect(attGroup2.members.allItems[4].name)
            .toEqual('email');
    }));
    /**
     * Nested projections with AddAttributeGroup
     */
    it('testNestedProj', () => __awaiter(void 0, void 0, void 0, function* () {
        const testName = 'TestNestedProj';
        const entityName = 'NewPerson';
        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', 'phoneNumber', 'email']
        const outerAttGroup = projectionTestUtils_1.projectionTestUtils.validateAttributeGroup(resolvedEntity.attributes, 'OuterAttributeGroup');
        const innerAttGroup = projectionTestUtils_1.projectionTestUtils.validateAttributeGroup(outerAttGroup.members, 'InnerAttributeGroup');
        expect(innerAttGroup.members.length)
            .toEqual(5);
        expect(innerAttGroup.members.allItems[0].name)
            .toEqual('name');
        expect(innerAttGroup.members.allItems[1].name)
            .toEqual('age');
        expect(innerAttGroup.members.allItems[2].name)
            .toEqual('address');
        expect(innerAttGroup.members.allItems[3].name)
            .toEqual('phoneNumber');
        expect(innerAttGroup.members.allItems[4].name)
            .toEqual('email');
    }));
    /**
     * Test resolving a type attribute with an add attribute group operation
     */
    it.skip('testTypeAttributeProj', () => __awaiter(void 0, void 0, void 0, function* () {
        const testName = 'TestTypeAttributeProj';
        const entityName = 'Person';
        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, ['referenceOnly']);
        // Original set of attributes: ["name", "age", "address", "phoneNumber", "email"]
        // Add attribute group applied to "address"
        expect(resolvedEntity.attributes.length)
            .toEqual(5);
        expect(resolvedEntity.attributes.allItems[0].name)
            .toEqual('name');
        expect(resolvedEntity.attributes.allItems[1].name)
            .toEqual('age');
        const attGroupDefinition = projectionTestUtils_1.projectionTestUtils.validateAttributeGroup(resolvedEntity.attributes, 'AddressAttributeGroup', 5, 2);
        expect(attGroupDefinition.members.allItems[0].name)
            .toEqual('address');
        expect(resolvedEntity.attributes.allItems[3].name)
            .toEqual('phoneNumber');
        expect(resolvedEntity.attributes.allItems[4].name)
            .toEqual('email');
    }));
});
//# sourceMappingURL=ProjectionAddAttributeGroup.test.js.map