/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
import { strict as assert } from "assert";
import { createIdCompressor } from "@fluidframework/id-compressor";
import { DetachedFieldIndex, RevisionTagCodec } from "../../core/index.js";
import { brand, idAllocatorFromMaxId, } from "../../util/index.js";
import { typeboxValidator } from "../../external-utilities/index.js";
// eslint-disable-next-line import/no-internal-modules
import { makeDetachedNodeToFieldCodec } from "../../core/tree/detachedFieldIndexCodec.js";
import { takeJsonSnapshot, useSnapshotDirectory } from "../snapshots/index.js";
import { testIdCompressor, testRevisionTagCodec } from "../utils.js";
// eslint-disable-next-line import/no-internal-modules
import { createSnapshotCompressor } from "../snapshots/testTrees.js";
const mintedTag = testIdCompressor.generateCompressedId();
const finalizedTag = testIdCompressor.normalizeToOpSpace(mintedTag);
const malformedIdCompressor = createIdCompressor();
const malformedRevisionTagCodec = new RevisionTagCodec(malformedIdCompressor);
const malformedData = [
    [
        "missing data",
        {
            version: 1,
            maxId: -1,
        },
    ],
    [
        "incorrect version",
        {
            version: 2,
            data: [],
            maxId: -1,
        },
    ],
    [
        "additional piece of data in entry",
        {
            version: 1,
            data: [[1, 2, 3, 4]],
            maxId: -1,
        },
    ],
    [
        "incorrect data type",
        {
            version: 1,
            data: "incorrect data type",
            maxId: -1,
        },
    ],
    [
        "a string",
        JSON.stringify({
            version: 1,
            data: [],
            maxId: -1,
        }),
    ],
    [
        "Unfinalized id",
        {
            version: 1,
            data: [[malformedIdCompressor.generateCompressedId(), 2, 3]],
            maxId: -1,
        },
    ],
];
const validData = [
    [
        "empty data",
        {
            version: 1,
            data: [],
            maxId: brand(-1),
        },
    ],
    [
        "revision with a single entry",
        {
            version: 1,
            data: [[brand(finalizedTag), 0, brand(1)]],
            maxId: brand(-1),
        },
    ],
    [
        "revision with multiple entries",
        {
            version: 1,
            data: [
                [
                    brand(finalizedTag),
                    [
                        [1, brand(0)],
                        [0, brand(1)],
                    ],
                ],
            ],
            maxId: brand(-1),
        },
    ],
];
export function generateTestCases(idCompressor) {
    const revision = idCompressor.generateCompressedId();
    const maxId = brand(42);
    return [
        {
            name: "empty",
            data: {
                maxId,
                data: new Map(),
            },
        },
        {
            name: "single range with single node",
            data: {
                maxId,
                data: new Map([[revision, new Map([[0, 1]])]]),
            },
        },
        {
            name: "multiple nodes that do not form a single range",
            data: {
                maxId,
                data: new Map([
                    [
                        revision,
                        new Map([
                            [2, 1],
                            [0, 2],
                            [1, 4],
                        ]),
                    ],
                ]),
            },
        },
        {
            name: "multiple nodes that form ranges",
            data: {
                maxId,
                data: new Map([
                    [
                        revision,
                        new Map([
                            [1, 2],
                            [3, 4],
                            [2, 3],
                            [7, 6],
                            [6, 5],
                        ]),
                    ],
                ]),
            },
        },
    ];
}
describe("DetachedFieldIndex", () => {
    it("encodes with a version stamp.", () => {
        const detachedFieldIndex = new DetachedFieldIndex("test", idAllocatorFromMaxId(), testRevisionTagCodec, { jsonValidator: typeboxValidator });
        const expected = {
            version: 1,
            data: [],
            maxId: -1,
        };
        assert.deepEqual(detachedFieldIndex.encode(), expected);
    });
    describe("round-trip through JSON", () => {
        const codec = makeDetachedNodeToFieldCodec(testRevisionTagCodec, {
            jsonValidator: typeboxValidator,
        });
        for (const { name, data } of generateTestCases(testIdCompressor)) {
            it(name, () => {
                const encoded = codec.encode(data);
                const decoded = codec.decode(encoded);
                assert.deepEqual(decoded, data);
            });
        }
    });
    describe("loadData", () => {
        describe("accepts correct data", () => {
            for (const [name, data] of validData) {
                it(name, () => {
                    const detachedFieldIndex = new DetachedFieldIndex("test", idAllocatorFromMaxId(), testRevisionTagCodec, {
                        jsonValidator: typeboxValidator,
                    });
                    detachedFieldIndex.loadData(data);
                });
            }
        });
        describe("throws on receiving malformed data", () => {
            for (const [name, data] of malformedData) {
                it(name, () => {
                    const id = idAllocatorFromMaxId();
                    const detachedFieldIndex = new DetachedFieldIndex("test", id, malformedRevisionTagCodec, {
                        jsonValidator: typeboxValidator,
                    });
                    assert.throws(() => detachedFieldIndex.loadData(data), "Expected malformed data to throw an error on decode, but it did not.");
                });
            }
        });
    });
    describe("Snapshots", () => {
        useSnapshotDirectory("detached-field-index");
        const snapshotIdCompressor = createSnapshotCompressor();
        const snapshotRevisionTagCodec = new RevisionTagCodec(snapshotIdCompressor);
        const codec = makeDetachedNodeToFieldCodec(snapshotRevisionTagCodec, {
            jsonValidator: typeboxValidator,
        });
        const testCases = generateTestCases(snapshotIdCompressor);
        for (const { name, data: change } of testCases) {
            it(name, () => {
                const encoded = codec.encode(change);
                takeJsonSnapshot(encoded);
            });
        }
    });
});
//# sourceMappingURL=detachedFieldIndex.spec.js.map