From c7fb6fd52eec295914452747f778dfc4fde8d64b Mon Sep 17 00:00:00 2001 From: Cadence Ember Date: Fri, 2 Feb 2024 15:55:02 +1300 Subject: [PATCH] Improve test coverage --- d2m/converters/message-to-event.js | 9 ++ d2m/converters/message-to-event.pk.test.js | 64 +++++++++++ d2m/converters/message-to-event.test.js | 40 +++++++ db/migrate.js | 1 - m2d/converters/emoji-sheet.test.js | 1 + m2d/converters/event-to-message.js | 90 +++++++++++---- m2d/converters/event-to-message.test.js | 54 ++++++++- test/data.js | 124 +++++++++++++++++++++ test/ooye-test-data.sql | 17 ++- test/test.js | 7 ++ 10 files changed, 374 insertions(+), 33 deletions(-) create mode 100644 d2m/converters/message-to-event.pk.test.js diff --git a/d2m/converters/message-to-event.js b/d2m/converters/message-to-event.js index 411404c..814fda2 100644 --- a/d2m/converters/message-to-event.js +++ b/d2m/converters/message-to-event.js @@ -257,6 +257,15 @@ async function messageToEvent(message, guild, options = {}, di) { if (match) { const row = from("event_message").join("message_channel", "message_id").join("channel_room", "channel_id").select("event_id", "room_id", "source").and("WHERE message_id = ? AND part = 0").get(match[1]) if (row) { + /* + we generate a partial referenced_message based on what PK provided. we don't need everything, since this will only be used for further message-to-event converting. + the following properties are necessary: + - content: used for generating the reply fallback + */ + // @ts-ignore + message.referenced_message = { + content: message.embeds[0].description.replace(/^.*?\)\*\*\s*/, "") + } message.embeds.shift() repliedToEventRow = row } diff --git a/d2m/converters/message-to-event.pk.test.js b/d2m/converters/message-to-event.pk.test.js new file mode 100644 index 0000000..48984e4 --- /dev/null +++ b/d2m/converters/message-to-event.pk.test.js @@ -0,0 +1,64 @@ +const {test} = require("supertape") +const {messageToEvent} = require("./message-to-event") +const data = require("../../test/data") +const Ty = require("../../types") + +/** + * @param {string} roomID + * @param {string} eventID + * @returns {(roomID: string, eventID: string) => Promise>} + */ +function mockGetEvent(t, roomID_in, eventID_in, outer) { + return async function(roomID, eventID) { + t.equal(roomID, roomID_in) + t.equal(eventID, eventID_in) + return new Promise(resolve => { + setTimeout(() => { + resolve({ + event_id: eventID_in, + room_id: roomID_in, + origin_server_ts: 1680000000000, + unsigned: { + age: 2245, + transaction_id: "$local.whatever" + }, + ...outer + }) + }) + }) + } +} + +test("message2event: pk reply is converted to native matrix reply", async t => { + const events = await messageToEvent(data.pk_message.pk_reply, {}, {}, { + api: { + getEvent: mockGetEvent(t, "!TqlyQmifxGUggEmdBN:cadence.moe", "$NB6nPgO2tfXyIwwDSF0Ga0BUrsgX1S-0Xl-jAvI8ucU", { + type: "m.room.message", + sender: "@cadence:cadence.moe", + content: { + msgtype: "m.text", + body: "now for my next experiment:" + } + }) + } + }) + t.deepEqual(events, [{ + $type: "m.room.message", + "m.mentions": { + user_ids: [ + "@cadence:cadence.moe" + ] + }, + msgtype: "m.text", + body: "> cadence: now for my next experiment:\n\nthis is a reply", + format: "org.matrix.custom.html", + formatted_body: '
In reply to cadence
' + + "now for my next experiment:
" + + "this is a reply", + "m.relates_to": { + "m.in_reply_to": { + event_id: "$NB6nPgO2tfXyIwwDSF0Ga0BUrsgX1S-0Xl-jAvI8ucU" + } + } + }]) +}) diff --git a/d2m/converters/message-to-event.test.js b/d2m/converters/message-to-event.test.js index 6b4695d..9f4e4d4 100644 --- a/d2m/converters/message-to-event.test.js +++ b/d2m/converters/message-to-event.test.js @@ -397,6 +397,46 @@ test("message2event: reply with a video", async t => { }]) }) +test("message2event: voice message", async t => { + const events = await messageToEvent(data.message.voice_message) + t.deepEqual(events, [{ + $type: "m.room.message", + body: "voice-message.ogg", + external_url: "https://cdn.discordapp.com/attachments/1099031887500034088/1112476845502365786/voice-message.ogg?ex=65c92d4c&is=65b6b84c&hm=0654bab5027474cbe23875954fa117cf44d8914c144cd151879590fa1baf8b1c&", + filename: "voice-message.ogg", + info: { + duration: 3960.0000381469727, + mimetype: "audio/ogg", + size: 10584, + }, + "m.mentions": {}, + msgtype: "m.audio", + url: "mxc://cadence.moe/MRRPDggXQMYkrUjTpxQbmcxB" + }]) +}) + +test("message2event: misc file", async t => { + const events = await messageToEvent(data.message.misc_file) + t.deepEqual(events, [{ + $type: "m.room.message", + msgtype: "m.text", + body: "final final final revised draft", + "m.mentions": {} + }, { + $type: "m.room.message", + body: "the.yml", + external_url: "https://cdn.discordapp.com/attachments/122155380120748034/1174514575220158545/the.yml?ex=65cd6270&is=65baed70&hm=8c5f1b571784e3c7f99628492298815884e351ae0dc7c2ae40dd22d97caf27d9&", + filename: "the.yml", + info: { + mimetype: "text/plain; charset=utf-8", + size: 2274 + }, + "m.mentions": {}, + msgtype: "m.file", + url: "mxc://cadence.moe/HnQIYQmmlIKwOQsbFsIGpzPP" + }]) +}) + test("message2event: simple reply in thread to a matrix user's reply", async t => { const events = await messageToEvent(data.message.simple_reply_to_reply_in_thread, data.guild.general, {}, { api: { diff --git a/db/migrate.js b/db/migrate.js index 57b5cbf..7c1faf9 100644 --- a/db/migrate.js +++ b/db/migrate.js @@ -16,7 +16,6 @@ async function migrate(db) { let migrationRan = false for (const filename of files) { - /* c8 ignore next - we can't unit test this, but it's run on every real world bridge startup */ if (progress >= filename) continue console.log(`Applying database migration ${filename}`) if (filename.endsWith(".sql")) { diff --git a/m2d/converters/emoji-sheet.test.js b/m2d/converters/emoji-sheet.test.js index f75fafc..de3a2ab 100644 --- a/m2d/converters/emoji-sheet.test.js +++ b/m2d/converters/emoji-sheet.test.js @@ -39,6 +39,7 @@ async function runSingleTest(t, url, totalSize) { res.body.emit("end") }) t.equal(result.subarray(1, 4).toString("ascii"), "PNG", `result was not a PNG file: ${result.toString("base64")}`) + /* c8 ignore next 5 */ if (meter.bytes < totalSize / 4) { // should download less than 25% of each file t.pass("intentionally read partial file") } else { diff --git a/m2d/converters/event-to-message.js b/m2d/converters/event-to-message.js index e48b5f3..2dcb2e8 100644 --- a/m2d/converters/event-to-message.js +++ b/m2d/converters/event-to-message.js @@ -5,6 +5,7 @@ const DiscordTypes = require("discord-api-types/v10") const {Readable} = require("stream") const chunk = require("chunk-text") const TurndownService = require("turndown") +const domino = require("domino") const assert = require("assert").strict const entities = require("entities") @@ -38,7 +39,7 @@ const turndownService = new TurndownService({ hr: "----", headingStyle: "atx", preformattedCode: true, - codeBlockStyle: "fenced", + codeBlockStyle: "fenced" }) /** @@ -339,6 +340,33 @@ async function handleRoomOrMessageLinks(input, di) { return input } +/** + * @param {string} content + * @param {DiscordTypes.APIGuild} guild + * @param {{api: import("../../matrix/api"), snow: import("snowtransfer").SnowTransfer, fetch: import("node-fetch")["default"]}} di + */ +async function checkWrittenMentions(content, guild, di) { + let writtenMentionMatch = content.match(/(?:^|[^"[<>/A-Za-z0-9])@([A-Za-z][A-Za-z0-9._\[\]\(\)-]+):?/d) // /d flag for indices requires node.js 16+ + if (writtenMentionMatch) { + const results = await di.snow.guild.searchGuildMembers(guild.id, {query: writtenMentionMatch[1]}) + if (results[0]) { + assert(results[0].user) + return { + // @ts-ignore - typescript doesn't know about indices yet + content: content.slice(0, writtenMentionMatch.indices[1][0]-1) + `<@${results[0].user.id}>` + content.slice(writtenMentionMatch.indices[1][1]), + ensureJoined: results[0].user + } + } + } +} + +const attachmentEmojis = new Map([ + ["m.image", "🖼️"], + ["m.video", "🎞️"], + ["m.audio", "🎶"], + ["m.file", "📄"] +]) + /** * @param {Ty.Event.Outer_M_Room_Message | Ty.Event.Outer_M_Room_Message_File | Ty.Event.Outer_M_Sticker | Ty.Event.Outer_M_Room_Message_Encrypted_File} event * @param {import("discord-api-types/v10").APIGuild} guild @@ -380,12 +408,10 @@ async function eventToMessage(event, guild, di) { // Handling edits. If the edit was an edit of a reply, edits do not include the reply reference, so we need to fetch up to 2 more events. // this event ---is an edit of--> original event ---is a reply to--> past event await (async () => { - if (!event.content["m.new_content"]) return + // Check if there is an edit const relatesTo = event.content["m.relates_to"] - if (!relatesTo) return + if (!event.content["m.new_content"] || !relatesTo || relatesTo.rel_type !== "m.replace") return // Check if we have a pointer to what was edited - const relType = relatesTo.rel_type - if (relType !== "m.replace") return const originalEventId = relatesTo.event_id if (!originalEventId) return messageIDsToEdit = select("event_message", "message_id", {event_id: originalEventId}, "ORDER BY part").pluck().all() @@ -480,12 +506,7 @@ async function eventToMessage(event, guild, di) { repliedToEvent.content = repliedToEvent.content["m.new_content"] } let contentPreview - const fileReplyContentAlternative = - ( repliedToEvent.content.msgtype === "m.image" ? "🖼️" - : repliedToEvent.content.msgtype === "m.video" ? "🎞️" - : repliedToEvent.content.msgtype === "m.audio" ? "🎶" - : repliedToEvent.content.msgtype === "m.file" ? "📄" - : null) + const fileReplyContentAlternative = attachmentEmojis.get(repliedToEvent.content.msgtype) if (fileReplyContentAlternative) { contentPreview = " " + fileReplyContentAlternative } else { @@ -574,8 +595,35 @@ async function eventToMessage(event, guild, di) { last = match.index } + // Handling written @mentions: we need to look for candidate Discord members to join to the room + // This shouldn't apply to code blocks, links, or inside attributes. So editing the HTML tree instead of regular expressions is a sensible choice here. + // We're using the domino parser because Turndown uses the same and can reuse this tree. + const doc = domino.createDocument( + // DOM parsers arrange elements in the and . Wrapping in a custom element ensures elements are reliably arranged in a single element. + '' + input + '' + ); + const root = doc.getElementById("turndown-root"); + async function forEachNode(node) { + for (; node; node = node.nextSibling) { + if (node.nodeType === 3 && node.nodeValue.includes("@")) { + const result = await checkWrittenMentions(node.nodeValue, guild, di) + if (result) { + node.nodeValue = result.content + ensureJoined.push(result.ensureJoined) + } + } + if (node.nodeType === 1 && ["CODE", "PRE", "A"].includes(node.tagName)) { + // don't recurse into code or links + } else { + // do recurse into everything else + await forEachNode(node.firstChild) + } + } + } + await forEachNode(root) + // @ts-ignore bad type from turndown - content = turndownService.turndown(input) + content = turndownService.turndown(root) // It's designed for commonmark, we need to replace the space-space-newline with just newline content = content.replace(/ \n/g, "\n") @@ -592,6 +640,12 @@ async function eventToMessage(event, guild, di) { content = await handleRoomOrMessageLinks(content, di) + const result = await checkWrittenMentions(content, guild, di) + if (result) { + content = result.content + ensureJoined.push(result.ensureJoined) + } + // Markdown needs to be escaped, though take care not to escape the middle of links // @ts-ignore bad type from turndown content = turndownService.escape(content) @@ -640,18 +694,6 @@ async function eventToMessage(event, guild, di) { content = displayNameRunoff + replyLine + content - // Handling written @mentions: we need to look for candidate Discord members to join to the room - let writtenMentionMatch = content.match(/(?:^|[^"[<>/A-Za-z0-9])@([A-Za-z][A-Za-z0-9._\[\]\(\)-]+):?/d) // /d flag for indices requires node.js 16+ - if (writtenMentionMatch) { - const results = await di.snow.guild.searchGuildMembers(guild.id, {query: writtenMentionMatch[1]}) - if (results[0]) { - assert(results[0].user) - // @ts-ignore - typescript doesn't know about indices yet - content = content.slice(0, writtenMentionMatch.indices[1][0]-1) + `<@${results[0].user.id}>` + content.slice(writtenMentionMatch.indices[1][1]) - ensureJoined.push(results[0].user) - } - } - // Split into 2000 character chunks const chunks = chunk(content, 2000) messages = messages.concat(chunks.map(content => ({ diff --git a/m2d/converters/event-to-message.test.js b/m2d/converters/event-to-message.test.js index 378e9f0..65893fe 100644 --- a/m2d/converters/event-to-message.test.js +++ b/m2d/converters/event-to-message.test.js @@ -1924,7 +1924,7 @@ test("event2message: mentioning PK discord users works", async t => { messagesToEdit: [], messagesToSend: [{ username: "cadence [they]", - content: "I'm just <@196188877885538304> testing mentions", + content: "I'm just **@Azalea &flwr; 🌺** (<@196188877885538304>) testing mentions", avatar_url: undefined }] } @@ -2845,7 +2845,7 @@ test("event2message: unknown emojis in the middle are linked", async t => { ) }) -test("event2message: guessed @mentions may join members to mention", async t => { +test("event2message: guessed @mentions in plaintext may join members to mention", async t => { let called = 0 const subtext = { user: { @@ -2893,6 +2893,56 @@ test("event2message: guessed @mentions may join members to mention", async t => t.equal(called, 1, "searchGuildMembers should be called once") }) +test("event2message: guessed @mentions in formatted body may join members to mention", async t => { + let called = 0 + const subtext = { + user: { + id: "321876634777218072", + username: "subtextual", + global_name: "subtext", + discriminator: "0" + } + } + t.deepEqual( + await eventToMessage({ + type: "m.room.message", + sender: "@cadence:cadence.moe", + content: { + msgtype: "m.text", + body: "wrong body", + format: "org.matrix.custom.html", + formatted_body: "HEY @SUBTEXT, WHAT FOOD WOULD YOU LIKE TO ORDER??" + }, + event_id: "$u5gSwSzv_ZQS3eM00mnTBCor8nx_A_AwuQz7e59PZk8", + room_id: "!kLRqKKUQXcibIMtOpl:cadence.moe" + }, { + id: "112760669178241024" + }, { + snow: { + guild: { + async searchGuildMembers(guildID, options) { + called++ + t.equal(guildID, "112760669178241024") + t.deepEqual(options, {query: "SUBTEXT"}) + return [subtext] + } + } + } + }), + { + messagesToDelete: [], + messagesToEdit: [], + messagesToSend: [{ + username: "cadence [they]", + content: "**_HEY <@321876634777218072>, WHAT FOOD WOULD YOU LIKE TO ORDER??_**", + avatar_url: undefined + }], + ensureJoined: [subtext.user] + } + ) + t.equal(called, 1, "searchGuildMembers should be called once") +}) + test("event2message: guessed @mentions work with other matrix bridge old users", async t => { t.deepEqual( await eventToMessage({ diff --git a/test/data.js b/test/data.js index 87ac510..9d86944 100644 --- a/test/data.js +++ b/test/data.js @@ -1340,6 +1340,89 @@ module.exports = { components: [] } }, + voice_message: { + id: "1112476845783388160", + type: 0, + content: "", + channel_id: "1099031887500034088", + author: { + id: "113340068197859328", + username: "kumaccino", + avatar: "b48302623a12bc7c59a71328f72ccb39", + discriminator: "0", + public_flags: 128, + premium_type: 0, + flags: 128, + banner: null, + accent_color: null, + global_name: "kumaccino", + avatar_decoration_data: null, + banner_color: null + }, + attachments: [ + { + id: "1112476845502365786", + filename: "voice-message.ogg", + size: 10584, + url: "https://cdn.discordapp.com/attachments/1099031887500034088/1112476845502365786/voice-message.ogg?ex=65c92d4c&is=65b6b84c&hm=0654bab5027474cbe23875954fa117cf44d8914c144cd151879590fa1baf8b1c&", + proxy_url: "https://media.discordapp.net/attachments/1099031887500034088/1112476845502365786/voice-message.ogg?ex=65c92d4c&is=65b6b84c&hm=0654bab5027474cbe23875954fa117cf44d8914c144cd151879590fa1baf8b1c&", + duration_secs: 3.9600000381469727, + waveform: "AAgXAAwAPBsCAAAAInEDFwAAAAAbMwATEBAAAAAAAAAAAAAAAA==", + content_type: "audio/ogg" + } + ], + embeds: [], + mentions: [], + mention_roles: [], + pinned: false, + mention_everyone: false, + tts: false, + timestamp: "2023-05-28T20:25:48.855000+00:00", + edited_timestamp: null, + flags: 8192, + components: [] + }, + misc_file: { + id: "1174514575819931718", + type: 0, + content: "final final final revised draft", + channel_id: "122155380120748034", + author: { + id: "142843483923677184", + username: "huck", + avatar: "a_1c7fda09a242d714570b4c828ef07504", + discriminator: "0", + public_flags: 512, + premium_type: 2, + flags: 512, + banner: null, + accent_color: null, + global_name: null, + avatar_decoration_data: null, + banner_color: null + }, + attachments: [ + { + id: "1174514575220158545", + filename: "the.yml", + size: 2274, + url: "https://cdn.discordapp.com/attachments/122155380120748034/1174514575220158545/the.yml?ex=65cd6270&is=65baed70&hm=8c5f1b571784e3c7f99628492298815884e351ae0dc7c2ae40dd22d97caf27d9&", + proxy_url: "https://media.discordapp.net/attachments/122155380120748034/1174514575220158545/the.yml?ex=65cd6270&is=65baed70&hm=8c5f1b571784e3c7f99628492298815884e351ae0dc7c2ae40dd22d97caf27d9&", + content_type: "text/plain; charset=utf-8", + content_scan_version: 0 + } + ], + embeds: [], + mentions: [], + mention_roles: [], + pinned: false, + mention_everyone: false, + tts: false, + timestamp: "2023-11-16T01:01:36.301000+00:00", + edited_timestamp: null, + flags: 0, + components: [] + }, simple_reply_to_reply_in_thread: { type: 19, tts: false, @@ -1681,6 +1764,47 @@ module.exports = { components: [] } }, + pk_message: { + pk_reply: { + id: "1202543812644306965", + type: 0, + content: "this is a reply", + channel_id: "1160894080998461480", + author: { + id: "1195662438662680720", + username: "special name", + avatar: "6b44a106659e78a2550474c61889194d", + discriminator: "0000", + public_flags: 0, + flags: 0, + bot: true, + global_name: null + }, + attachments: [], + embeds: [ + { + type: "rich", + description: "**[Reply to:](https://discord.com/channels/1160893336324931584/1160894080998461480/1202543413652881428)** now for my next experiment:", + author: { + name: "cadence [they] ↩️", + icon_url: "https://cdn.discordapp.com/avatars/1162510387057545227/af0ead3b92cf6e448fdad80b4e7fc9e5.png", + proxy_icon_url: "https://images-ext-1.discordapp.net/external/wWslraV-s-bLDwphL64YxeDm30M7PIhQQy0EQa8jpDc/https/cdn.discordapp.com/avatars/1162510387057545227/af0ead3b92cf6e448fdad80b4e7fc9e5.png" + } + } + ], + mentions: [], + mention_roles: [], + pinned: false, + mention_everyone: false, + tts: false, + timestamp: "2024-02-01T09:19:47.118000+00:00", + edited_timestamp: null, + flags: 0, + components: [], + application_id: "466378653216014359", + webhook_id: "1195662438662680720" + } + }, message_with_embeds: { nothing_but_a_field: { guild_id: "497159726455455754", diff --git a/test/ooye-test-data.sql b/test/ooye-test-data.sql index f1b720f..f455d9e 100644 --- a/test/ooye-test-data.sql +++ b/test/ooye-test-data.sql @@ -12,7 +12,8 @@ INSERT INTO channel_room (channel_id, room_id, name, nick, thread_parent, custom ('297272183716052993', '!rEOspnYqdOalaIFniV:cadence.moe', 'general', NULL, NULL, NULL), ('122155380120748034', '!cqeGDbPiMFAhLsqqqq:cadence.moe', 'cadences-mind', 'coding', NULL, NULL), ('176333891320283136', '!qzDBLKlildpzrrOnFZ:cadence.moe', '🌈丨davids-horse_she-took-the-kids', 'wonderland', NULL, 'mxc://cadence.moe/EVvrSkKIRONHjtRJsMLmHWLS'), -('489237891895768942', '!tnedrGVYKFNUdnegvf:tchncs.de', 'ex-room-doesnt-exist-any-more', NULL, NULL, NULL); +('489237891895768942', '!tnedrGVYKFNUdnegvf:tchncs.de', 'ex-room-doesnt-exist-any-more', NULL, NULL, NULL), +('1160894080998461480', '!TqlyQmifxGUggEmdBN:cadence.moe', 'ooyexperiment', NULL, NULL, NULL); INSERT INTO sim (user_id, sim_name, localpart, mxid) VALUES ('0', 'bot', '_ooye_bot', '@_ooye_bot:cadence.moe'), @@ -24,8 +25,8 @@ INSERT INTO sim (user_id, sim_name, localpart, mxid) VALUES ('1109360903096369153', 'amanda', '_ooye_amanda', '@_ooye_amanda:cadence.moe'), ('43d378d5-1183-47dc-ab3c-d14e21c3fe58', '_pk_zoego', '_ooye__pk_zoego', '@_ooye__pk_zoego:cadence.moe'); -INSERT INTO sim_proxy (user_id, proxy_owner_id) VALUES -('43d378d5-1183-47dc-ab3c-d14e21c3fe58', '196188877885538304'); +INSERT INTO sim_proxy (user_id, proxy_owner_id, displayname) VALUES +('43d378d5-1183-47dc-ab3c-d14e21c3fe58', '196188877885538304', 'Azalea &flwr; 🌺'); INSERT INTO sim_member (mxid, room_id, hashed_profile_content) VALUES ('@_ooye_bojack_horseman:cadence.moe', '!hYnGGlPHlbujVVfktC:cadence.moe', NULL); @@ -48,7 +49,8 @@ INSERT INTO message_channel (message_id, channel_id) VALUES ('1162005526675193909', '1162005314908999790'), ('1162625810109317170', '497161350934560778'), ('1158842413025071135', '176333891320283136'), -('1197612733600895076', '112760669178241024'); +('1197612733600895076', '112760669178241024'), +('1202543413652881428', '1160894080998461480'); INSERT INTO event_message (event_id, event_type, event_subtype, message_id, part, reaction_part, source) VALUES ('$X16nfVks1wsrhq4E9SSLiqrf2N8KD0erD0scZG7U5xg', 'm.room.message', 'm.text', '1126786462646550579', 0, 0, 1), @@ -74,7 +76,8 @@ INSERT INTO event_message (event_id, event_type, event_subtype, message_id, part ('$0wEdIP8fhTq-P68xwo_gyUw-Zv0KA2aS2tfhdFSrLZc', 'm.room.message', 'm.text', '1162625810109317170', 1, 1, 1), ('$zJFjTvNn1w_YqpR4o4ISKUFisNRgZcu1KSMI_LADPVQ', 'm.room.message', 'm.notice', '1162625810109317170', 1, 0, 1), ('$dVCLyj6kxb3DaAWDtjcv2kdSny8JMMHdDhCMz8mDxVo', 'm.room.message', 'm.text', '1158842413025071135', 0, 0, 1), -('$7tJoMw1h44n2gxgLUE1T_YinGrLbK0x-TDY1z6M7GBw', 'm.room.message', 'm.text', '1197612733600895076', 0, 0, 1); +('$7tJoMw1h44n2gxgLUE1T_YinGrLbK0x-TDY1z6M7GBw', 'm.room.message', 'm.text', '1197612733600895076', 0, 0, 1), +('$NB6nPgO2tfXyIwwDSF0Ga0BUrsgX1S-0Xl-jAvI8ucU', 'm.room.message', 'm.text', '1202543413652881428', 0, 0, 0); INSERT INTO file (discord_url, mxc_url) VALUES ('https://cdn.discordapp.com/attachments/497161332244742154/1124628646431297546/image.png', 'mxc://cadence.moe/qXoZktDqNtEGuOCZEADAMvhM'), @@ -92,7 +95,9 @@ INSERT INTO file (discord_url, mxc_url) VALUES ('https://cdn.discordapp.com/emojis/1125827250609201255.png', 'mxc://cadence.moe/pgdGTxAyEltccRgZKxdqzHHP'), ('https://cdn.discordapp.com/avatars/320067006521147393/5fc4ad85c1ea876709e9a7d3374a78a1.png?size=1024', 'mxc://cadence.moe/JPzSmALLirnIprlSMKohSSoX'), ('https://cdn.discordapp.com/emojis/288858540888686602.png', 'mxc://cadence.moe/mwZaCtRGAQQyOItagDeCocEO'), -('https://cdn.discordapp.com/attachments/112760669178241024/1197621094786531358/Ins_1960637570.mp4', 'mxc://cadence.moe/kMqLycqMURhVpwleWkmASpnU'); +('https://cdn.discordapp.com/attachments/112760669178241024/1197621094786531358/Ins_1960637570.mp4', 'mxc://cadence.moe/kMqLycqMURhVpwleWkmASpnU'), +('https://cdn.discordapp.com/attachments/1099031887500034088/1112476845502365786/voice-message.ogg', 'mxc://cadence.moe/MRRPDggXQMYkrUjTpxQbmcxB'), +('https://cdn.discordapp.com/attachments/122155380120748034/1174514575220158545/the.yml', 'mxc://cadence.moe/HnQIYQmmlIKwOQsbFsIGpzPP'); INSERT INTO emoji (emoji_id, name, animated, mxc_url) VALUES ('230201364309868544', 'hippo', 0, 'mxc://cadence.moe/qWmbXeRspZRLPcjseyLmeyXC'), diff --git a/test/test.js b/test/test.js index 8e7f193..95daf5b 100644 --- a/test/test.js +++ b/test/test.js @@ -48,6 +48,12 @@ file._actuallyUploadDiscordFileToMxc = function(url, res) { throw new Error(`Not t.pass("it did not throw an error") }) await p + + test("migrate: migration works the second time", async t => { + await migrate.migrate(db) + t.pass("it did not throw an error") + }) + db.exec(fs.readFileSync(join(__dirname, "ooye-test-data.sql"), "utf8")) require("../db/orm.test") require("../discord/utils.test") @@ -63,6 +69,7 @@ file._actuallyUploadDiscordFileToMxc = function(url, res) { throw new Error(`Not require("../d2m/converters/lottie.test") require("../d2m/converters/message-to-event.test") require("../d2m/converters/message-to-event.embeds.test") + require("../d2m/converters/message-to-event.pk.test") require("../d2m/converters/pins-to-list.test") require("../d2m/converters/remove-reaction.test") require("../d2m/converters/thread-to-announcement.test")