"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const test_utils_1 = require("../testing/test-utils");
const Note_1 = require("../models/Note");
const Revision_1 = require("../models/Revision");
describe('models/Revision', () => {
    beforeEach(async () => {
        await (0, test_utils_1.setupDatabaseAndSynchronizer)(1);
        await (0, test_utils_1.switchClient)(1);
    });
    it('should create patches of text and apply it', (async () => {
        const note1 = await Note_1.default.save({ body: 'my note\nsecond line' });
        const patch = Revision_1.default.createTextPatch(note1.body, 'my new note\nsecond line');
        const merged = Revision_1.default.applyTextPatch(note1.body, patch);
        expect(merged).toBe('my new note\nsecond line');
    }));
    it('should check if it is an empty revision', async () => {
        const testCases = [
            [false, {
                    title_diff: '',
                    body_diff: '',
                    metadata_diff: '{"new":{"id":"aaa"},"deleted":[]}',
                }],
            [true, {
                    title_diff: '',
                    body_diff: '',
                    metadata_diff: '',
                }],
            [true, {
                    title_diff: '[]',
                    body_diff: '',
                    metadata_diff: '{"new":{},"deleted":[]}',
                }],
            [true, {
                    title_diff: '',
                    body_diff: '[]',
                    metadata_diff: '{"new":{},"deleted":[]}',
                }],
            [false, {
                    title_diff: '[{"diffs":[[1,"hello"]],"start1":0,"start2":0,"length1":0,"length2":5}]',
                    body_diff: '[]',
                    metadata_diff: '{"new":{},"deleted":[]}',
                }],
        ];
        for (const t of testCases) {
            const [expected, input] = t;
            // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
            expect(Revision_1.default.isEmptyRevision(input)).toBe(expected);
        }
    });
    it('should not fail to create revisions on naughty strings', (async () => {
        // Previously this pattern would fail:
        // - Create a patch between an empty string and smileys
        // - Use that patch on the empty string to get back the smileys
        // - Create a patch between those smileys and new smileys
        // https://github.com/JackuB/diff-match-patch/issues/22
        const nss = await (0, test_utils_1.naughtyStrings)();
        // First confirm that it indeed fails with the legacy approach.
        let errorCount = 0;
        for (let i = 0; i < nss.length - 1; i++) {
            const ns1 = nss[i];
            const ns2 = nss[i + 1];
            try {
                const patchText = Revision_1.default.createTextPatchLegacy('', ns1);
                const patchedText = Revision_1.default.applyTextPatchLegacy('', patchText);
                Revision_1.default.createTextPatchLegacy(patchedText, ns2);
            }
            catch (error) {
                errorCount++;
            }
        }
        expect(errorCount).toBe(10);
        // Now feed the naughty list again but using the new approach. In that
        // case it should work fine.
        await (0, test_utils_1.expectNotThrow)(async () => {
            for (let i = 0; i < nss.length - 1; i++) {
                const ns1 = nss[i];
                const ns2 = nss[i + 1];
                const patchText = Revision_1.default.createTextPatch('', ns1);
                const patchedText = Revision_1.default.applyTextPatch('', patchText);
                Revision_1.default.createTextPatch(patchedText, ns2);
            }
        });
    }));
    it('should successfully handle legacy patches', async () => {
        // The code should handle applying a series of new style patches and
        // legacy patches, and the correct text should be recovered at the end.
        const changes = [
            '',
            'one',
            'one three',
            'one two three',
        ];
        const patches = [
            Revision_1.default.createTextPatch(changes[0], changes[1]),
            Revision_1.default.createTextPatchLegacy(changes[1], changes[2]),
            Revision_1.default.createTextPatch(changes[2], changes[3]),
        ];
        // Sanity check - verify that the patches are as expected
        expect(patches[0].substr(0, 2)).toBe('[{'); // New
        expect(patches[1].substr(0, 2)).toBe('@@'); // Legacy
        expect(patches[2].substr(0, 2)).toBe('[{'); // New
        let finalString = Revision_1.default.applyTextPatch(changes[0], patches[0]);
        finalString = Revision_1.default.applyTextPatch(finalString, patches[1]);
        finalString = Revision_1.default.applyTextPatch(finalString, patches[2]);
        expect(finalString).toBe('one two three');
    });
    it('should create patches of objects and apply it', (async () => {
        const oldObject = {
            one: '123',
            two: '456',
            three: '789',
        };
        const newObject = {
            one: '123',
            three: '999',
        };
        const patch = Revision_1.default.createObjectPatch(oldObject, newObject);
        const merged = Revision_1.default.applyObjectPatch(oldObject, patch);
        expect(JSON.stringify(merged)).toBe(JSON.stringify(newObject));
    }));
    it('should handle invalid object patch', (async () => {
        const oldObject = {
            one: '123',
            two: '456',
            three: '789',
        };
        const brokenPatch = `{"new":{"four":"444
"},"deleted":["one"]}`;
        const expected = {
            two: '456',
            three: '789',
            four: '444',
        };
        const merged = Revision_1.default.applyObjectPatch(oldObject, brokenPatch);
        expect(JSON.stringify(merged)).toBe(JSON.stringify(expected));
    }));
    it('should not strip off newlines from object values', (async () => {
        const oldObject = {
            one: '123',
            two: '456',
            three: '789',
        };
        const patch = {
            'new': {
                'four': 'one line\ntwo line',
            },
            'deleted': [],
        };
        const expected = {
            one: '123',
            two: '456',
            three: '789',
            four: 'one line\ntwo line',
        };
        const merged = Revision_1.default.applyObjectPatch(oldObject, JSON.stringify(patch));
        expect(JSON.stringify(merged)).toBe(JSON.stringify(expected));
    }));
    it('should move target revision to the top', (async () => {
        const revs = [
            { id: '123' },
            { id: '456' },
            { id: '789' },
        ];
        let newRevs;
        newRevs = Revision_1.default.moveRevisionToTop({ id: '456' }, revs);
        expect(newRevs[0].id).toBe('123');
        expect(newRevs[1].id).toBe('789');
        expect(newRevs[2].id).toBe('456');
        newRevs = Revision_1.default.moveRevisionToTop({ id: '789' }, revs);
        expect(newRevs[0].id).toBe('123');
        expect(newRevs[1].id).toBe('456');
        expect(newRevs[2].id).toBe('789');
    }));
    // cSpell:disable
    it('should create patch stats', (async () => {
        const tests = [
            {
                patch: `@@ -625,16 +625,48 @@
 rrupted download
+%0A- %5B %5D Fix mobile screen options`,
                expected: [-0, +32],
            },
            {
                patch: `@@ -564,17 +564,17 @@
 ages%0A- %5B
- 
+x
 %5D Check `,
                expected: [-1, +1],
            },
            {
                patch: `@@ -1022,56 +1022,415 @@
 .%0A%0A#
- How to view a note history%0A%0AWhile all the apps 
+%C2%A0How does it work?%0A%0AAll the apps save a version of the modified notes every 10 minutes.
 %0A%0A# `,
                expected: [-(19 + 27 + 2), 17 + 67 + 4],
            },
            {
                patch: '',
                expected: [-0, +0],
            },
        ];
        for (const test of tests) {
            const stats = Revision_1.default.patchStats(test.patch);
            expect(stats.removed).toBe(-test.expected[0]);
            expect(stats.added).toBe(test.expected[1]);
        }
    }));
    // cSpell:enable
});
//# sourceMappingURL=Revision.test.js.map