"use strict";
/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
Object.defineProperty(exports, "__esModule", { value: true });
const node_assert_1 = require("node:assert");
const ops_js_1 = require("../ops.js");
const testClient_js_1 = require("./testClient.js");
const testUtils_js_1 = require("./testUtils.js");
describe("obliterate", () => {
    let client;
    let refSeq;
    const localClientId = 17;
    const remoteClientId = localClientId + 1;
    beforeEach(() => {
        client = new testClient_js_1.TestClient({
            mergeTreeEnableObliterate: true,
        });
        client.startOrUpdateCollaboration("local");
        for (const char of "hello world") {
            client.applyMsg(client.makeOpMessage(client.insertTextLocal(client.getLength(), char), client.getCurrentSeq() + 1));
        }
        node_assert_1.strict.equal(client.getText(), "hello world");
        refSeq = client.getCurrentSeq();
    });
    it("removes text", () => {
        client.obliterateRangeLocal(0, client.getLength());
        node_assert_1.strict.equal(client.getText(), "");
    });
    describe("concurrent obliterate and insert", () => {
        it("removes text for obliterate then insert", () => {
            (0, testUtils_js_1.obliterateRange)({
                mergeTree: client.mergeTree,
                start: 0,
                end: client.getLength(),
                refSeq,
                clientId: remoteClientId,
                seq: refSeq + 1,
                opArgs: undefined,
            });
            (0, testUtils_js_1.insertText)({
                mergeTree: client.mergeTree,
                pos: 1,
                refSeq,
                clientId: remoteClientId + 1,
                seq: refSeq + 2,
                text: "more ",
                props: undefined,
                opArgs: { op: { type: ops_js_1.MergeTreeDeltaType.INSERT } },
            });
            node_assert_1.strict.equal(client.getText(), "");
        });
        it("removes text for insert then obliterate when deleting entire string", () => {
            (0, testUtils_js_1.insertText)({
                mergeTree: client.mergeTree,
                pos: 1,
                refSeq,
                clientId: remoteClientId + 1,
                seq: refSeq + 1,
                text: "more ",
                props: undefined,
                opArgs: { op: { type: ops_js_1.MergeTreeDeltaType.INSERT } },
            });
            (0, testUtils_js_1.obliterateRange)({
                mergeTree: client.mergeTree,
                start: 0,
                end: "hello world".length,
                refSeq,
                clientId: remoteClientId,
                seq: refSeq + 2,
                opArgs: undefined,
            });
            node_assert_1.strict.equal(client.getText(), "");
        });
        it("removes text for insert then obliterate", () => {
            (0, testUtils_js_1.insertText)({
                mergeTree: client.mergeTree,
                pos: 5,
                refSeq,
                clientId: remoteClientId + 1,
                seq: refSeq + 1,
                text: "more ",
                props: undefined,
                opArgs: { op: { type: ops_js_1.MergeTreeDeltaType.INSERT } },
            });
            (0, testUtils_js_1.obliterateRange)({
                mergeTree: client.mergeTree,
                start: 1,
                end: "hello world".length,
                refSeq,
                clientId: remoteClientId,
                seq: refSeq + 2,
                opArgs: undefined,
            });
            node_assert_1.strict.equal(client.getText(), "h");
        });
    });
    describe("endpoint behavior", () => {
        it("does not expand to include text inserted at start", () => {
            (0, testUtils_js_1.obliterateRange)({
                mergeTree: client.mergeTree,
                start: 5,
                end: client.getLength(),
                refSeq,
                clientId: remoteClientId,
                seq: refSeq + 1,
                opArgs: undefined,
            });
            (0, testUtils_js_1.insertText)({
                mergeTree: client.mergeTree,
                pos: 5,
                refSeq,
                clientId: remoteClientId + 1,
                seq: refSeq + 2,
                text: "XXX",
                props: undefined,
                opArgs: { op: { type: ops_js_1.MergeTreeDeltaType.INSERT } },
            });
            node_assert_1.strict.equal(client.getText(), "helloXXX");
        });
        it("does not expand to include text inserted at end", () => {
            (0, testUtils_js_1.obliterateRange)({
                mergeTree: client.mergeTree,
                start: 0,
                end: "hello".length,
                refSeq,
                clientId: remoteClientId,
                seq: refSeq + 1,
                opArgs: undefined,
            });
            (0, testUtils_js_1.insertText)({
                mergeTree: client.mergeTree,
                pos: 5,
                refSeq,
                clientId: remoteClientId + 1,
                seq: refSeq + 2,
                text: "XXX",
                props: undefined,
                opArgs: { op: { type: ops_js_1.MergeTreeDeltaType.INSERT } },
            });
            node_assert_1.strict.equal(client.getText(), "XXX world");
        });
    });
    describe("local obliterate with concurrent inserts", () => {
        it("removes range when pending local obliterate op", () => {
            client.obliterateRangeLocal(0, client.getLength());
            (0, testUtils_js_1.insertText)({
                mergeTree: client.mergeTree,
                pos: 1,
                refSeq,
                clientId: remoteClientId,
                seq: refSeq + 2,
                text: "XXX",
                props: undefined,
                opArgs: { op: { type: ops_js_1.MergeTreeDeltaType.INSERT } },
            });
            node_assert_1.strict.equal(client.getText(), "");
        });
    });
    describe("local references", () => {
        it("cleans up local references once the collab window advances enough", () => {
            const client2 = new testClient_js_1.TestClient({ mergeTreeEnableObliterate: true });
            client2.startOrUpdateCollaboration("client2");
            const obliterateStart = 0;
            const obliterateEnd = client.getLength();
            const startSeg = client.getContainingSegment(obliterateStart);
            const endSeg = client.getContainingSegment(obliterateEnd);
            let seq = refSeq;
            (0, testUtils_js_1.obliterateRange)({
                mergeTree: client.mergeTree,
                start: obliterateStart,
                end: obliterateEnd,
                refSeq,
                clientId: remoteClientId,
                seq: ++seq,
                opArgs: undefined,
            });
            (0, testUtils_js_1.insertText)({
                mergeTree: client.mergeTree,
                pos: 1,
                refSeq,
                clientId: remoteClientId + 1,
                seq: ++seq,
                text: "more ",
                props: undefined,
                opArgs: { op: { type: ops_js_1.MergeTreeDeltaType.INSERT } },
            });
            node_assert_1.strict.equal(client.getText(), "");
            startSeg.segment?.localRefs?.walkReferences((ref) => {
                const oblProps = ref.properties?.obliterate;
                (0, node_assert_1.strict)(oblProps?.start !== undefined, "start ref should NOT be removed");
            });
            endSeg.segment?.localRefs?.walkReferences((ref) => {
                const oblProps = ref.properties?.obliterate;
                (0, node_assert_1.strict)(oblProps?.end !== undefined, "end ref should NOT be removed");
            });
            // this will force Zamboni to run
            for (let i = 0; i < 5; i++) {
                const insert = client.makeOpMessage(client.insertTextLocal(client.getLength(), i.toString()), ++seq);
                insert.minimumSequenceNumber = seq - 1;
                client.applyMsg(insert);
                client2.applyMsg(insert);
            }
            // want to check that the start and end segment don't have the obliterate refs on them
            startSeg.segment?.localRefs?.walkReferences((ref) => {
                const oblProps = ref.properties?.obliterate;
                (0, node_assert_1.strict)(oblProps.start === undefined, "start ref should be removed");
            });
            endSeg.segment?.localRefs?.walkReferences((ref) => {
                const oblProps = ref.properties?.obliterate;
                (0, node_assert_1.strict)(oblProps.end === undefined, "end ref should be removed");
            });
        });
    });
});
//# sourceMappingURL=obliterate.spec.js.map