"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const shim_1 = require("./shim");
const promises_1 = require("fs/promises");
const os = require('os');
const { filename } = require('./path-utils');
const test_utils_1 = require("./testing/test-utils");
const { enexXmlToMd } = require('./import-enex-md-gen.js');
const import_enex_1 = require("./import-enex");
const Note_1 = require("./models/Note");
const Tag_1 = require("./models/Tag");
const Resource_1 = require("./models/Resource");
const enexSampleBaseDir = `${test_utils_1.supportDir}/../enex_to_md`;
const importEnexFile = async (filename, options = null) => {
    const filePath = `${enexSampleBaseDir}/${filename}`;
    await (0, import_enex_1.default)('', filePath, options);
};
const readExpectedFile = async (filename) => {
    const filePath = `${enexSampleBaseDir}/${filename}`;
    return (0, promises_1.readFile)(filePath, 'utf8');
};
describe('import-enex-md-gen', () => {
    beforeEach(async () => {
        await (0, test_utils_1.setupDatabaseAndSynchronizer)(1);
        await (0, test_utils_1.switchClient)(1);
    });
    it('should convert ENEX content to Markdown', async () => {
        const files = await shim_1.default.fsDriver().readDirStats(enexSampleBaseDir);
        for (let i = 0; i < files.length; i++) {
            const htmlFilename = files[i].path;
            if (htmlFilename.indexOf('.html') < 0)
                continue;
            const htmlPath = `${enexSampleBaseDir}/${htmlFilename}`;
            const mdPath = `${enexSampleBaseDir}/${filename(htmlFilename)}.md`;
            // if (htmlFilename !== 'highlight.html') continue;
            const html = await shim_1.default.fsDriver().readFile(htmlPath);
            let expectedMd = await shim_1.default.fsDriver().readFile(mdPath);
            let actualMd = await enexXmlToMd(`<div>${html}</div>`, []);
            if (os.EOL === '\r\n') {
                expectedMd = expectedMd.replace(/\r\n/g, '\n');
                actualMd = actualMd.replace(/\r\n/g, '\n');
            }
            if (actualMd !== expectedMd) {
                const result = [];
                result.push('');
                result.push(`Error converting file: ${htmlFilename}`);
                result.push('--------------------------------- Got:');
                result.push(actualMd.split('\n').map((l) => `"${l}"`).join('\n'));
                result.push('--------------------------------- Expected:');
                result.push(expectedMd.split('\n').map((l) => `"${l}"`).join('\n'));
                result.push('--------------------------------------------');
                result.push('');
                // eslint-disable-next-line no-console
                console.info(result.join('\n'));
                expect(false).toBe(true);
                // return;
            }
            else {
                expect(true).toBe(true);
            }
        }
    });
    it('should import ENEX metadata', async () => {
        await importEnexFile('sample-enex.xml');
        const note = (await Note_1.default.all())[0];
        expect(note.title).toBe('Test Note for Export');
        expect(note.body).toBe([
            '    Hello, World.',
            '',
            '![snapshot-DAE9FC15-88E3-46CF-B744-DA9B1B56EB57.jpg](:/3d0f4d01abc02cf8c4dc1c796df8c4b2)',
        ].join('\n'));
        expect(note.created_time).toBe(1375217524000);
        expect(note.updated_time).toBe(1376560800000);
        expect(note.latitude).toBe('33.88394692');
        expect(note.longitude).toBe('-117.91913551');
        expect(note.altitude).toBe('96.0000');
        expect(note.author).toBe('Brett Kelly');
        const tag = (await Tag_1.default.tagsByNoteId(note.id))[0];
        expect(tag.title).toBe('fake-tag');
        const resource = (await Resource_1.default.all())[0];
        expect(resource.id).toBe('3d0f4d01abc02cf8c4dc1c796df8c4b2');
        const s = await (0, promises_1.stat)(Resource_1.default.fullPath(resource));
        expect(s.size).toBe(277);
    });
    it('should handle invalid dates', async () => {
        await importEnexFile('invalid_date.enex');
        const note = (await Note_1.default.all())[0];
        expect(note.created_time).toBe(1521822724000); // 20180323T163204Z
        expect(note.updated_time).toBe(1521822724000); // Because this date was invalid, it is set to the created time instead
    });
    it('should handle empty resources', async () => {
        await (0, test_utils_1.expectNotThrow)(() => importEnexFile('empty_resource.enex'));
        const all = await Resource_1.default.all();
        expect(all.length).toBe(1);
        expect(all[0].size).toBe(0);
    });
    it('should handle tasks', async () => {
        await importEnexFile('tasks.enex');
        const expectedMd = await shim_1.default.fsDriver().readFile(`${enexSampleBaseDir}/tasks.md`);
        const note = (await Note_1.default.all())[0];
        expect(note.body).toEqual(expectedMd);
    });
    it('should handle empty note content', async () => {
        await importEnexFile('empty_content.enex');
        const all = await Note_1.default.all();
        expect(all.length).toBe(1);
        expect(all[0].title).toBe('China and the case for stimulus.');
        expect(all[0].body).toBe('');
    });
    it('should handle invalid mime types', async () => {
        // This is to handle the case where a resource has an invalid mime type,
        // but that type can be determined from the filename. For example, in
        // this thread, the ENEX file contains a "file.zip" file with a mime
        // type "application/octet-stream", which can later cause problems to
        // open the file.
        // https://discourse.joplinapp.org/t/importing-a-note-with-a-zip-file/12123?u=laurent
        await importEnexFile('WithInvalidMime.enex');
        const all = await Resource_1.default.all();
        expect(all.length).toBe(1);
        expect(all[0].mime).toBe('application/zip');
    });
    // Disabled for now because the ENEX parser has become so error-tolerant
    // that it's no longer possible to generate a note that would generate a
    // failure.
    // it('should keep importing notes when one of them is corrupted', async () => {
    // 	const filePath = `${enexSampleBaseDir}/ImportTestCorrupt.enex`;
    // 	const errors: any[] = [];
    // 	const consoleSpy = jest.spyOn(console, 'warn').mockImplementation(jest.fn());
    // 	await importEnex('', filePath, {
    // 		onError: (error: any) => errors.push(error),
    // 	});
    // 	consoleSpy.mockRestore();
    // 	const notes:NoteEntity[] = await Note.all();
    // 	expect(notes.length).toBe(2);
    // 	expect(notes.find(n => n.title === 'Note 1')).toBeTruthy();
    // 	expect(notes.find(n => n.title === 'Note 3')).toBeTruthy();
    // 	// Check that an error was recorded and that it includes the title
    // 	// of the note, so that it can be found back by the user
    // 	expect(errors.length).toBe(1);
    // 	expect(errors[0].message.includes('Note 2')).toBe(true);
    // });
    it('should throw an error and stop if the outer XML is invalid', async () => {
        await (0, test_utils_1.expectThrow)(async () => importEnexFile('invalid_html.enex'));
    });
    it('should import images with sizes', async () => {
        await importEnexFile('images_with_and_without_size.enex');
        let expected = await readExpectedFile('images_with_and_without_size.md');
        const note = (await Note_1.default.all())[0];
        const all = await Resource_1.default.all();
        expect(all.length).toBe(2);
        const svgResource = all.find(r => r.mime === 'image/svg+xml');
        const pngResource = all.find(r => r.mime === 'image/png');
        expected = expected.replace(/RESOURCE_ID_1/, pngResource.id);
        expected = expected.replace(/RESOURCE_ID_2/, svgResource.id);
        expect(note.body).toBe(expected);
        const filePath = `${enexSampleBaseDir}/invalid_html.enex`;
        await (0, test_utils_1.expectThrow)(async () => (0, import_enex_1.default)('', filePath));
    });
    it('should set resource extension correctly', async () => {
        // Handle case where the resource has a certain extension, eg. "mscz"
        // and a mime type that doesn't really match (application/zip). In that
        // case we want to make sure that the file is not converted to a .zip
        // file. Fixes https://discourse.joplinapp.org/t/import-issue-evernote-enex-containing-musescore-file-mscz/31394/1
        await importEnexFile('invalid_resource_mime_type.enex');
        const resource = (await Resource_1.default.all())[0];
        expect(resource.file_extension).toBe('mscz');
        expect(resource.mime).toBe('application/zip');
        expect(Resource_1.default.fullPath(resource).endsWith('.mscz')).toBe(true);
    });
    it('should handle resources without encoding', async () => {
        // Handle case where the resource has a certain extension, eg. "mscz"
        // and a mime type that doesn't really match (application/zip). In that
        // case we want to make sure that the file is not converted to a .zip
        // file. Fixes https://discourse.joplinapp.org/t/import-issue-evernote-enex-containing-musescore-file-mscz/31394/1
        await importEnexFile('resource_with_missing_encoding.enex');
        const resource = (await Resource_1.default.all())[0];
        const resourcePath = Resource_1.default.fullPath(resource);
        const content = await (0, promises_1.readFile)(resourcePath, 'utf-8');
        expect(content).toBe('{ "test": 123 }');
    });
    it('should sanitize resource filenames with slashes', async () => {
        await importEnexFile('resource_filename_with_slashes.enex');
        const resource = (await Resource_1.default.all())[0];
        expect(resource.filename).toBe('house_500.jpg.png');
        expect(resource.file_extension).toBe('png');
        // However we keep the title as it is
        expect(resource.title).toBe('app_images/resizable/961b875f-24ac-402f-9b76-37e2d4f03a6c/house_500.jpg.png');
    });
    it('should sanitize resource filenames with colons', async () => {
        await importEnexFile('resource_filename_with_colons.enex');
        const resource = (await Resource_1.default.all())[0];
        expect(resource.filename).toBe('08.06.2014165855');
        expect(resource.file_extension).toBe('2014165855');
        expect(resource.title).toBe('08.06.2014 16:58:55');
    });
    it('should resolve note links', async () => {
        await importEnexFile('linked_notes.enex', { batchSize: 1 });
        const notes = await Note_1.default.all();
        const note1 = notes.find(n => n.title === 'Note 1');
        const note2 = notes.find(n => n.title === 'Note 2');
        const note3 = notes.find(n => n.title === 'Note 3');
        const note4 = notes.find(n => n.title === 'Note 4');
        expect(notes.length).toBe(7);
        expect(note1.body).toBe(`[Note 2](:/${note2.id})[Note 3](:/${note3.id})`);
        expect(note3.body).toBe('[Ambiguous note](evernote:///view/5223870/s49/9cd5e810-fa03-429a-8194-ab847f2f1ab2/c99d9e01-ca35-4c75-ba63-f0c0ef97787d/)');
        expect(note4.body).toBe('[Note 5](https://joplinapp.org)');
    });
    it('should remove empty hidden divs from imported notes', async () => {
        const empty = await enexXmlToMd('<div style="display:none;--en-chs:&quot;metadata&quot;"> </div><div>Test content</div>', [], []);
        const withContent = await enexXmlToMd('<div style="display:none;">Important data</div><div>Visible text</div>', [], []);
        expect(empty).not.toContain('<div style="display: none;">');
        expect(empty).toContain('Test content');
        expect(withContent).toContain('<div style="display: none;">');
        expect(withContent).toContain('Important data');
    });
});
//# sourceMappingURL=import-enex-md-gen.test.js.map