"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const test_utils_1 = require("../testing/test-utils");
const Folder_1 = require("../models/Folder");
const Note_1 = require("../models/Note");
const Tag_1 = require("../models/Tag");
describe('models/Tag', () => {
    beforeEach(async () => {
        await (0, test_utils_1.setupDatabaseAndSynchronizer)(1);
        await (0, test_utils_1.switchClient)(1);
    });
    it('should add tags by title', async () => {
        const folder1 = await Folder_1.default.save({ title: 'folder1' });
        const note1 = await Note_1.default.save({ title: 'ma note', parent_id: folder1.id });
        await Tag_1.default.setNoteTagsByTitles(note1.id, ['un', 'deux']);
        const noteTags = await Tag_1.default.tagsByNoteId(note1.id);
        expect(noteTags.length).toBe(2);
    });
    it('should get the notes associated with a tag', async () => {
        const note1 = await Note_1.default.save({});
        const note2 = await Note_1.default.save({});
        const note3 = await Note_1.default.save({});
        await Tag_1.default.setNoteTagsByTitles(note1.id, ['un']);
        await Tag_1.default.setNoteTagsByTitles(note2.id, ['un']);
        await Tag_1.default.setNoteTagsByTitles(note3.id, ['deux']);
        await Tag_1.default.save({ title: 'trois' });
        const tag1 = await Tag_1.default.loadByTitle('un');
        const tag2 = await Tag_1.default.loadByTitle('deux');
        const tag3 = await Tag_1.default.loadByTitle('trois');
        expect((await Tag_1.default.noteIds(tag1.id)).sort()).toEqual([note1.id, note2.id].sort());
        expect((await Tag_1.default.noteIds(tag2.id)).sort()).toEqual([note3.id].sort());
        expect((await Tag_1.default.noteIds(tag3.id)).sort()).toEqual([].sort());
        expect(await Tag_1.default.hasNote(tag1.id, note1.id)).toBe(true);
        expect(await Tag_1.default.hasNote(tag1.id, note2.id)).toBe(true);
        expect(await Tag_1.default.hasNote(tag1.id, note3.id)).toBe(false);
        expect(await Tag_1.default.hasNote(tag2.id, note1.id)).toBe(false);
        expect(await Tag_1.default.hasNote(tag2.id, note2.id)).toBe(false);
        expect(await Tag_1.default.hasNote(tag2.id, note3.id)).toBe(true);
        expect(await Tag_1.default.hasNote(tag3.id, note1.id)).toBe(false);
        expect(await Tag_1.default.hasNote(tag3.id, note2.id)).toBe(false);
        expect(await Tag_1.default.hasNote(tag3.id, note3.id)).toBe(false);
        const notesTag1 = await Tag_1.default.notes(tag1.id);
        const notesTag2 = await Tag_1.default.notes(tag2.id);
        const notesTag3 = await Tag_1.default.notes(tag3.id);
        expect(notesTag1.map(n => n.id).sort()).toEqual([note1.id, note2.id].sort());
        expect(notesTag2.map(n => n.id).sort()).toEqual([note3.id].sort());
        expect(notesTag3.map(n => n.id).sort()).toEqual([].sort());
    });
    it('should not retrieve deleted notes', async () => {
        const note1 = await Note_1.default.save({});
        const note2 = await Note_1.default.save({});
        await Tag_1.default.setNoteTagsByTitles(note1.id, ['un']);
        await Tag_1.default.setNoteTagsByTitles(note2.id, ['un']);
        const tag1 = await Tag_1.default.loadByTitle('un');
        await Note_1.default.delete(note1.id, { toTrash: true });
        expect(await Tag_1.default.noteIds(tag1.id)).toEqual([note2.id]);
        expect((await Tag_1.default.notes(tag1.id)).map(n => n.id).sort()).toEqual([note2.id]);
        expect(await Tag_1.default.hasNote(tag1.id, note1.id)).toBe(false);
        expect(await Tag_1.default.hasNote(tag1.id, note2.id)).toBe(true);
        const allWithNotes = await Tag_1.default.allWithNotes();
        expect(allWithNotes[0].note_count).toBe(1);
    });
    it('should not allow renaming tag to existing tag names', async () => {
        const folder1 = await Folder_1.default.save({ title: 'folder1' });
        const note1 = await Note_1.default.save({ title: 'ma note', parent_id: folder1.id });
        await Tag_1.default.setNoteTagsByTitles(note1.id, ['un', 'deux']);
        const tagUn = await Tag_1.default.loadByTitle('un');
        const hasThrown = await (0, test_utils_1.checkThrowAsync)(async () => await Tag_1.default.save({ id: tagUn.id, title: 'deux' }, { userSideValidation: true }));
        expect(hasThrown).toBe(true);
    });
    it('should not return tags without notes', async () => {
        const folder1 = await Folder_1.default.save({ title: 'folder1' });
        const note1 = await Note_1.default.save({ title: 'ma note', parent_id: folder1.id });
        await Tag_1.default.setNoteTagsByTitles(note1.id, ['un']);
        let tags = await Tag_1.default.allWithNotes();
        expect(tags.length).toBe(1);
        await Note_1.default.delete(note1.id);
        tags = await Tag_1.default.allWithNotes();
        expect(tags.length).toBe(0);
    });
    it('should return tags with note counts', async () => {
        const folder1 = await Folder_1.default.save({ title: 'folder1' });
        const note1 = await Note_1.default.save({ title: 'ma note', parent_id: folder1.id });
        const note2 = await Note_1.default.save({ title: 'ma 2nd note', parent_id: folder1.id });
        const todo1 = await Note_1.default.save({ title: 'todo 1', parent_id: folder1.id, is_todo: 1, todo_completed: 1590085027710 });
        await Tag_1.default.setNoteTagsByTitles(note1.id, ['un']);
        await Tag_1.default.setNoteTagsByTitles(note2.id, ['un']);
        await Tag_1.default.setNoteTagsByTitles(todo1.id, ['un']);
        let tags = await Tag_1.default.allWithNotes();
        expect(tags.length).toBe(1);
        expect(tags[0].note_count).toBe(3);
        expect(tags[0].todo_completed_count).toBe(1);
        await Note_1.default.delete(todo1.id);
        tags = await Tag_1.default.allWithNotes();
        expect(tags.length).toBe(1);
        expect(tags[0].note_count).toBe(2);
        await Note_1.default.delete(note1.id);
        tags = await Tag_1.default.allWithNotes();
        expect(tags.length).toBe(1);
        expect(tags[0].note_count).toBe(1);
        await Note_1.default.delete(note2.id);
        tags = await Tag_1.default.allWithNotes();
        expect(tags.length).toBe(0);
    });
    it('should load individual tags with note count', async () => {
        const folder1 = await Folder_1.default.save({ title: 'folder1' });
        const note1 = await Note_1.default.save({ title: 'ma note', parent_id: folder1.id });
        const note2 = await Note_1.default.save({ title: 'ma 2nd note', parent_id: folder1.id });
        const todo1 = await Note_1.default.save({ title: 'todo 2', parent_id: folder1.id, is_todo: 1, todo_completed: 1590085027710 });
        const todo2 = await Note_1.default.save({ title: 'todo 2', parent_id: folder1.id, is_todo: 1 });
        const tag = await Tag_1.default.save({ title: 'mytag' });
        await Tag_1.default.addNote(tag.id, note1.id);
        let tagWithCount = await Tag_1.default.loadWithCount(tag.id);
        expect(tagWithCount.note_count).toBe(1);
        await Tag_1.default.addNote(tag.id, note2.id);
        tagWithCount = await Tag_1.default.loadWithCount(tag.id);
        expect(tagWithCount.note_count).toBe(2);
        await Tag_1.default.addNote(tag.id, todo1.id);
        await Tag_1.default.addNote(tag.id, todo2.id);
        tagWithCount = await Tag_1.default.loadWithCount(tag.id);
        expect(tagWithCount.note_count).toBe(4);
        expect(tagWithCount.todo_completed_count).toBe(1);
    });
    it('should get common tags for set of notes', async () => {
        const folder1 = await Folder_1.default.save({ title: 'folder1' });
        const taga = await Tag_1.default.save({ title: 'mytaga' });
        const tagb = await Tag_1.default.save({ title: 'mytagb' });
        const tagc = await Tag_1.default.save({ title: 'mytagc' });
        await Tag_1.default.save({ title: 'mytagd' });
        const note0 = await Note_1.default.save({ title: 'ma note 0', parent_id: folder1.id });
        const note1 = await Note_1.default.save({ title: 'ma note 1', parent_id: folder1.id });
        const note2 = await Note_1.default.save({ title: 'ma note 2', parent_id: folder1.id });
        const note3 = await Note_1.default.save({ title: 'ma note 3', parent_id: folder1.id });
        await Tag_1.default.addNote(taga.id, note1.id);
        await Tag_1.default.addNote(taga.id, note2.id);
        await Tag_1.default.addNote(tagb.id, note2.id);
        await Tag_1.default.addNote(taga.id, note3.id);
        await Tag_1.default.addNote(tagb.id, note3.id);
        await Tag_1.default.addNote(tagc.id, note3.id);
        let commonTags = await Tag_1.default.commonTagsByNoteIds(null);
        expect(commonTags.length).toBe(0);
        commonTags = await Tag_1.default.commonTagsByNoteIds(undefined);
        expect(commonTags.length).toBe(0);
        commonTags = await Tag_1.default.commonTagsByNoteIds([]);
        expect(commonTags.length).toBe(0);
        commonTags = await Tag_1.default.commonTagsByNoteIds([note0.id, note1.id, note2.id, note3.id]);
        let commonTagIds = commonTags.map(t => t.id);
        expect(commonTagIds.length).toBe(0);
        commonTags = await Tag_1.default.commonTagsByNoteIds([note1.id, note2.id, note3.id]);
        commonTagIds = commonTags.map(t => t.id);
        expect(commonTagIds.length).toBe(1);
        expect(commonTagIds.includes(taga.id)).toBe(true);
        commonTags = await Tag_1.default.commonTagsByNoteIds([note2.id, note3.id]);
        commonTagIds = commonTags.map(t => t.id);
        expect(commonTagIds.length).toBe(2);
        expect(commonTagIds.includes(taga.id)).toBe(true);
        expect(commonTagIds.includes(tagb.id)).toBe(true);
        commonTags = await Tag_1.default.commonTagsByNoteIds([note3.id]);
        commonTagIds = commonTags.map(t => t.id);
        expect(commonTags.length).toBe(3);
        expect(commonTagIds.includes(taga.id)).toBe(true);
        expect(commonTagIds.includes(tagb.id)).toBe(true);
        expect(commonTagIds.includes(tagc.id)).toBe(true);
    });
    it('should allow finding tags when case does not match, for standard ASCII characters', async () => {
        const note1 = await Note_1.default.save({});
        await Tag_1.default.setNoteTagsByTitles(note1.id, ['Hello']);
        const tag1 = await Tag_1.default.loadByTitle('Hello');
        const tag2 = await Tag_1.default.loadByTitle('hello');
        expect(tag1).toStrictEqual(tag2);
    });
    it('should not create duplicate tags when tagging with existing titles (issue #14540)', async () => {
        const folder1 = await Folder_1.default.save({ title: 'folder1' });
        const note1 = await Note_1.default.save({ title: 'ma note', parent_id: folder1.id });
        // Test 1: Simple existing tag
        const tag1 = await Tag_1.default.save({ title: 'meetings' });
        await Tag_1.default.setNoteTagsByTitles(note1.id, ['meetings']);
        let allTags = await Tag_1.default.all();
        expect(allTags.length).toBe(1);
        expect(allTags[0].id).toBe(tag1.id);
        // Test 2: Whitespace issues
        await Tag_1.default.setNoteTagsByTitles(note1.id, ['meetings ']);
        allTags = await Tag_1.default.all();
        expect(allTags.length).toBe(1);
        // Test 3: Normalization issues
        const composed = '\u00E9';
        const decomposed = '\u0065\u0301';
        await Tag_1.default.save({ title: composed });
        await Tag_1.default.setNoteTagsByTitles(note1.id, [decomposed]);
        allTags = await Tag_1.default.all();
        // In addition to 'meetings', we should have only one 'é' tag
        expect(allTags.length).toBe(2);
        // Test 4: Case change should not create new tag but match existing
        await Tag_1.default.setNoteTagsByTitles(note1.id, ['MEETINGS']);
        allTags = await Tag_1.default.all();
        expect(allTags.length).toBe(2);
    });
    it('should prefer an exact legacy tag match before the normalized fallback', async () => {
        const decomposed = '\u0065\u0301';
        const composed = '\u00E9';
        const legacyTagId = Tag_1.default.generateUuid();
        const normalizedTag = await Tag_1.default.save({ title: composed });
        await Tag_1.default.db().exec('INSERT INTO tags (id, title, created_time, updated_time) VALUES (?, ?, ?, ?)', [legacyTagId, decomposed, 1, 1]);
        const loadedTag = await Tag_1.default.loadByTitle(decomposed);
        expect(loadedTag.id).toBe(legacyTagId);
        expect(loadedTag.id).not.toBe(normalizedTag.id);
    });
    it.each([
        // cSpell:disable
        'Посмотреть 1',
        'Öp',
        // cSpell:enable
    ])('should find match for tags which have been saved, when they contain special unicode characters', async (title) => {
        await Tag_1.default.save({ title });
        const loadedTag = await Tag_1.default.loadByTitle(title);
        expect(loadedTag.id).not.toBeNull();
    });
});
//# sourceMappingURL=Tag.test.js.map