"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 ts_stopwatch_1 = require("ts-stopwatch");
const internal_1 = require("../../../internal");
const Persistence_1 = require("../../../Persistence");
const types_1 = require("../../../Persistence/CdmFolder/types");
const Storage_1 = require("../../../Storage");
const testHelper_1 = require("../../testHelper");
/**
 * The model json tests.
 */
// tslint:disable-next-line: max-func-body-length
describe('Persistence.ModelJson.ModelJson', () => {
    /**
     * Test path between TestDataPath and TestName.
     */
    const testsSubpath = 'Persistence/ModelJson/ModelJson';
    const cdmExtension = internal_1.CdmConstants.cdmExtension;
    const modelJsonExtension = internal_1.CdmConstants.modelJsonExtension;
    const manifestExtension = internal_1.CdmConstants.manifestExtension;
    /**
     * Test ManifestPersistence fromData and toData and save it back to a file.
     */
    it('TestModelJsonFromAndToData', () => __awaiter(void 0, void 0, void 0, function* () {
        const cdmCorpus = testHelper_1.testHelper.getLocalCorpus(testsSubpath, 'TestModelJsonFromAndToData');
        const stopwatch = new ts_stopwatch_1.Stopwatch();
        stopwatch.start();
        const absPath = cdmCorpus.storage.createAbsoluteCorpusPath(modelJsonExtension, cdmCorpus.storage.fetchRootFolder('local'));
        const cdmManifest = yield cdmCorpus.createRootManifest(absPath);
        const obtainedModelJson = yield Persistence_1.ModelJson.ManifestPersistence.toData(cdmManifest, undefined, undefined);
        stopwatch.stop();
        HandleOutput('TestModelJsonFromAndToData', modelJsonExtension, obtainedModelJson);
        expect(stopwatch.getTime())
            .toBeLessThan(800);
    }));
    /**
     * Test loading CDM folder files and save the model.json file
     */
    it('TestLoadingCdmFolderAndModelJsonToData', () => __awaiter(void 0, void 0, void 0, function* () {
        const cdmCorpus = testHelper_1.testHelper.getLocalCorpus(testsSubpath, 'TestLoadingCdmFolderAndModelJsonToData');
        const stopwatch = new ts_stopwatch_1.Stopwatch();
        stopwatch.start();
        const cdmManifest = yield cdmCorpus.fetchObjectAsync(`default${manifestExtension}`, cdmCorpus.storage.fetchRootFolder('local'));
        stopwatch.stop();
        expect(stopwatch.getTime())
            .toBeLessThan(8500);
        stopwatch.reset();
        stopwatch.start();
        const obtainedModelJson = yield Persistence_1.ModelJson.ManifestPersistence.toData(cdmManifest, undefined, undefined);
        stopwatch.stop();
        HandleOutput('TestLoadingCdmFolderAndModelJsonToData', modelJsonExtension, obtainedModelJson, true, true);
        expect(stopwatch.getTime())
            .toBeLessThan(8500);
    }));
    /**
     * Test loading model json result files and save it as CDM folder files.
     */
    it('TestLoadingModelJsonResultAndCdmFolderToData', () => __awaiter(void 0, void 0, void 0, function* () {
        const cdmCorpus = testHelper_1.testHelper.getLocalCorpus(testsSubpath, 'TestLoadingModelJsonResultAndCdmFolderToData');
        const absPath = cdmCorpus.storage.createAbsoluteCorpusPath(modelJsonExtension, cdmCorpus.storage.fetchRootFolder('local'));
        const stopwatch = new ts_stopwatch_1.Stopwatch();
        stopwatch.start();
        const cdmManifest = yield cdmCorpus.createRootManifest(absPath);
        stopwatch.stop();
        expect(stopwatch.getTime())
            .toBeLessThan(1500);
        stopwatch.reset();
        stopwatch.start();
        const obtainedCdmFolder = Persistence_1.CdmFolder.ManifestPersistence.toData(cdmManifest, undefined, undefined);
        stopwatch.stop();
        HandleOutput('TestLoadingModelJsonResultAndCdmFolderToData', `cdmFolder${cdmExtension}`, obtainedCdmFolder);
        expect(stopwatch.getTime())
            .toBeLessThan(1500);
    }));
    /**
     * Test if when loading a model.json file the foundations is imported correctly.
     */
    it('TestManifestFoundationImport', () => __awaiter(void 0, void 0, void 0, function* () {
        const corpus = testHelper_1.testHelper.getLocalCorpus(testsSubpath, 'TestManifestFoundationImport');
        corpus.setEventCallback((statusLevel, message1) => {
            if (statusLevel >= internal_1.cdmStatusLevel.error) {
                throw new Error(message1);
            }
        });
        const cdmManifest = yield corpus.fetchObjectAsync(modelJsonExtension, corpus.storage.fetchRootFolder('local'));
    }));
    /**
     * Test if the imports location are relative to the root level file.
     */
    it('TestImportsRelativePath', () => __awaiter(void 0, void 0, void 0, function* () {
        // the corpus path in the imports are relative to the document where it was defined.
        // when saving in model.json the documents are flattened to the manifest level
        // so it is necessary to recalculate the path to be relative to the manifest.
        const corpus = testHelper_1.testHelper.getLocalCorpus(testsSubpath, 'TestImportsRelativePath');
        const folder = corpus.storage.fetchRootFolder('local');
        const manifest = new internal_1.CdmManifestDefinition(corpus.ctx, 'manifest');
        const entityDeclaration = manifest.entities.push('EntityName', 'EntityName/EntityName.cdm.json/EntityName');
        folder.documents.push(manifest);
        const entityFolder = folder.childFolders.push('EntityName');
        const document = new internal_1.CdmDocumentDefinition(corpus.ctx, 'EntityName.cdm.json');
        document.imports.push('subfolder/EntityName.cdm.json');
        document.definitions.push('EntityName');
        entityFolder.documents.push(document);
        const subFolder = entityFolder.childFolders.push('subfolder');
        subFolder.documents.push('EntityName.cdm.json');
        corpus.storage.fetchRootFolder('remote').documents
            .push(manifest);
        const data = yield Persistence_1.ModelJson.ManifestPersistence.toData(manifest, undefined, undefined);
        expect(data.entities.length)
            .toBe(1);
        const imports = data.entities[0]['cdm:imports'];
        expect(imports.length)
            .toBe(1);
        expect(imports[0].corpusPath)
            .toBe('EntityName/subfolder/EntityName.cdm.json');
    }));
    /**
     * Test loading model.json files and save it as CDM folder files.
     */
    it('TestLoadingModelJsonAndCdmFolderToData', () => __awaiter(void 0, void 0, void 0, function* () {
        const cdmCorpus = testHelper_1.testHelper.getLocalCorpus(testsSubpath, 'TestLoadingModelJsonAndCdmFolderToData');
        const absPath = cdmCorpus.storage.createAbsoluteCorpusPath(modelJsonExtension, cdmCorpus.storage.fetchRootFolder('local'));
        const stopwatch = new ts_stopwatch_1.Stopwatch();
        stopwatch.start();
        const cdmManifest = yield cdmCorpus.createRootManifest(absPath);
        stopwatch.stop();
        expect(stopwatch.getTime())
            .toBeLessThan(1000);
        stopwatch.reset();
        stopwatch.start();
        const obtainedCdmFolder = Persistence_1.CdmFolder.ManifestPersistence.toData(cdmManifest, undefined, undefined);
        stopwatch.stop();
        HandleOutput('TestLoadingModelJsonAndCdmFolderToData', `cdmFolder${cdmExtension}`, obtainedCdmFolder);
        expect(stopwatch.getTime())
            .toBeLessThan(1000);
    }));
    /**
     * Test loading CDM folder result files and save as model.json
     */
    it('TestLoadingCdmFolderResultAndModelJsonToData', () => __awaiter(void 0, void 0, void 0, function* () {
        const cdmCorpus = testHelper_1.testHelper.getLocalCorpus(testsSubpath, 'TestLoadingCdmFolderResultAndModelJsonToData');
        const absPath = cdmCorpus.storage.createAbsoluteCorpusPath(`result.model${manifestExtension}`, cdmCorpus.storage.fetchRootFolder('local'));
        const stopwatch = new ts_stopwatch_1.Stopwatch();
        stopwatch.start();
        const cdmManifest = yield cdmCorpus.createRootManifest(absPath);
        stopwatch.stop();
        expect(stopwatch.getTime())
            .toBeLessThan(1500);
        stopwatch.reset();
        stopwatch.start();
        const obtainedModelJson = yield Persistence_1.ModelJson.ManifestPersistence.toData(cdmManifest, undefined, undefined);
        stopwatch.stop();
        expect(cdmManifest.imports.item(internal_1.constants.FOUNDATIONS_CORPUS_PATH, undefined, false))
            .toBeUndefined();
        expect(obtainedModelJson['cdm:imports'].length)
            .toBe(1);
        expect(obtainedModelJson['cdm:imports'][0]['corpusPath'])
            .toBe(internal_1.constants.FOUNDATIONS_CORPUS_PATH);
        HandleOutput('TestLoadingCdmFolderResultAndModelJsonToData', modelJsonExtension, obtainedModelJson);
        expect(stopwatch.getTime())
            .toBeLessThan(1500);
    }));
    /**
     * Tests loading Model.json and converting to CdmFolder
     */
    it('TestExtensibilityLoadingModelJsonAndCdmFolderToData', () => __awaiter(void 0, void 0, void 0, function* () {
        const cdmCorpus = testHelper_1.testHelper.getLocalCorpus(testsSubpath, 'TestExtensibilityLoadingModelJsonAndCdmFolderToData');
        const absPath = cdmCorpus.storage.createAbsoluteCorpusPath(modelJsonExtension, cdmCorpus.storage.fetchRootFolder('local'));
        const cdmManifest = yield cdmCorpus.createRootManifest(absPath);
        const obtainedCdmFolder = Persistence_1.CdmFolder.ManifestPersistence.toData(cdmManifest, undefined, undefined);
        // For EntityReferences, entityPath contains a GUID that will not match the snapshot.
        for (const entity of obtainedCdmFolder.entities) {
            if (entity.type === types_1.entityDeclarationDefinitionType.referencedEntity) {
                entity.entityPath = undefined;
            }
        }
        /**
         * entityDeclaration contains a GUID that will not match the snapshot.
         */
        obtainedCdmFolder.entities.forEach((entity) => {
            // tslint:disable-next-line: no-string-literal
            if (entity['entityDeclaration']) {
                // tslint:disable-next-line: no-string-literal
                entity['entityDeclaration'] = undefined;
            }
        });
        HandleOutput('TestExtensibilityLoadingModelJsonAndCdmFolderToData', `cdmFolder${cdmExtension}`, obtainedCdmFolder);
    }));
    it('TestReferenceModels', () => __awaiter(void 0, void 0, void 0, function* () {
        const corpus = testHelper_1.testHelper.getLocalCorpus(testsSubpath, 'TestReferenceModels');
        const manifest = yield corpus.fetchObjectAsync(modelJsonExtension, corpus.storage.fetchRootFolder('local'));
        // entity with same modelId but different location
        const referenceEntity1 = new internal_1.CdmReferencedEntityDeclarationDefinition(corpus.ctx, 'ReferenceEntity1');
        referenceEntity1.entityPath = 'remote:/contoso/entity1.model.json/Entity1';
        const modelIdTrait1 = referenceEntity1.exhibitsTraits.push('is.propertyContent.multiTrait');
        modelIdTrait1.isFromProperty = true;
        modelIdTrait1.arguments.push('modelId', 'f19bbb97-c031-441a-8bd1-61b9181c0b83/1a7ef9c8-c7e8-45f8-9d8a-b80f8ffe4612');
        manifest.entities.push(referenceEntity1);
        // entity without modelId but same location
        const referenceEntity2 = new internal_1.CdmReferencedEntityDeclarationDefinition(corpus.ctx, 'ReferenceEntity2');
        referenceEntity2.entityPath = 'remote:/contoso/entity.model.json/Entity2';
        manifest.entities.push(referenceEntity2);
        // entity with modelId and new location
        const referenceEntity3 = new internal_1.CdmReferencedEntityDeclarationDefinition(corpus.ctx, 'ReferenceEntity3');
        referenceEntity3.entityPath = 'remote:/contoso/entity3.model.json/Entity3';
        const modelIdTrait3 = referenceEntity3.exhibitsTraits.push('is.propertyContent.multiTrait');
        modelIdTrait3.isFromProperty = true;
        modelIdTrait3.arguments.push('modelId', '3b2e040a-c8c5-4508-bb42-09952eb04a50');
        manifest.entities.push(referenceEntity3);
        // entity with same modelId and same location
        const referenceEntity4 = new internal_1.CdmReferencedEntityDeclarationDefinition(corpus.ctx, 'ReferenceEntity4');
        referenceEntity4.entityPath = 'remote:/contoso/entity.model.json/Entity4';
        const modelIdTrait4 = referenceEntity4.exhibitsTraits.push('is.propertyContent.multiTrait');
        modelIdTrait4.isFromProperty = true;
        modelIdTrait4.arguments.push('modelId', 'f19bbb97-c031-441a-8bd1-61b9181c0b83/1a7ef9c8-c7e8-45f8-9d8a-b80f8ffe4612');
        manifest.entities.push(referenceEntity4);
        const obtainedModelJson = yield Persistence_1.ModelJson.ManifestPersistence.toData(manifest, undefined, undefined);
        HandleOutput('TestReferenceModels', modelJsonExtension, obtainedModelJson);
    }));
    /**
     * Tests that a description on a CdmFolder entity sets the description on the ModelJson entity.
     */
    it('TestSettingModelJsonEntityDescription', () => __awaiter(void 0, void 0, void 0, function* () {
        const cdmCorpus = new internal_1.CdmCorpusDefinition();
        cdmCorpus.setEventCallback(() => { }, internal_1.cdmStatusLevel.error);
        const cdmManifest = cdmCorpus.MakeObject(internal_1.cdmObjectType.manifestDef, 'test');
        const document = cdmCorpus.MakeObject(internal_1.cdmObjectType.documentDef, `entity${cdmExtension}`);
        const folder = cdmCorpus.storage.fetchRootFolder('local');
        folder.documents.push(document);
        const entity = document.definitions.push(internal_1.cdmObjectType.entityDef, 'entity');
        entity.description = 'test description';
        cdmManifest.entities.push(entity);
        folder.documents.push(cdmManifest);
        const obtainedModelJson = yield Persistence_1.ModelJson.ManifestPersistence.toData(cdmManifest, undefined, undefined);
        expect(obtainedModelJson.entities[0].description)
            .toEqual('test description');
    }));
    /**
     * Tests that traits that convert into annotations are properly converted on load and save
     */
    it('TestLoadingAndSavingCdmTraits', () => __awaiter(void 0, void 0, void 0, function* () {
        const cdmCorpus = testHelper_1.testHelper.getLocalCorpus(testsSubpath, 'TestLoadingAndSavingCdmTraits');
        const manifest = yield cdmCorpus.fetchObjectAsync('model.json');
        const entity = yield cdmCorpus.fetchObjectAsync('someEntity.cdm.json/someEntity');
        expect(entity.exhibitsTraits.item('is.CDM.entityVersion'))
            .not.toBeUndefined();
        const manifestData = yield Persistence_1.ModelJson.ManifestPersistence.toData(manifest, new internal_1.resolveOptions(manifest.inDocument), new internal_1.copyOptions());
        const versionAnnotation = manifestData.entities[0]['annotations'][0];
        expect(versionAnnotation.value)
            .toBe('<version>');
    }));
    /**
     * Tests that the "date" and "time" data types are correctly loaded/saved from/to a model.json.
     */
    it('TestLoadingAndSavingDateAndTimeDataTypes', () => __awaiter(void 0, void 0, void 0, function* () {
        const cdmCorpus = testHelper_1.testHelper.getLocalCorpus(testsSubpath, 'TestLoadingAndSavingDateAndTimeDataTypes');
        // Load the manifest and resolve it
        const manifest = yield cdmCorpus.fetchObjectAsync('local:/default.manifest.cdm.json');
        const resolvedManifest = yield manifest.createResolvedManifestAsync('resolved', undefined);
        // Convert loaded manifest to model.json
        const modelJson = yield Persistence_1.ModelJson.ManifestPersistence.toData(resolvedManifest, undefined, undefined);
        // Verify that the attributes' data types were correctly persisted as "date" and "time"
        expect(modelJson.entities[0].attributes[0].dataType)
            .toEqual('date');
        expect(modelJson.entities[0].attributes[1].dataType)
            .toEqual('time');
        // Now check that these attributes' data types are still "date" and "time" when loading the model.json back to manifest
        // We first need to create a second adapter to the input folder to fool the OM into thinking it's different
        // This is because there's a bug that currently prevents us from saving and then loading a model.json under the same namespace
        cdmCorpus.storage.mount('local2', new Storage_1.LocalAdapter(testHelper_1.testHelper.getInputFolderPath(testsSubpath, 'TestLoadingAndSavingDateAndTimeDataTypes')));
        const manifestFromModelJson = yield cdmCorpus.fetchObjectAsync('local2:/model.json');
        const entity = yield cdmCorpus.fetchObjectAsync(manifestFromModelJson.entities.allItems[0].entityPath, manifestFromModelJson);
        // Verify that the attributes' data types were correctly loaded as "date" and "time"
        expect(entity.attributes.allItems[0].dataFormat)
            .toEqual(internal_1.cdmDataFormat.date);
        expect(entity.attributes.allItems[1].dataFormat)
            .toEqual(internal_1.cdmDataFormat.time);
    }));
    /**
     * Test model.json is correctly created without an entity when the location is not recognized
     */
    it('TestIncorrectModelLocation', () => __awaiter(void 0, void 0, void 0, function* () {
        const expectedLogs = new Set([internal_1.cdmLogCode.ErrStorageInvalidAdapterPath, internal_1.cdmLogCode.ErrPersistModelJsonEntityParsingError, internal_1.cdmLogCode.ErrPersistModelJsonRefEntityInvalidLocation]);
        const corpus = testHelper_1.testHelper.getLocalCorpus(testsSubpath, 'TestIncorrectModelLocation', undefined, false, expectedLogs);
        const manifest = yield corpus.fetchObjectAsync('model.json');
        expect(manifest)
            .not.toBeUndefined();
        expect(manifest.entities.length)
            .toBe(0);
        testHelper_1.testHelper.expectCdmLogCodeEquality(corpus, internal_1.cdmLogCode.ErrPersistModelJsonRefEntityInvalidLocation, true);
    }));
    /**
     * Handles the obtained output.
     * If needed, writes the output to a test debugging file.
     * It reads expected output and compares it to the actual output.
     * @param testName The name of the test.
     * @param outputFileName The name of the output file. Used both for expected and actual output.
     * @param actualOutput The output obtained through operations, that is to be compared with the expected output.
     * @param isLanguageSpecific There is subfolder called Typescript.
     */
    function HandleOutput(testName, outputFileName, actualOutput, doesWriteTestDebuggingFiles, isLanguageSpecific) {
        const actualOutputSerialized = JSON.stringify(actualOutput);
        if (doesWriteTestDebuggingFiles) {
            testHelper_1.testHelper.writeActualOutputFileContent(testsSubpath, testName, outputFileName, actualOutputSerialized);
        }
        const expectedOutputSerialized = testHelper_1.testHelper.getExpectedOutputFileContent(testsSubpath, testName, outputFileName, isLanguageSpecific);
        const expectedOutput = JSON.parse(expectedOutputSerialized);
        testHelper_1.testHelper.assertObjectContentEquality(expectedOutput, actualOutput);
    }
});
//# sourceMappingURL=modelJson.test.js.map