"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");
/**
 * Various projections scenarios, partner scenarios, bug fixes
 */
describe('Cdm/Projection/ProjectionMiscellaneousTest', () => {
    const resOptsCombinations = [
        new Set([]),
        new Set(['referenceOnly']),
        new Set(['normalized']),
        new Set(['structured']),
        new Set(['referenceOnly', 'normalized']),
        new Set(['referenceOnly', 'structured']),
        new Set(['normalized', 'structured']),
        new Set(['referenceOnly', 'normalized', 'structured'])
    ];
    /**
     * The path between TestDataPath and TestName.
     */
    const testsSubpath = 'Cdm/Projection/ProjectionMiscellaneousTest';
    /**
     * Test case scenario for Bug #24 from the projections internal bug bash
     * Reference Link: https://commondatamodel.visualstudio.com/CDM/_workitems/edit/24
     */
    it('TestInvalidOperationType', () => __awaiter(void 0, void 0, void 0, function* () {
        const testName = 'TestInvalidOperationType';
        const corpus = testHelper_1.testHelper.getLocalCorpus(testsSubpath, testName);
        corpus.setEventCallback((statusLevel, message) => {
            if (message.indexOf('ProjectionPersistence | Invalid operation type \'replaceAsForeignKey11111\'. | fromData') == -1) {
                fail(message);
            }
        }, internal_1.cdmStatusLevel.warning);
        const manifest = yield corpus.fetchObjectAsync('default.manifest.cdm.json');
        // Raise error: 'ProjectionPersistence | Invalid operation type 'replaceAsForeignKey11111'. | FromData',
        // when attempting to load a projection with an invalid operation
        const entityName = 'SalesNestedFK';
        const entity = yield corpus.fetchObjectAsync(`local:/${entityName}.cdm.json/${entityName}`, manifest);
        expect(entity)
            .toBeTruthy();
    }));
    /**
     * Test case scenario for Bug #23 from the projections internal bug bash
     * Reference Link: https://commondatamodel.visualstudio.com/CDM/_workitems/edit/23
     */
    it('TestZeroMinimumCardinality', () => __awaiter(void 0, void 0, void 0, function* () {
        const testName = 'TestZeroMinimumCardinality';
        const corpus = testHelper_1.testHelper.getLocalCorpus(testsSubpath, testName);
        corpus.setEventCallback((statusLevel, message) => {
            fail(message);
        }, internal_1.cdmStatusLevel.warning);
        // Create Local Root Folder
        const localRoot = corpus.storage.fetchRootFolder('local');
        // Create Manifest
        const manifest = corpus.MakeObject(internal_1.cdmObjectType.manifestDef, 'default');
        localRoot.documents.push(manifest, 'default.manifest.cdm.json');
        const entityName = 'TestEntity';
        // Create Entity
        const entity = corpus.MakeObject(internal_1.cdmObjectType.entityDef, entityName);
        entity.extendsEntity = corpus.MakeRef(internal_1.cdmObjectType.entityRef, 'CdmEntity', true);
        // Create Entity Document
        const document = corpus.MakeObject(internal_1.cdmObjectType.documentDef, `${entityName}.cdm.json`, false);
        document.definitions.push(entity);
        localRoot.documents.push(document, document.getName());
        manifest.entities.push(entity);
        const attributeName = 'testAttribute';
        const attributeDataType = 'string';
        const attributePurpose = 'hasA';
        // Create Type Attribute
        const attribute = corpus.MakeObject(internal_1.cdmObjectType.typeAttributeDef, attributeName, false);
        attribute.dataType = corpus.MakeRef(internal_1.cdmObjectType.dataTypeRef, attributeDataType, true);
        attribute.purpose = corpus.MakeRef(internal_1.cdmObjectType.purposeRef, attributePurpose, true);
        attribute.displayName = attributeName;
        if (entity) {
            entity.attributes.push(attribute);
        }
        attribute.cardinality = new internal_1.CardinalitySettings(attribute);
        attribute.cardinality.minimum = '0';
        attribute.cardinality.maximum = '*';
        expect(attribute.isNullable)
            .toBeTruthy();
    }));
    /**
     * Tests if it resolves correct when there are two entity attributes in circular denpendency using projection
     */
    it('TestCircularEntityAttributes', (done) => __awaiter(void 0, void 0, void 0, function* () {
        const testName = 'TestCircularEntityAttributes';
        const entityName = 'A';
        const corpus = testHelper_1.testHelper.getLocalCorpus(testsSubpath, testName);
        const entity = yield corpus.fetchObjectAsync(`${entityName}.cdm.json/${entityName}`);
        const resEntity = yield entity.createResolvedEntityAsync(`resolved-${entityName}`);
        expect(resEntity)
            .toBeDefined();
        expect(resEntity.attributes.length)
            .toEqual(2);
        done();
    }));
    /**
     * Tests if not setting the projection 'source' on an entity attribute triggers an error log
     */
    it('TestEntityAttributeSource', () => {
        const corpus = new internal_1.CdmCorpusDefinition();
        let errorCount = 0;
        corpus.setEventCallback((level, message) => {
            errorCount++;
        }, internal_1.cdmStatusLevel.error);
        const projection = new internal_1.CdmProjection(corpus.ctx);
        const entityAttribute = new internal_1.CdmEntityAttributeDefinition(corpus.ctx, 'attribute');
        entityAttribute.entity = new internal_1.CdmEntityReference(corpus.ctx, projection, false);
        // First case, a projection without source.
        projection.validate();
        expect(errorCount)
            .toEqual(1);
        errorCount = 0;
        // Second case, a projection with a nested projection.
        const innerProjection = new internal_1.CdmProjection(corpus.ctx);
        projection.source = new internal_1.CdmEntityReference(corpus.ctx, innerProjection, false);
        projection.validate();
        innerProjection.validate();
        expect(errorCount)
            .toEqual(1);
        errorCount = 0;
        // Third case, a projection with an explicit entity definition.
        innerProjection.source = new internal_1.CdmEntityReference(corpus.ctx, new internal_1.CdmEntityDefinition(corpus.ctx, 'Entity'), false);
        projection.validate();
        innerProjection.validate();
        expect(errorCount)
            .toEqual(0);
        // Third case, a projection with a named reference.
        innerProjection.source = new internal_1.CdmEntityReference(corpus.ctx, 'Entity', false);
        projection.validate();
        innerProjection.validate();
        expect(errorCount)
            .toEqual(0);
    });
    /**
     * Tests resolution of an entity when maximum depth is reached while resolving a polymorphic entity
     */
    it('TestMaxDepthOnPolymorphicEntity', () => __awaiter(void 0, void 0, void 0, function* () {
        const testName = 'TestMaxDepthOnPolymorphicEntity';
        const entityName = 'A';
        const corpus = testHelper_1.testHelper.getLocalCorpus(testsSubpath, testName);
        const entity = yield corpus.fetchObjectAsync(`${entityName}.cdm.json/${entityName}`);
        const resOpt = new internal_1.resolveOptions(entity);
        resOpt.maxDepth = 1;
        const resEntity = yield entity.createResolvedEntityAsync(`resolved-${entityName}`, resOpt);
        expect(resEntity)
            .not
            .toBeUndefined();
        expect(resEntity.attributes.length)
            .toBe(4);
    }));
    /**
     * Tests if setting the projection 'source' on a type attribute triggers an error log
     */
    it('TestTypeAttributeSource', () => {
        const corpus = new internal_1.CdmCorpusDefinition();
        let errorCount = 0;
        corpus.setEventCallback((level, message) => {
            errorCount++;
        }, internal_1.cdmStatusLevel.error);
        const projection = new internal_1.CdmProjection(corpus.ctx);
        const typeAttribute = new internal_1.CdmTypeAttributeDefinition(corpus.ctx, 'attribute');
        typeAttribute.projection = projection;
        // First case, a projection without source.
        projection.validate();
        expect(errorCount)
            .toEqual(0);
        // Second case, a projection with a nested projection.
        const innerProjection = new internal_1.CdmProjection(corpus.ctx);
        projection.source = new internal_1.CdmEntityReference(corpus.ctx, innerProjection, false);
        projection.validate();
        innerProjection.validate();
        expect(errorCount)
            .toEqual(0);
        // Third case, a projection with an explicit entity definition.
        innerProjection.source = new internal_1.CdmEntityReference(corpus.ctx, new internal_1.CdmEntityDefinition(corpus.ctx, 'Entity'), false);
        projection.validate();
        innerProjection.validate();
        expect(errorCount)
            .toEqual(1);
        errorCount = 0;
        // Third case, a projection with a named reference.
        innerProjection.source = new internal_1.CdmEntityReference(corpus.ctx, 'Entity', false);
        projection.validate();
        innerProjection.validate();
        expect(errorCount)
            .toEqual(1);
    });
    /**
     * Tests setting the 'runSequentially' flag to true
     */
    it('testRunSequentially', () => __awaiter(void 0, void 0, void 0, function* () {
        const testName = 'TestRunSequentially';
        const entityName = 'NewPerson';
        const corpus = testHelper_1.testHelper.getLocalCorpus(testsSubpath, testName);
        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']
        // Rename attributes 'age' to 'yearsOld' then 'phoneNumber' to 'contactNumber' followed by a add count attribute.
        expect(resolvedEntity.attributes.length)
            .toEqual(6);
        expect(resolvedEntity.attributes.allItems[0].name)
            .toEqual('name');
        expect(resolvedEntity.attributes.allItems[1].name)
            .toEqual('yearsOld');
        expect(resolvedEntity.attributes.allItems[2].name)
            .toEqual('address');
        expect(resolvedEntity.attributes.allItems[3].name)
            .toEqual('contactNumber');
        expect(resolvedEntity.attributes.allItems[4].name)
            .toEqual('email');
        expect(resolvedEntity.attributes.allItems[5].name)
            .toEqual('countAttribute');
    }));
    /**
     * Tests setting the 'runSequentially' flag to true mixed with 'sourceInput' set to true
     */
    it('testRunSequentiallyAndSourceInput', () => __awaiter(void 0, void 0, void 0, function* () {
        const testName = 'TestRunSequentiallyAndSourceInput';
        const entityName = 'NewPerson';
        const corpus = testHelper_1.testHelper.getLocalCorpus(testsSubpath, testName);
        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']
        // Replace 'age' with 'ageFK' and 'address' with 'addressFK' as foreign keys, followed by a add count attribute.
        expect(resolvedEntity.attributes.length)
            .toEqual(3);
        expect(resolvedEntity.attributes.allItems[0].name)
            .toEqual('ageFK');
        expect(resolvedEntity.attributes.allItems[1].name)
            .toEqual('addressFK');
        expect(resolvedEntity.attributes.allItems[2].name)
            .toEqual('countAttribute');
    }));
});
//# sourceMappingURL=ProjectionMiscellaneous.test.js.map