var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {
    if (value !== null && value !== void 0) {
        if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
        var dispose, inner;
        if (async) {
            if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
            dispose = value[Symbol.asyncDispose];
        }
        if (dispose === void 0) {
            if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
            dispose = value[Symbol.dispose];
            if (async) inner = dispose;
        }
        if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
        if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };
        env.stack.push({ value: value, dispose: dispose, async: async });
    }
    else if (async) {
        env.stack.push({ async: true });
    }
    return value;
};
var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
    return function (env) {
        function fail(e) {
            env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
            env.hasError = true;
        }
        var r, s = 0;
        function next() {
            while (r = env.stack.pop()) {
                try {
                    if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
                    if (r.dispose) {
                        var result = r.dispose.call(r.value);
                        if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
                    }
                    else s |= 1;
                }
                catch (e) {
                    fail(e);
                }
            }
            if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
            if (env.hasError) throw env.error;
        }
        return next();
    };
})(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
    var e = new Error(message);
    return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
});
import { SchemaItem, SchemaItemKey, SchemaItemType, SchemaKey, SchemaMatchType } from "@itwin/ecschema-metadata";
import { expect } from "chai";
import { IModelIncrementalSchemaLocater } from "../../IModelIncrementalSchemaLocater";
import { TestContext } from "./TestContext";
import oldConfiguration from "../assets/IncrementalSchemaLocater/configs/old.config";
import simpleConfiguration from "../assets/IncrementalSchemaLocater/configs/simple.config";
import * as chai from "chai";
import * as chaiAsPromised from "chai-as-promised";
chai.use(chaiAsPromised);
function parseSchemaItemKey(itemKey) {
    const [schemaName, itemName] = SchemaItem.parseFullName(itemKey);
    const schemaKey = SchemaKey.parseString(`${schemaName}.0.0.0`);
    return new SchemaItemKey(itemName, schemaKey);
}
describe("Incremental Schema Loading", function () {
    describe("Simple iModel Incremental Loading Tests", () => {
        const testSchemaConfiguration = simpleConfiguration.schemas[0];
        const testSchemaKey = new SchemaKey(testSchemaConfiguration.name, 1, 0, 0);
        it("should get schema info", async () => {
            const env_1 = { stack: [], error: void 0, hasError: false };
            try {
                const env = __addDisposableResource(env_1, await TestContext.create(), true);
                await env.importAssetSchema(testSchemaKey);
                const schemaInfo = await env.schemaContext.getSchemaInfo(testSchemaKey, SchemaMatchType.Exact);
                expect(schemaInfo).to.be.not.undefined;
                expect(schemaInfo).to.have.nested.property("schemaKey.name", testSchemaKey.name);
                expect(schemaInfo).to.have.property("references").to.have.a.lengthOf(testSchemaConfiguration.references.length);
                expect(schemaInfo).to.have.property("references").to.satisfy((refs) => {
                    for (const ref of refs) {
                        expect(testSchemaConfiguration.references, `Could not find referenced schema: ${ref.schemaKey.name}`).to.include(ref.schemaKey.name);
                    }
                    return true;
                });
            }
            catch (e_1) {
                env_1.error = e_1;
                env_1.hasError = true;
            }
            finally {
                const result_1 = __disposeResources(env_1);
                if (result_1)
                    await result_1;
            }
        });
        it("should get schema with item stubs", async () => {
            const env_2 = { stack: [], error: void 0, hasError: false };
            try {
                const env = __addDisposableResource(env_2, await TestContext.create(), true);
                await env.importAssetSchema(testSchemaKey);
                const schema = await env.schemaContext.getSchema(testSchemaKey);
                expect(schema).to.be.not.undefined;
                expect(schema).to.have.property("name", testSchemaKey.name);
                expect(schema).to.have.property("description", testSchemaConfiguration.description);
                expect(schema).to.have.property("label", testSchemaConfiguration.label);
                expect(schema).to.have.property("references").to.have.a.lengthOf(testSchemaConfiguration.references.length);
                for (const item of schema.getItems()) {
                    expect(item).to.have.property("name");
                    expect(item).to.have.property("schemaItemType").to.satisfy((type) => SchemaItemType[type] !== undefined);
                }
                expect(schema).to.be.not.undefined;
                expect(schema).to.have.property("name", testSchemaKey.name);
                const items = [...schema.getItems()];
                expect(items).to.have.a.lengthOf(testSchemaConfiguration.itemCount);
                for (const checkStub of testSchemaConfiguration.checkStubs) {
                    const item = await schema.lookupItem(checkStub.item);
                    expect(item).to.be.not.undefined;
                    const props = item.toJSON();
                    for (const [propertyName, propertyValue] of Object.entries(checkStub.properties)) {
                        expect(props).to.have.property(propertyName).deep.equalInAnyOrder(propertyValue);
                    }
                }
            }
            catch (e_2) {
                env_2.error = e_2;
                env_2.hasError = true;
            }
            finally {
                const result_2 = __disposeResources(env_2);
                if (result_2)
                    await result_2;
            }
        });
        it("should get schema with class stubs with hierarchy", async () => {
            const env_3 = { stack: [], error: void 0, hasError: false };
            try {
                const env = __addDisposableResource(env_3, await TestContext.create(), true);
                await env.importAssetSchema(testSchemaKey);
                const schema = await env.schemaContext.getSchema(testSchemaKey);
                expect(schema).to.be.not.undefined;
                expect(schema).to.have.property("name", testSchemaKey.name);
                const derivedClassKey = parseSchemaItemKey(testSchemaConfiguration.checkHierachy.derivedClass);
                const derivedClass = await env.schemaContext.getSchemaItem(derivedClassKey);
                expect(derivedClass, `${derivedClassKey.fullName} was not found`).to.be.not.undefined;
                const baseClassKey = parseSchemaItemKey(testSchemaConfiguration.checkHierachy.baseClass);
                const baseClass = await env.schemaContext.getSchemaItem(baseClassKey);
                expect(baseClass, `${baseClassKey.fullName} was not found`).to.be.not.undefined;
                const isDerivedFrom = await derivedClass.is(baseClass);
                expect(isDerivedFrom, `${derivedClass.name} is not derived from ${baseClass.name}`).to.be.true;
            }
            catch (e_3) {
                env_3.error = e_3;
                env_3.hasError = true;
            }
            finally {
                const result_3 = __disposeResources(env_3);
                if (result_3)
                    await result_3;
            }
        });
        it("should get schema full schema stack", async () => {
            const env_4 = { stack: [], error: void 0, hasError: false };
            try {
                const env = __addDisposableResource(env_4, await TestContext.create(), true);
                await env.importAssetSchema(testSchemaKey);
                const schema = await env.schemaContext.getSchema(testSchemaKey);
                expect(schema).to.be.not.undefined;
                expect(schema).to.have.property("name", testSchemaKey.name);
                expect(schema).to.have.property("references").to.have.a.lengthOf(testSchemaConfiguration.references.length);
                for (const item of schema.getItems()) {
                    expect(item).to.have.property("name");
                    expect(item).to.have.property("schemaItemType").to.satisfy((type) => SchemaItemType[type] !== undefined);
                }
                expect(schema).to.be.not.undefined;
                expect(schema).to.have.property("name", testSchemaKey.name);
                // Wait till schemas are fully loaded to be comparable.
                // TODO: remove this check when issue #1763 is fixed.
                if (schema.loadingController)
                    await schema.loadingController.wait();
                const items = [...schema.getItems()];
                expect(items).to.have.a.lengthOf(testSchemaConfiguration.itemCount);
                for (const checkItem of testSchemaConfiguration.checkFullLoad) {
                    const item = await schema.lookupItem(checkItem.item);
                    expect(item).to.be.not.undefined;
                    const itemProps = item.toJSON();
                    for (const [propertyName, propertyValue] of Object.entries(checkItem.properties)) {
                        expect(itemProps).to.have.property(propertyName).deep.equalInAnyOrder(propertyValue);
                    }
                }
            }
            catch (e_4) {
                env_4.error = e_4;
                env_4.hasError = true;
            }
            finally {
                const result_4 = __disposeResources(env_4);
                if (result_4)
                    await result_4;
            }
        });
    });
    describe("Old Schema profile in iModel Tests", () => {
        it("should succeed with incremental loading fallback.", async () => {
            const env_5 = { stack: [], error: void 0, hasError: false };
            try {
                const env = __addDisposableResource(env_5, await TestContext.create({
                    bimFile: oldConfiguration.bimFile,
                }), true);
                const resolveSchemaKey = async (schemaName) => {
                    const schemaFullName = (await env.getSchemaNames()).find((name) => name.startsWith(schemaName));
                    if (schemaFullName === undefined) {
                        throw new Error(`Test schema '${schemaName}' not found`);
                    }
                    return SchemaKey.parseString(schemaFullName);
                };
                const testSchemaConfiguration = oldConfiguration.schemas[0];
                const testSchemaKey = await resolveSchemaKey(testSchemaConfiguration.name);
                const schema = await env.schemaContext.getSchema(testSchemaKey);
                expect(schema).to.be.not.undefined;
                expect(schema).to.have.property("name", testSchemaKey.name);
                expect(schema).to.have.property("references").to.have.a.lengthOf(testSchemaConfiguration.references.length);
                for (const item of schema.getItems()) {
                    expect(item).to.have.property("name");
                    expect(item).to.have.property("schemaItemType").to.satisfy((type) => SchemaItemType[type] !== undefined);
                }
                expect(schema).to.be.not.undefined;
                expect(schema).to.have.property("name", testSchemaKey.name);
                const items = [...schema.getItems()];
                expect(items).to.have.a.lengthOf(testSchemaConfiguration.itemCount);
                for (const checkItem of testSchemaConfiguration.checkFullLoad) {
                    const item = await schema.lookupItem(checkItem.item);
                    expect(item).to.be.not.undefined;
                    const itemProps = item.toJSON();
                    for (const [propertyName, propertyValue] of Object.entries(checkItem.properties)) {
                        expect(itemProps).to.have.property(propertyName).deep.equalInAnyOrder(propertyValue);
                    }
                }
            }
            catch (e_5) {
                env_5.error = e_5;
                env_5.hasError = true;
            }
            finally {
                const result_5 = __disposeResources(env_5);
                if (result_5)
                    await result_5;
            }
        });
    });
    describe("Test Incremental Loading setup", () => {
        it("schema context should not have an instance of incremental schema locater if loading is disabled", async () => {
            const env_6 = { stack: [], error: void 0, hasError: false };
            try {
                const env = __addDisposableResource(env_6, await TestContext.create({ incrementalSchemaLoading: "disabled" }), true);
                const locaters = env.iModel.schemaContext.locaters;
                const incrementalLocater = locaters.find((locater) => locater instanceof IModelIncrementalSchemaLocater);
                expect(incrementalLocater).to.be.undefined;
            }
            catch (e_6) {
                env_6.error = e_6;
                env_6.hasError = true;
            }
            finally {
                const result_6 = __disposeResources(env_6);
                if (result_6)
                    await result_6;
            }
        });
        it("schema context should have an instance of incremental schema locater if loading is enabled", async () => {
            const env_7 = { stack: [], error: void 0, hasError: false };
            try {
                const env = __addDisposableResource(env_7, await TestContext.create({ incrementalSchemaLoading: "enabled" }), true);
                const locaters = env.iModel.schemaContext.locaters;
                const incrementalLocater = locaters.find((locater) => locater instanceof IModelIncrementalSchemaLocater);
                expect(incrementalLocater).to.be.not.undefined;
            }
            catch (e_7) {
                env_7.error = e_7;
                env_7.hasError = true;
            }
            finally {
                const result_7 = __disposeResources(env_7);
                if (result_7)
                    await result_7;
            }
        });
        it("schema context should not have an instance of incremental schema locater if loading is not specified", async () => {
            const env_8 = { stack: [], error: void 0, hasError: false };
            try {
                const env = __addDisposableResource(env_8, await TestContext.create({ incrementalSchemaLoading: undefined }), true);
                const locaters = env.iModel.schemaContext.locaters;
                const incrementalLocater = locaters.find((locater) => locater instanceof IModelIncrementalSchemaLocater);
                expect(incrementalLocater).to.be.undefined;
            }
            catch (e_8) {
                env_8.error = e_8;
                env_8.hasError = true;
            }
            finally {
                const result_8 = __disposeResources(env_8);
                if (result_8)
                    await result_8;
            }
        });
    });
});
//# sourceMappingURL=IncrementalLoading.test.js.map