Rearrange code (self-review)
This commit is contained in:
parent
c5d6c5e4c7
commit
47ac49a855
16 changed files with 275 additions and 74 deletions
8
.c8rc.json
Normal file
8
.c8rc.json
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"watermarks": {
|
||||||
|
"statements": [60, 100],
|
||||||
|
"lines": [60, 100],
|
||||||
|
"functions": [60, 100],
|
||||||
|
"branches": [60, 100]
|
||||||
|
}
|
||||||
|
}
|
|
@ -93,7 +93,11 @@ async function editToChanges(message, guild, api) {
|
||||||
// We can choose an existing event to promote. Bigger order is better.
|
// We can choose an existing event to promote. Bigger order is better.
|
||||||
const order = e => 2*+(e.event_type === "m.room.message") + 1*+(e.event_subtype === "m.text")
|
const order = e => 2*+(e.event_type === "m.room.message") + 1*+(e.event_subtype === "m.text")
|
||||||
eventsToReplace.sort((a, b) => order(b) - order(a))
|
eventsToReplace.sort((a, b) => order(b) - order(a))
|
||||||
promotions.push({column, eventID: eventsToReplace[0].old.event_id})
|
if (column === "part") {
|
||||||
|
promotions.push({column, eventID: eventsToReplace[0].old.event_id}) // part should be the first one
|
||||||
|
} else {
|
||||||
|
promotions.push({column, eventID: eventsToReplace[eventsToReplace.length - 1].old.event_id}) // reaction_part should be the last one
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// No existing events to promote, but new events are being sent. Whatever gets sent will be the next part = 0.
|
// No existing events to promote, but new events are being sent. Whatever gets sent will be the next part = 0.
|
||||||
promotions.push({column, nextEvent: true})
|
promotions.push({column, nextEvent: true})
|
||||||
|
|
|
@ -175,3 +175,63 @@ test("edit2changes: edit of reply to skull webp attachment with content", async
|
||||||
}
|
}
|
||||||
}])
|
}])
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test("edit2changes: edits the text event when multiple rows have part = 0 (should never happen in real life, but make sure the safety net works)", async t => {
|
||||||
|
const {eventsToRedact, eventsToReplace, eventsToSend} = await editToChanges(data.message_update.edited_content_with_sticker_and_attachments_but_all_parts_equal_0, data.guild.general, {})
|
||||||
|
t.deepEqual(eventsToRedact, [])
|
||||||
|
t.deepEqual(eventsToSend, [])
|
||||||
|
t.deepEqual(eventsToReplace, [{
|
||||||
|
oldID: "$lnAF9IosAECTnlv9p2e18FG8rHn-JgYKHEHIh5qd999",
|
||||||
|
newContent: {
|
||||||
|
$type: "m.room.message",
|
||||||
|
msgtype: "m.text",
|
||||||
|
body: "* only the content can be edited",
|
||||||
|
"m.mentions": {},
|
||||||
|
// *** Replaced With: ***
|
||||||
|
"m.new_content": {
|
||||||
|
msgtype: "m.text",
|
||||||
|
body: "only the content can be edited",
|
||||||
|
"m.mentions": {}
|
||||||
|
},
|
||||||
|
"m.relates_to": {
|
||||||
|
rel_type: "m.replace",
|
||||||
|
event_id: "$lnAF9IosAECTnlv9p2e18FG8rHn-JgYKHEHIh5qd999"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}])
|
||||||
|
})
|
||||||
|
|
||||||
|
test("edit2changes: promotes the text event when multiple rows have part = 1 (should never happen in real life, but make sure the safety net works)", async t => {
|
||||||
|
const {eventsToRedact, eventsToReplace, eventsToSend, promotions} = await editToChanges(data.message_update.edited_content_with_sticker_and_attachments_but_all_parts_equal_1, data.guild.general, {})
|
||||||
|
t.deepEqual(eventsToRedact, [])
|
||||||
|
t.deepEqual(eventsToSend, [])
|
||||||
|
t.deepEqual(eventsToReplace, [{
|
||||||
|
oldID: "$lnAF9IosAECTnlv9p2e18FG8rHn-JgYKHEHIh5qd111",
|
||||||
|
newContent: {
|
||||||
|
$type: "m.room.message",
|
||||||
|
msgtype: "m.text",
|
||||||
|
body: "* only the content can be edited",
|
||||||
|
"m.mentions": {},
|
||||||
|
// *** Replaced With: ***
|
||||||
|
"m.new_content": {
|
||||||
|
msgtype: "m.text",
|
||||||
|
body: "only the content can be edited",
|
||||||
|
"m.mentions": {}
|
||||||
|
},
|
||||||
|
"m.relates_to": {
|
||||||
|
rel_type: "m.replace",
|
||||||
|
event_id: "$lnAF9IosAECTnlv9p2e18FG8rHn-JgYKHEHIh5qd111"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}])
|
||||||
|
t.deepEqual(promotions, [
|
||||||
|
{
|
||||||
|
column: "part",
|
||||||
|
eventID: "$lnAF9IosAECTnlv9p2e18FG8rHn-JgYKHEHIh5qd111"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
column: "reaction_part",
|
||||||
|
eventID: "$f9cjKiacXI9qPF_nUAckzbiKnJEi0LM399kOkhdd111"
|
||||||
|
}
|
||||||
|
])
|
||||||
|
})
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
// @ts-check
|
// @ts-check
|
||||||
|
|
||||||
|
const assert = require("assert")
|
||||||
const stream = require("stream")
|
const stream = require("stream")
|
||||||
const {PNG} = require("pngjs")
|
const {PNG} = require("pngjs")
|
||||||
|
|
||||||
|
@ -27,7 +28,7 @@ async function convert(text) {
|
||||||
/** @type RlottieWasm */
|
/** @type RlottieWasm */
|
||||||
const rh = new r.RlottieWasm()
|
const rh = new r.RlottieWasm()
|
||||||
const status = rh.load(text)
|
const status = rh.load(text)
|
||||||
if (!status) throw new Error(`Rlottie unable to load ${text.length} byte data file.`)
|
assert(status, `Rlottie unable to load ${text.length} byte data file.`)
|
||||||
const rendered = rh.render(0, SIZE, SIZE)
|
const rendered = rh.render(0, SIZE, SIZE)
|
||||||
let png = new PNG({
|
let png = new PNG({
|
||||||
width: SIZE,
|
width: SIZE,
|
||||||
|
@ -38,11 +39,9 @@ async function convert(text) {
|
||||||
inputHasAlpha: true,
|
inputHasAlpha: true,
|
||||||
})
|
})
|
||||||
png.data = Buffer.from(rendered)
|
png.data = Buffer.from(rendered)
|
||||||
// The transform stream is necessary because PNG requires me to pipe it somewhere before this event loop ends
|
// png.pack() is a bad stream and will throw away any data it sends if it's not connected to a destination straight away.
|
||||||
const resultStream = png.pack()
|
// We use Duplex.from to convert it into a good stream.
|
||||||
const p = new stream.PassThrough()
|
return stream.Duplex.from(png.pack())
|
||||||
resultStream.pipe(p)
|
|
||||||
return p
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports.convert = convert
|
module.exports.convert = convert
|
||||||
|
|
|
@ -78,10 +78,14 @@ function getDiscordParseCallbacks(message, guild, useHTML) {
|
||||||
return `@${role.name}:`
|
return `@${role.name}:`
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
everyone: node =>
|
everyone: () => {
|
||||||
"@room",
|
if (message.mention_everyone) return "@room"
|
||||||
here: node =>
|
return "@everyone"
|
||||||
"@here"
|
},
|
||||||
|
here: () => {
|
||||||
|
if (message.mention_everyone) return "@room"
|
||||||
|
return "@here"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -199,6 +203,7 @@ async function attachmentToEvent(mentions, attachment) {
|
||||||
async function messageToEvent(message, guild, options = {}, di) {
|
async function messageToEvent(message, guild, options = {}, di) {
|
||||||
const events = []
|
const events = []
|
||||||
|
|
||||||
|
/* c8 ignore next 7 */
|
||||||
if (message.type === DiscordTypes.MessageType.ThreadCreated) {
|
if (message.type === DiscordTypes.MessageType.ThreadCreated) {
|
||||||
// This is the kind of message that appears when somebody makes a thread which isn't close enough to the message it's based off.
|
// This is the kind of message that appears when somebody makes a thread which isn't close enough to the message it's based off.
|
||||||
// It lacks the lines and the pill, so it looks kind of like a member join message, and it says:
|
// It lacks the lines and the pill, so it looks kind of like a member join message, and it says:
|
||||||
|
|
|
@ -60,7 +60,7 @@ function userToSimName(user) {
|
||||||
|
|
||||||
// 1. Is sim user already registered?
|
// 1. Is sim user already registered?
|
||||||
const existing = select("sim", "sim_name", {user_id: user.id}).pluck().get()
|
const existing = select("sim", "sim_name", {user_id: user.id}).pluck().get()
|
||||||
if (existing) return existing
|
assert.equal(existing, null, "Shouldn't try to create a new name for an existing sim")
|
||||||
|
|
||||||
// 2. Register based on username (could be new or old format)
|
// 2. Register based on username (could be new or old format)
|
||||||
// (Unless it's a special user, in which case copy their provided mappings.)
|
// (Unless it's a special user, in which case copy their provided mappings.)
|
||||||
|
|
36
m2d/actions/emoji-sheet.js
Normal file
36
m2d/actions/emoji-sheet.js
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
// @ts-check
|
||||||
|
|
||||||
|
const assert = require("assert")
|
||||||
|
const fetch = require("node-fetch").default
|
||||||
|
|
||||||
|
const utils = require("../converters/utils")
|
||||||
|
const {sync} = require("../../passthrough")
|
||||||
|
|
||||||
|
/** @type {import("../converters/emoji-sheet")} */
|
||||||
|
const emojiSheetConverter = sync.require("../converters/emoji-sheet")
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Downloads the emoji from the web and converts to uncompressed PNG data.
|
||||||
|
* @param {string} mxc a single mxc:// URL
|
||||||
|
* @returns {Promise<Buffer | undefined>} uncompressed PNG data, or undefined if the downloaded emoji is not valid
|
||||||
|
*/
|
||||||
|
async function getAndConvertEmoji(mxc) {
|
||||||
|
const abortController = new AbortController()
|
||||||
|
|
||||||
|
const url = utils.getPublicUrlForMxc(mxc)
|
||||||
|
assert(url)
|
||||||
|
|
||||||
|
/** @type {import("node-fetch").Response} */
|
||||||
|
// If it turns out to be a GIF, we want to abandon the connection without downloading the whole thing.
|
||||||
|
// If we were using connection pooling, we would be forced to download the entire GIF.
|
||||||
|
// So we set no agent to ensure we are not connection pooling.
|
||||||
|
// @ts-ignore the signal is slightly different from the type it wants (still works fine)
|
||||||
|
const res = await fetch(url, {agent: false, signal: abortController.signal})
|
||||||
|
return emojiSheetConverter.convertImageStream(res.body, () => {
|
||||||
|
abortController.abort()
|
||||||
|
res.body.pause()
|
||||||
|
res.body.emit("end")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports.getAndConvertEmoji = getAndConvertEmoji
|
|
@ -17,8 +17,8 @@ const eventToMessage = sync.require("../converters/event-to-message")
|
||||||
const api = sync.require("../../matrix/api")
|
const api = sync.require("../../matrix/api")
|
||||||
/** @type {import("../../d2m/actions/register-user")} */
|
/** @type {import("../../d2m/actions/register-user")} */
|
||||||
const registerUser = sync.require("../../d2m/actions/register-user")
|
const registerUser = sync.require("../../d2m/actions/register-user")
|
||||||
/** @type {import("../converters/emoji-sheet")} */
|
/** @type {import("../actions/emoji-sheet")} */
|
||||||
const emojiSheet = sync.require("../converters/emoji-sheet")
|
const emojiSheet = sync.require("../actions/emoji-sheet")
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {DiscordTypes.RESTPostAPIWebhookWithTokenJSONBody & {files?: {name: string, file: Buffer | Readable}[], pendingFiles?: ({name: string, url: string} | {name: string, url: string, key: string, iv: string} | {name: string, buffer: Buffer | Readable})[]}} message
|
* @param {DiscordTypes.RESTPostAPIWebhookWithTokenJSONBody & {files?: {name: string, file: Buffer | Readable}[], pendingFiles?: ({name: string, url: string} | {name: string, url: string, key: string, iv: string} | {name: string, buffer: Buffer | Readable})[]}} message
|
||||||
|
|
|
@ -1,13 +1,10 @@
|
||||||
// @ts-check
|
// @ts-check
|
||||||
|
|
||||||
const assert = require("assert").strict
|
const assert = require("assert").strict
|
||||||
const fs = require("fs")
|
|
||||||
const {pipeline} = require("stream").promises
|
const {pipeline} = require("stream").promises
|
||||||
const sharp = require("sharp")
|
const sharp = require("sharp")
|
||||||
const {GIFrame} = require("giframe")
|
const {GIFrame} = require("giframe")
|
||||||
const {PNG} = require("pngjs")
|
const {PNG} = require("pngjs")
|
||||||
const utils = require("./utils")
|
|
||||||
const fetch = require("node-fetch").default
|
|
||||||
const streamMimeType = require("stream-mime-type")
|
const streamMimeType = require("stream-mime-type")
|
||||||
|
|
||||||
const SIZE = 48
|
const SIZE = 48
|
||||||
|
@ -50,49 +47,6 @@ async function compositeMatrixEmojis(mxcs, mxcDownloader) {
|
||||||
return output.data
|
return output.data
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Downloads the emoji from the web and converts to uncompressed PNG data.
|
|
||||||
* @param {string} mxc a single mxc:// URL
|
|
||||||
* @returns {Promise<Buffer | undefined>} uncompressed PNG data, or undefined if the downloaded emoji is not valid
|
|
||||||
*/
|
|
||||||
async function getAndConvertEmoji(mxc) {
|
|
||||||
const abortController = new AbortController()
|
|
||||||
|
|
||||||
const url = utils.getPublicUrlForMxc(mxc)
|
|
||||||
assert(url)
|
|
||||||
|
|
||||||
/** @type {import("node-fetch").Response} */
|
|
||||||
// If it turns out to be a GIF, we want to abandon the connection without downloading the whole thing.
|
|
||||||
// If we were using connection pooling, we would be forced to download the entire GIF.
|
|
||||||
// So we set no agent to ensure we are not connection pooling.
|
|
||||||
// @ts-ignore the signal is slightly different from the type it wants (still works fine)
|
|
||||||
const res = await fetch(url, {agent: false, signal: abortController.signal})
|
|
||||||
return convertImageStream(res.body, () => {
|
|
||||||
abortController.abort()
|
|
||||||
res.body.pause()
|
|
||||||
res.body.emit("end")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* MOCK: Gets the emoji from the filesystem and converts to uncompressed PNG data.
|
|
||||||
* @param {string} mxc a single mxc:// URL
|
|
||||||
* @returns {Promise<Buffer | undefined>} uncompressed PNG data, or undefined if the downloaded emoji is not valid
|
|
||||||
*/
|
|
||||||
async function _mockGetAndConvertEmoji(mxc) {
|
|
||||||
const id = mxc.match(/\/([^./]*)$/)?.[1]
|
|
||||||
let s
|
|
||||||
if (fs.existsSync(`test/res/${id}.png`)) {
|
|
||||||
s = fs.createReadStream(`test/res/${id}.png`)
|
|
||||||
} else {
|
|
||||||
s = fs.createReadStream(`test/res/${id}.gif`)
|
|
||||||
}
|
|
||||||
return convertImageStream(s, () => {
|
|
||||||
s.pause()
|
|
||||||
s.emit("end")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {import("node-fetch").Response["body"]} streamIn
|
* @param {import("node-fetch").Response["body"]} streamIn
|
||||||
* @param {() => any} stopStream
|
* @param {() => any} stopStream
|
||||||
|
@ -156,6 +110,4 @@ async function convertImageStream(streamIn, stopStream) {
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports.compositeMatrixEmojis = compositeMatrixEmojis
|
module.exports.compositeMatrixEmojis = compositeMatrixEmojis
|
||||||
module.exports.getAndConvertEmoji = getAndConvertEmoji
|
module.exports.convertImageStream = convertImageStream
|
||||||
module.exports._mockGetAndConvertEmoji = _mockGetAndConvertEmoji
|
|
||||||
module.exports._convertImageStream = convertImageStream
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
const assert = require("assert").strict
|
|
||||||
const {test} = require("supertape")
|
const {test} = require("supertape")
|
||||||
const {_convertImageStream} = require("./emoji-sheet")
|
const {convertImageStream} = require("./emoji-sheet")
|
||||||
const fs = require("fs")
|
const fs = require("fs")
|
||||||
const {Transform} = require("stream").Transform
|
const {Transform} = require("stream").Transform
|
||||||
|
|
||||||
|
@ -33,7 +32,7 @@ async function runSingleTest(t, path, totalSize, sizeCheck) {
|
||||||
const file = fs.createReadStream(path)
|
const file = fs.createReadStream(path)
|
||||||
const meter = new Meter()
|
const meter = new Meter()
|
||||||
const p = file.pipe(meter)
|
const p = file.pipe(meter)
|
||||||
const result = await _convertImageStream(p, () => {
|
const result = await convertImageStream(p, () => {
|
||||||
file.pause()
|
file.pause()
|
||||||
file.emit("end")
|
file.emit("end")
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
const assert = require("assert").strict
|
const assert = require("assert").strict
|
||||||
|
const fs = require("fs")
|
||||||
const {test} = require("supertape")
|
const {test} = require("supertape")
|
||||||
const {eventToMessage} = require("./event-to-message")
|
const {eventToMessage} = require("./event-to-message")
|
||||||
const {_mockGetAndConvertEmoji} = require("./emoji-sheet")
|
const {convertImageStream} = require("./emoji-sheet")
|
||||||
const data = require("../../test/data")
|
const data = require("../../test/data")
|
||||||
const {MatrixServerError} = require("../../matrix/mreq")
|
const {MatrixServerError} = require("../../matrix/mreq")
|
||||||
const {db, select, discord} = require("../../passthrough")
|
const {select, discord} = require("../../passthrough")
|
||||||
|
|
||||||
/* c8 ignore next 7 */
|
/* c8 ignore next 7 */
|
||||||
function slow() {
|
function slow() {
|
||||||
|
@ -47,6 +48,25 @@ function sameFirstContentAndWhitespace(t, a, b) {
|
||||||
t.equal(a2, b2)
|
t.equal(a2, b2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MOCK: Gets the emoji from the filesystem and converts to uncompressed PNG data.
|
||||||
|
* @param {string} mxc a single mxc:// URL
|
||||||
|
* @returns {Promise<Buffer | undefined>} uncompressed PNG data, or undefined if the downloaded emoji is not valid
|
||||||
|
*/
|
||||||
|
async function mockGetAndConvertEmoji(mxc) {
|
||||||
|
const id = mxc.match(/\/([^./]*)$/)?.[1]
|
||||||
|
let s
|
||||||
|
if (fs.existsSync(`test/res/${id}.png`)) {
|
||||||
|
s = fs.createReadStream(`test/res/${id}.png`)
|
||||||
|
} else {
|
||||||
|
s = fs.createReadStream(`test/res/${id}.gif`)
|
||||||
|
}
|
||||||
|
return convertImageStream(s, () => {
|
||||||
|
s.pause()
|
||||||
|
s.emit("end")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
test("event2message: body is used when there is no formatted_body", async t => {
|
test("event2message: body is used when there is no formatted_body", async t => {
|
||||||
t.deepEqual(
|
t.deepEqual(
|
||||||
await eventToMessage({
|
await eventToMessage({
|
||||||
|
@ -3535,7 +3555,7 @@ slow()("event2message: unknown emoji at the end is reuploaded as a sprite sheet"
|
||||||
},
|
},
|
||||||
event_id: "$g07oYSZFWBkxohNEfywldwgcWj1hbhDzQ1sBAKvqOOU",
|
event_id: "$g07oYSZFWBkxohNEfywldwgcWj1hbhDzQ1sBAKvqOOU",
|
||||||
room_id: "!kLRqKKUQXcibIMtOpl:cadence.moe"
|
room_id: "!kLRqKKUQXcibIMtOpl:cadence.moe"
|
||||||
}, {}, {mxcDownloader: _mockGetAndConvertEmoji})
|
}, {}, {mxcDownloader: mockGetAndConvertEmoji})
|
||||||
const testResult = {
|
const testResult = {
|
||||||
content: messages.messagesToSend[0].content,
|
content: messages.messagesToSend[0].content,
|
||||||
fileName: messages.messagesToSend[0].pendingFiles[0].name,
|
fileName: messages.messagesToSend[0].pendingFiles[0].name,
|
||||||
|
@ -3560,7 +3580,7 @@ slow()("event2message: known emoji from an unreachable server at the end is reup
|
||||||
},
|
},
|
||||||
event_id: "$g07oYSZFWBkxohNEfywldwgcWj1hbhDzQ1sBAKvqOOU",
|
event_id: "$g07oYSZFWBkxohNEfywldwgcWj1hbhDzQ1sBAKvqOOU",
|
||||||
room_id: "!kLRqKKUQXcibIMtOpl:cadence.moe"
|
room_id: "!kLRqKKUQXcibIMtOpl:cadence.moe"
|
||||||
}, {}, {mxcDownloader: _mockGetAndConvertEmoji})
|
}, {}, {mxcDownloader: mockGetAndConvertEmoji})
|
||||||
const testResult = {
|
const testResult = {
|
||||||
content: messages.messagesToSend[0].content,
|
content: messages.messagesToSend[0].content,
|
||||||
fileName: messages.messagesToSend[0].pendingFiles[0].name,
|
fileName: messages.messagesToSend[0].pendingFiles[0].name,
|
||||||
|
@ -3585,7 +3605,7 @@ slow()("event2message: known and unknown emojis in the end are reuploaded as a s
|
||||||
},
|
},
|
||||||
event_id: "$g07oYSZFWBkxohNEfywldwgcWj1hbhDzQ1sBAKvqOOU",
|
event_id: "$g07oYSZFWBkxohNEfywldwgcWj1hbhDzQ1sBAKvqOOU",
|
||||||
room_id: "!kLRqKKUQXcibIMtOpl:cadence.moe"
|
room_id: "!kLRqKKUQXcibIMtOpl:cadence.moe"
|
||||||
}, {}, {mxcDownloader: _mockGetAndConvertEmoji})
|
}, {}, {mxcDownloader: mockGetAndConvertEmoji})
|
||||||
const testResult = {
|
const testResult = {
|
||||||
content: messages.messagesToSend[0].content,
|
content: messages.messagesToSend[0].content,
|
||||||
fileName: messages.messagesToSend[0].pendingFiles[0].name,
|
fileName: messages.messagesToSend[0].pendingFiles[0].name,
|
||||||
|
@ -3610,7 +3630,7 @@ slow()("event2message: all unknown chess emojis are reuploaded as a sprite sheet
|
||||||
},
|
},
|
||||||
event_id: "$Me6iE8C8CZyrDEOYYrXKSYRuuh_25Jj9kZaNrf7LKr4",
|
event_id: "$Me6iE8C8CZyrDEOYYrXKSYRuuh_25Jj9kZaNrf7LKr4",
|
||||||
room_id: "!maggESguZBqGBZtSnr:cadence.moe"
|
room_id: "!maggESguZBqGBZtSnr:cadence.moe"
|
||||||
}, {}, {mxcDownloader: _mockGetAndConvertEmoji})
|
}, {}, {mxcDownloader: mockGetAndConvertEmoji})
|
||||||
const testResult = {
|
const testResult = {
|
||||||
content: messages.messagesToSend[0].content,
|
content: messages.messagesToSend[0].content,
|
||||||
fileName: messages.messagesToSend[0].pendingFiles[0].name,
|
fileName: messages.messagesToSend[0].pendingFiles[0].name,
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
const assert = require("assert")
|
||||||
const {kstateToState, stateToKState, diffKState, kstateStripConditionals} = require("./kstate")
|
const {kstateToState, stateToKState, diffKState, kstateStripConditionals} = require("./kstate")
|
||||||
const {test} = require("supertape")
|
const {test} = require("supertape")
|
||||||
|
|
||||||
|
@ -162,3 +163,29 @@ test("diffKState: power levels are mixed together", t => {
|
||||||
})
|
})
|
||||||
t.notDeepEqual(original, result)
|
t.notDeepEqual(original, result)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test("diffKState: cannot merge power levels if original power levels are missing", t => {
|
||||||
|
const original = {}
|
||||||
|
assert.throws(() =>
|
||||||
|
diffKState(original, {
|
||||||
|
"m.room.power_levels/": {
|
||||||
|
"events": {
|
||||||
|
"m.room.avatar": 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
, /original power level data is missing/)
|
||||||
|
t.pass()
|
||||||
|
})
|
||||||
|
|
||||||
|
test("diffKState: kstate keys must contain a slash separator", t => {
|
||||||
|
assert.throws(() =>
|
||||||
|
diffKState({
|
||||||
|
"m.room.name/": {name: "test name"},
|
||||||
|
}, {
|
||||||
|
"m.room.name/": {name: "test name"},
|
||||||
|
"new": {a: 2}
|
||||||
|
})
|
||||||
|
, /does not contain a slash separator/)
|
||||||
|
t.pass()
|
||||||
|
})
|
||||||
|
|
|
@ -54,6 +54,6 @@
|
||||||
"addbot": "node addbot.js",
|
"addbot": "node addbot.js",
|
||||||
"test": "cross-env FORCE_COLOR=true supertape --no-check-assertions-count --format tap test/test.js | tap-dot",
|
"test": "cross-env FORCE_COLOR=true supertape --no-check-assertions-count --format tap test/test.js | tap-dot",
|
||||||
"test-slow": "cross-env FORCE_COLOR=true supertape --no-check-assertions-count --format tap --no-worker test/test.js -- --slow | tap-dot",
|
"test-slow": "cross-env FORCE_COLOR=true supertape --no-check-assertions-count --format tap --no-worker test/test.js -- --slow | tap-dot",
|
||||||
"cover": "c8 --skip-full -x db/migrations -x matrix/file.js -x matrix/api.js -x matrix/mreq.js -r html -r text supertape --no-check-assertions-count --format fail test/test.js -- --slow"
|
"cover": "c8 --skip-full -x db/migrations -x matrix/file.js -x matrix/api.js -x matrix/mreq.js -x d2m/converters/rlottie-wasm.js -r html -r text supertape --no-check-assertions-count --format fail --no-worker test/test.js -- --slow"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
82
test/data.js
82
test/data.js
|
@ -2662,6 +2662,88 @@ module.exports = {
|
||||||
name: "pomu puff"
|
name: "pomu puff"
|
||||||
}]
|
}]
|
||||||
},
|
},
|
||||||
|
edited_content_with_sticker_and_attachments_but_all_parts_equal_0: {
|
||||||
|
id: "1106366167788044451",
|
||||||
|
type: 0,
|
||||||
|
content: "only the content can be edited",
|
||||||
|
channel_id: "122155380120748034",
|
||||||
|
author: {
|
||||||
|
id: "113340068197859328",
|
||||||
|
username: "Cookie 🍪",
|
||||||
|
global_name: null,
|
||||||
|
display_name: null,
|
||||||
|
avatar: "b48302623a12bc7c59a71328f72ccb39",
|
||||||
|
discriminator: "7766",
|
||||||
|
public_flags: 128,
|
||||||
|
avatar_decoration: null
|
||||||
|
},
|
||||||
|
attachments: [{
|
||||||
|
id: "1106366167486038016",
|
||||||
|
filename: "image.png",
|
||||||
|
size: 127373,
|
||||||
|
url: "https://cdn.discordapp.com/attachments/122155380120748034/1106366167486038016/image.png",
|
||||||
|
proxy_url: "https://media.discordapp.net/attachments/122155380120748034/1106366167486038016/image.png",
|
||||||
|
width: 333,
|
||||||
|
height: 287,
|
||||||
|
content_type: "image/png"
|
||||||
|
}],
|
||||||
|
embeds: [],
|
||||||
|
mentions: [],
|
||||||
|
mention_roles: [],
|
||||||
|
pinned: false,
|
||||||
|
mention_everyone: false,
|
||||||
|
tts: false,
|
||||||
|
timestamp: "2023-05-11T23:44:09.690000+00:00",
|
||||||
|
edited_timestamp: "2023-05-11T23:44:19.690000+00:00",
|
||||||
|
flags: 0,
|
||||||
|
components: [],
|
||||||
|
sticker_items: [{
|
||||||
|
id: "1106323941183717586",
|
||||||
|
format_type: 1,
|
||||||
|
name: "pomu puff"
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
edited_content_with_sticker_and_attachments_but_all_parts_equal_1: {
|
||||||
|
id: "1106366167788044452",
|
||||||
|
type: 0,
|
||||||
|
content: "only the content can be edited",
|
||||||
|
channel_id: "122155380120748034",
|
||||||
|
author: {
|
||||||
|
id: "113340068197859328",
|
||||||
|
username: "Cookie 🍪",
|
||||||
|
global_name: null,
|
||||||
|
display_name: null,
|
||||||
|
avatar: "b48302623a12bc7c59a71328f72ccb39",
|
||||||
|
discriminator: "7766",
|
||||||
|
public_flags: 128,
|
||||||
|
avatar_decoration: null
|
||||||
|
},
|
||||||
|
attachments: [{
|
||||||
|
id: "1106366167486038016",
|
||||||
|
filename: "image.png",
|
||||||
|
size: 127373,
|
||||||
|
url: "https://cdn.discordapp.com/attachments/122155380120748034/1106366167486038016/image.png",
|
||||||
|
proxy_url: "https://media.discordapp.net/attachments/122155380120748034/1106366167486038016/image.png",
|
||||||
|
width: 333,
|
||||||
|
height: 287,
|
||||||
|
content_type: "image/png"
|
||||||
|
}],
|
||||||
|
embeds: [],
|
||||||
|
mentions: [],
|
||||||
|
mention_roles: [],
|
||||||
|
pinned: false,
|
||||||
|
mention_everyone: false,
|
||||||
|
tts: false,
|
||||||
|
timestamp: "2023-05-11T23:44:09.690000+00:00",
|
||||||
|
edited_timestamp: "2023-05-11T23:44:19.690000+00:00",
|
||||||
|
flags: 0,
|
||||||
|
components: [],
|
||||||
|
sticker_items: [{
|
||||||
|
id: "1106323941183717586",
|
||||||
|
format_type: 1,
|
||||||
|
name: "pomu puff"
|
||||||
|
}]
|
||||||
|
},
|
||||||
edit_of_reply_to_skull_webp_attachment_with_content: {
|
edit_of_reply_to_skull_webp_attachment_with_content: {
|
||||||
type: 19,
|
type: 19,
|
||||||
tts: false,
|
tts: false,
|
||||||
|
|
|
@ -33,6 +33,8 @@ INSERT INTO sim_member (mxid, room_id, hashed_profile_content) VALUES
|
||||||
|
|
||||||
INSERT INTO message_channel (message_id, channel_id) VALUES
|
INSERT INTO message_channel (message_id, channel_id) VALUES
|
||||||
('1106366167788044450', '122155380120748034'),
|
('1106366167788044450', '122155380120748034'),
|
||||||
|
('1106366167788044451', '122155380120748034'),
|
||||||
|
('1106366167788044452', '122155380120748034'),
|
||||||
('1126786462646550579', '112760669178241024'),
|
('1126786462646550579', '112760669178241024'),
|
||||||
('1128084748338741392', '112760669178241024'),
|
('1128084748338741392', '112760669178241024'),
|
||||||
('1128084851279536279', '112760669178241024'),
|
('1128084851279536279', '112760669178241024'),
|
||||||
|
@ -68,6 +70,12 @@ INSERT INTO event_message (event_id, event_type, event_subtype, message_id, part
|
||||||
('$lnAF9IosAECTnlv9p2e18FG8rHn-JgYKHEHIh5qdFv4', 'm.room.message', 'm.text', '1106366167788044450', 0, 1, 1),
|
('$lnAF9IosAECTnlv9p2e18FG8rHn-JgYKHEHIh5qdFv4', 'm.room.message', 'm.text', '1106366167788044450', 0, 1, 1),
|
||||||
('$Ijf1MFCD39ktrNHxrA-i2aKoRWNYdAV2ZXYQeiZIgEU', 'm.room.message', 'm.image', '1106366167788044450', 1, 1, 0),
|
('$Ijf1MFCD39ktrNHxrA-i2aKoRWNYdAV2ZXYQeiZIgEU', 'm.room.message', 'm.image', '1106366167788044450', 1, 1, 0),
|
||||||
('$f9cjKiacXI9qPF_nUAckzbiKnJEi0LM399kOkhdd8f8', 'm.sticker', NULL, '1106366167788044450', 1, 0, 0),
|
('$f9cjKiacXI9qPF_nUAckzbiKnJEi0LM399kOkhdd8f8', 'm.sticker', NULL, '1106366167788044450', 1, 0, 0),
|
||||||
|
('$lnAF9IosAECTnlv9p2e18FG8rHn-JgYKHEHIh5qd999', 'm.room.message', 'm.text', '1106366167788044451', 0, 0, 1),
|
||||||
|
('$Ijf1MFCD39ktrNHxrA-i2aKoRWNYdAV2ZXYQeiZI999', 'm.room.message', 'm.image', '1106366167788044451', 0, 0, 1),
|
||||||
|
('$f9cjKiacXI9qPF_nUAckzbiKnJEi0LM399kOkhdd999', 'm.sticker', NULL, '1106366167788044451', 0, 0, 1),
|
||||||
|
('$lnAF9IosAECTnlv9p2e18FG8rHn-JgYKHEHIh5qd111', 'm.room.message', 'm.text', '1106366167788044452', 1, 1, 1),
|
||||||
|
('$Ijf1MFCD39ktrNHxrA-i2aKoRWNYdAV2ZXYQeiZI111', 'm.room.message', 'm.image', '1106366167788044452', 1, 1, 1),
|
||||||
|
('$f9cjKiacXI9qPF_nUAckzbiKnJEi0LM399kOkhdd111', 'm.sticker', NULL, '1106366167788044452', 1, 1, 1),
|
||||||
('$Fxy8SMoJuTduwReVkHZ1uHif9EuvNx36Hg79cltiA04', 'm.room.message', 'm.text', '1144865310588014633', 0, 0, 1),
|
('$Fxy8SMoJuTduwReVkHZ1uHif9EuvNx36Hg79cltiA04', 'm.room.message', 'm.text', '1144865310588014633', 0, 0, 1),
|
||||||
('$v_Gtr-bzv9IVlSLBO5DstzwmiDd-GSFaNfHX66IupV8', 'm.room.message', 'm.text', '1144874214311067708', 0, 0, 0),
|
('$v_Gtr-bzv9IVlSLBO5DstzwmiDd-GSFaNfHX66IupV8', 'm.room.message', 'm.text', '1144874214311067708', 0, 0, 0),
|
||||||
('$7LIdiJCEqjcWUrpzWzS8TELOlFfBEe4ytgS7zn2lbSs', 'm.room.message', 'm.text', '1145688633186193479', 0, 0, 0),
|
('$7LIdiJCEqjcWUrpzWzS8TELOlFfBEe4ytgS7zn2lbSs', 'm.room.message', 'm.text', '1145688633186193479', 0, 0, 0),
|
||||||
|
|
|
@ -49,6 +49,7 @@ passthrough.from = orm.from
|
||||||
passthrough.select = orm.select
|
passthrough.select = orm.select
|
||||||
|
|
||||||
const file = sync.require("../matrix/file")
|
const file = sync.require("../matrix/file")
|
||||||
|
/* c8 ignore next */
|
||||||
file._actuallyUploadDiscordFileToMxc = function(url, res) { throw new Error(`Not allowed to upload files during testing.\nURL: ${url}`) }
|
file._actuallyUploadDiscordFileToMxc = function(url, res) { throw new Error(`Not allowed to upload files during testing.\nURL: ${url}`) }
|
||||||
|
|
||||||
;(async () => {
|
;(async () => {
|
||||||
|
@ -88,7 +89,7 @@ file._actuallyUploadDiscordFileToMxc = function(url, res) { throw new Error(`Not
|
||||||
{url: "https://matrix.cadence.moe/_matrix/media/r0/download/cadence.moe/AYPpqXzVJvZdzMQJGjioIQBZ", to: "test/res/AYPpqXzVJvZdzMQJGjioIQBZ.png"},
|
{url: "https://matrix.cadence.moe/_matrix/media/r0/download/cadence.moe/AYPpqXzVJvZdzMQJGjioIQBZ", to: "test/res/AYPpqXzVJvZdzMQJGjioIQBZ.png"},
|
||||||
{url: "https://matrix.cadence.moe/_matrix/media/r0/download/cadence.moe/UVuzvpVUhqjiueMxYXJiFEAj", to: "test/res/UVuzvpVUhqjiueMxYXJiFEAj.png"},
|
{url: "https://matrix.cadence.moe/_matrix/media/r0/download/cadence.moe/UVuzvpVUhqjiueMxYXJiFEAj", to: "test/res/UVuzvpVUhqjiueMxYXJiFEAj.png"},
|
||||||
{url: "https://ezgif.com/images/format-demo/butterfly.gif", to: "test/res/butterfly.gif"},
|
{url: "https://ezgif.com/images/format-demo/butterfly.gif", to: "test/res/butterfly.gif"},
|
||||||
{url: "https://ezgif.com/images/format-demo/butterfly.gif", to: "test/res/butterfly.png"},
|
{url: "https://ezgif.com/images/format-demo/butterfly.png", to: "test/res/butterfly.png"},
|
||||||
])
|
])
|
||||||
}, {timeout: 60000})
|
}, {timeout: 60000})
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue