Skip to content

Commit 8c0f3d9

Browse files
committed
Better testing, improvement to the identifier regular expression. Misc. minor improvements.
1 parent fe1457c commit 8c0f3d9

File tree

9 files changed

+106
-117
lines changed

9 files changed

+106
-117
lines changed

src/__tests__/application.spec.js

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,17 @@ describe("Application startup and shutdown", () => {
110110
vi.restoreAllMocks();
111111
});
112112

113+
it("That login errors as swallowed.", () => {
114+
application.start(TOKEN);
115+
client.login = vi.fn().mockImplementationOnce(() => {
116+
console.log("WOT");
117+
new Promise((_, error) => {
118+
error("login failed");
119+
throw new Error("logg-in failed");
120+
});
121+
});
122+
});
123+
113124
it("That messages authored by other bots are ignored even if they contain attachments that could be prompted in respect of.", () => {
114125
application.start(TOKEN);
115126
discordInterfaceHarness.onClientReady();
@@ -237,7 +248,7 @@ describe("Application startup and shutdown", () => {
237248
await new Promise(resolve => setTimeout(resolve, 2000));
238249
discordInterfaceHarness.onMessageUpdate(userMessage, updatedUserMessage);
239250
expect(updatedUserMessage.channel.messages.delete).not.toHaveBeenCalled();
240-
251+
241252
application.stop();
242253
}
243254
);

src/__tests__/id-bot-message.spec.js

Lines changed: 70 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -6,114 +6,86 @@ import {Factory} from "../js/factory";
66
const factory = new Factory();
77

88
describe(
9-
"Emoji character counting in message content",
9+
"Emoji, custom-emoji and image-identifier counting..",
1010
() => [
11-
["", 0, 0],
12-
[" ", 0, 0],
13-
["\u{0023}", 0, 0],
14-
["\u{0030}", 0, 0],
15-
["\u{0039}", 0, 0],
16-
["\u{00AE}", 0, 0],
17-
["🫸", 1, 0],
18-
["🫸🫸", 2, 0],
19-
[" 🫸🫸", 2, 0],
20-
["🫸🫸 ", 2, 0],
21-
[" 🫸🫸 ", 2, 0],
22-
["<:blah:345802398509358903485093>🫸", 1, 1],
23-
["<:name:1245079798410121307>", 0, 1],
24-
["<a:name:1245079798410121307>", 0, 1],
25-
["<:n:1245079798410121307>", 0, 1],
26-
["<a:n:1245079798410121307>", 0, 1],
27-
["<:name:1>", 0, 1],
28-
["<a:name:1>", 0, 1],
29-
["<:n:1>", 0, 1],
30-
["<a:n:1>", 0, 1],
31-
["<a:-:a>", 0, 0],
32-
["<a:n:a>", 0, 0],
33-
["<b:n:1>", 0, 0],
34-
["<ab:n:1>", 0, 0],
35-
["<ba:n:1>", 0, 0],
36-
["<::1245079798410121307>", 0, 0],
37-
["<a::1245079798410121307>", 0, 0],
38-
["<::1>", 0, 0],
39-
["<a::1>", 0, 0],
40-
["<:name:>", 0, 0],
41-
["<a:name:>", 0, 0],
42-
["<:n:>", 0, 0],
43-
["<a:n:>", 0, 0],
44-
[":name:1245079798410121307>", 0, 0],
45-
["a:name:1245079798410121307>", 0, 0],
46-
[":n:1245079798410121307>", 0, 0],
47-
["a:n:1245079798410121307>", 0, 0],
48-
[":name:1>", 0, 0],
49-
["a:name:1>", 0, 0],
50-
[":n:1>", 0, 0],
51-
["a:n:1>", 0, 0],
52-
["<:name:1245079798410121307", 0, 0],
53-
["<a:name:1245079798410121307", 0, 0],
54-
["<:n:1245079798410121307", 0, 0],
55-
["<a:n:1245079798410121307", 0, 0],
56-
["<:name:1", 0, 0],
57-
["<a:name:1", 0, 0],
58-
["<:n:1", 0, 0],
59-
["<a:n:1", 0, 0],
60-
[":name:1245079798410121307", 0, 0],
61-
["a:name:1245079798410121307", 0, 0],
62-
[":n:1245079798410121307", 0, 0],
63-
["a:n:1245079798410121307", 0, 0],
64-
[":name:1", 0, 0],
65-
["a:name:1", 0, 0],
66-
[":n:1", 0, 0],
67-
["a:n:1", 0, 0],
68-
["🫸<:id:3458>", 1, 1],
69-
["🫸<:custom_emoji:3458>🫸", 2, 1],
70-
["<:custom:3454458>🫸<:fish:3453453453458>🫸<:something:3458>", 2, 3],
71-
].forEach(([messageContent, expectedEmojiCount, expectedCustomEmojiCount]) =>
11+
["", 0, 0, 0],
12+
[" ID:", 0, 0, 0],
13+
// ["\u{0023}ID: a", 0, 0, 0],
14+
["\u{0030}ID: a", 0, 0, 0],
15+
["\u{0039}id: ", 0, 0, 0],
16+
["\u{00AE}iD: a", 0, 0, 0],
17+
["ID: a🫸", 1, 0, 1],
18+
["ID: 🫸 ID: 🫸", 2, 0, 0],
19+
["ID: a🫸 ID: a🫸", 2, 0, 2],
20+
[" 🫸🫸ID: ", 2, 0, 0],
21+
["🫸ID: x🫸 ", 2, 0, 1],
22+
[" 🫸ID: 🫸ID: ", 2, 0, 0],
23+
["<:blah:345802398509358903485093> ID: a🫸", 1, 1, 1],
24+
["<:name:1245079798410121307>ID: ", 0, 1, 0],
25+
["ID: something <a:name:1245079798410121307>", 0, 1, 1],
26+
["ID: s <:n:1245079798410121307> ID: d", 0, 1, 2],
27+
["<a:n:1245079798410121307>WID: ", 0, 1, 0],
28+
["<:name:1>", 0, 1, 0],
29+
["<a:name:1>", 0, 1, 0],
30+
["<:n:1>", 0, 1, 0],
31+
["<a:n:1>", 0, 1, 0],
32+
["<a:-:a>", 0, 0, 0],
33+
["<a:n:a>", 0, 0, 0],
34+
["<b:n:1>", 0, 0, 0],
35+
["<ab:n:1>", 0, 0, 0],
36+
["<ba:n:1>", 0, 0, 0],
37+
["<::1245079798410121307>", 0, 0, 0],
38+
["<a::1245079798410121307>ID: abcsID: abcd.", 0, 0, 1],
39+
["<::1>", 0, 0, 0],
40+
["<a::1>", 0, 0, 0],
41+
["<:name:>", 0, 0, 0],
42+
["<a:name:>", 0, 0, 0],
43+
["<:n:>", 0, 0, 0],
44+
["<a:n:>", 0, 0, 0],
45+
[":name:1245079798410121307>", 0, 0, 0],
46+
["a:name:1245079798410121307>", 0, 0, 0],
47+
[":n:1245079798410121307>", 0, 0, 0],
48+
["a:n:1245079798410121307>", 0, 0, 0],
49+
[":name:1>", 0, 0, 0],
50+
["a:name:1>", 0, 0, 0],
51+
[":n:1>", 0, 0, 0],
52+
["a:n:1>", 0, 0, 0],
53+
["<:name:1245079798410121307", 0, 0, 0],
54+
["<a:name:1245079798410121307", 0, 0, 0],
55+
["<:n:1245079798410121307", 0, 0, 0],
56+
["<a:n:1245079798410121307", 0, 0, 0],
57+
["<:name:1", 0, 0, 0],
58+
["<a:name:1", 0, 0, 0],
59+
["<:n:1", 0, 0, 0],
60+
["<a:n:1", 0, 0, 0],
61+
[":name:1245079798410121307", 0, 0, 0],
62+
["a:name:1245079798410121307", 0, 0, 0],
63+
[":n:1245079798410121307", 0, 0, 0],
64+
["a:n:1245079798410121307", 0, 0, 0],
65+
[":name:1", 0, 0, 0],
66+
["a:name:1 ID: abcs.ID: abcd.", 0, 0, 2],
67+
[":n:1", 0, 0, 0],
68+
["a:n:1", 0, 0, 0],
69+
["🫸<:id:3458>", 1, 1, 0],
70+
["🫸<:custom_emoji:3458>🫸", 2, 1, 0],
71+
["<:custom:3454458>🫸<:fish:3453453453458>🫸<:something:3458>", 2, 3, 0],
72+
[`<:custom:3454458> ID: a custom emoji ID: whoopee
73+
🐈ID: an emoji of a cat. ID: an emoji of a castle
74+
75+
🏰`, 2, 1, 4],
76+
].forEach(([content, expectedEmojiCount, expectedCustomEmojiCount, expectedImageIdCount]) =>
7277
it(
73-
`That "${messageContent}" contains ${expectedEmojiCount} emoji characters and ${expectedCustomEmojiCount} custom emoji references.`,
78+
`That "${content}" contains ${expectedEmojiCount} emoji characters and ${expectedCustomEmojiCount} custom emoji references and ${expectedImageIdCount} image ids.`,
7479
() => {
7580
const imageIdStats = factory
7681
.createIdBotMessage({
7782
id: createUuid(),
7883
attachments: new Map(),
79-
content: messageContent
84+
content
8085
}).imageIdStats;
8186
expect(imageIdStats.emojiCount).toBe(expectedEmojiCount);
8287
expect(imageIdStats.customEmojiCount).toBe(expectedCustomEmojiCount);
83-
}
84-
)
85-
)
86-
);
87-
88-
89-
describe(
90-
"Image ID counting in message content",
91-
() => [
92-
["", 0],
93-
[" ", 0],
94-
["ID:", 0],
95-
["ID: a", 1],
96-
["ID: ab", 1],
97-
["ID: abc", 1],
98-
["ID: abcd", 1],
99-
["ID: abcd. ID: abcd.", 2],
100-
["ID: abcd. ID: a", 2],
101-
["ID: aID: abcd.", 1],
102-
["ID: abcsID: abcd.", 1],
103-
["ID: abcs. ID: abcd.", 2],
104-
["ID: abcs ID: abcd. ID: abcd", 3]
105-
].forEach(([messageContent, expectedImageIdCount]) =>
106-
it(
107-
`That "${messageContent}" contains ${expectedImageIdCount} identifiers`,
108-
() => {
109-
const discordMessage = factory
110-
.createIdBotMessage({
111-
id: createUuid(),
112-
attachments: new Map(),
113-
content: messageContent
114-
});
115-
116-
expect(discordMessage.imageIdStats.imageIdentifierCount).toBe(expectedImageIdCount);
88+
expect(imageIdStats.imageIdentifierCount).toBe(expectedImageIdCount);
11789
}
11890
)
11991
)

src/js/max-stale-cache-manager.js renamed to src/js/cache-max-stale-manager.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
class MaxStaleCacheManager {
1+
class CacheMaxStaleManager {
22

33
/**
44
* @type {Cache}
@@ -98,5 +98,5 @@ class MaxStaleCacheManager {
9898
}
9999

100100
export {
101-
MaxStaleCacheManager
101+
CacheMaxStaleManager
102102
};

src/js/cache.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ class Cache {
107107
}
108108

109109
toString() {
110-
return `Cache(ktv=${this.#keyToValue}, ktm=${this.#keyToMetaData}, )`;
110+
return `Cache(ktv=${[...this.#keyToValue.entries()]}, ktm=${[...this.#keyToMetaData.entries()]}, )`;
111111
}
112112
}
113113

src/js/durations-ms.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ const SECONDS_PER_MINUTE = 60;
33
const MINUTES_PER_HOUR = 60;
44
const HOURS_PER_DAY = 24;
55

6+
// noinspection PointlessArithmeticExpressionJS
67
const ONE_SECOND_MILLI_SECONDS = 1 * MS_PER_SECOND;
78
const ONE_MINUTE_MILLI_SECONDS = ONE_SECOND_MILLI_SECONDS * SECONDS_PER_MINUTE;
89
const ONE_HOUR_MILLI_SECONDS = ONE_MINUTE_MILLI_SECONDS * MINUTES_PER_HOUR;

src/js/factory.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {Client} from "discord.js";
88
import {GatewayIntentBits} from "discord-api-types/v10";
99
import {DiscordInterface} from "./discord-interface.js";
1010
import {Application} from "./application.js";
11-
import {MaxStaleCacheManager} from "./max-stale-cache-manager.js";
11+
import {CacheMaxStaleManager} from "./cache-max-stale-manager.js";
1212

1313
const CLIENT_OPTIONS = {
1414
intents: [
@@ -29,10 +29,10 @@ class Factory {
2929
* @param {Cache} cache
3030
* @param {number} tickIntervalDurationMilliSeconds
3131
* @param {number} maxStaleLifetimeMilliSeconds
32-
* @returns {MaxStaleCacheManager}
32+
* @returns {CacheMaxStaleManager}
3333
*/
3434
createCacheExpirator(cache, tickIntervalDurationMilliSeconds = 100, maxStaleLifetimeMilliSeconds = undefined) {
35-
return new MaxStaleCacheManager(
35+
return new CacheMaxStaleManager(
3636
cache, this.createLogger("MaxStaleCacheManager"),
3737
this,
3838
tickIntervalDurationMilliSeconds,

src/js/id-bot-message.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ class IdBotMessage {
2020
/**
2121
* @type RegExp
2222
*/
23-
#MESSAGE_ID_VALIDATING_REGEXP = /(?<=(^|\s|\W)ID:\s*)(\w+)(?!\WID:)/svg;
23+
#MESSAGE_ID_REGEXP = /(?<=(^|\s|\W)ID:\s*)(\w+)(?!\WID:)/svg;
2424

2525
/**
2626
* @type RegExp
@@ -41,6 +41,7 @@ class IdBotMessage {
4141
}
4242

4343
get referencedMessageId() {
44+
// noinspection JSUnresolvedReference
4445
return this.#discordJsMessage?.reference?.messageId;
4546
}
4647

@@ -118,7 +119,7 @@ class IdBotMessage {
118119
const contentStrippedOfCustomEmoji = content.replaceAll(this.#CUSTOM_EMOJI_REGEX, "");
119120
const numberOfEmoji = numberOfEmojiContained(contentStrippedOfCustomEmoji);
120121

121-
const idMatches = [...content.matchAll(this.#MESSAGE_ID_VALIDATING_REGEXP)];
122+
const idMatches = [...content.matchAll(this.#MESSAGE_ID_REGEXP)];
122123

123124
this.#imageIdStats = factory.createImageIdStats(
124125
[...discordJsMessage.attachments.values()]

src/js/id-bot.js

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,16 @@ class IdBot {
1414
#discordInterface;
1515

1616
/**
17+
* A cache that maps: the original message id to reminder message id.
18+
*
1719
* @type Cache
1820
*/
1921
#cache;
2022

2123
/**
22-
* @type MaxStaleCacheManager
24+
* @type CacheMaxStaleManager
2325
*/
24-
#maxStaleCacheManager;
26+
#cacheMaxStaleManager;
2527

2628
/**
2729
* @type Logger
@@ -55,14 +57,15 @@ class IdBot {
5557
if (replyId) {
5658
this.#deleteChannelMessage(message.channel, replyId);
5759
this.#cache.remove(messageId);
60+
this.#logger.debug(this.#cache);
5861
} else {
5962
this.#logger.warn(`${message.toIdString()} has no known replies`);
6063
}
6164
}
6265

6366
#onClientReady() {
6467
this.#logger.info(`Ready`);
65-
this.#maxStaleCacheManager.start();
68+
this.#cacheMaxStaleManager.start();
6669
}
6770

6871
/**
@@ -95,6 +98,7 @@ class IdBot {
9598
this.#logger.debug(`${message.toIdString()} is our new reminder reply to ${referencedMessageId}."`);
9699

97100
this.#cache.set(referencedMessageId, message.id);
101+
this.#logger.debug(this.#cache);
98102
}
99103
}
100104
};
@@ -112,9 +116,9 @@ class IdBot {
112116
const imageIdStats = updatedMessage.imageIdStats;
113117

114118
if (!imageIdStats.isCorrectlyIdentified) {
115-
this.#deleteOurReplyTo(updatedMessage);
116119
const replyMessageContent = this.#reminderMessage(imageIdStats);
117120
this.#logger.debug(`${updatedMessage.toIdString()} not correctly identified, replying with "${replyMessageContent}"`);
121+
this.#deleteOurReplyTo(updatedMessage);
118122
this.#discordInterface.replyTo(updatedMessage, replyMessageContent);
119123
} else {
120124
this.#deleteOurReplyTo(updatedMessage);
@@ -136,18 +140,18 @@ class IdBot {
136140

137141
/**
138142
* @param {Cache} cache
139-
* @param {MaxStaleCacheManager} maxStaleCacheManager
143+
* @param {CacheMaxStaleManager} cacheMaxStaleManager
140144
* @param {DiscordInterface} discordInterface
141145
* @param {Logger} logger
142146
*/
143147
constructor(
144148
cache,
145-
maxStaleCacheManager,
149+
cacheMaxStaleManager,
146150
discordInterface,
147151
logger
148152
) {
149153
this.#cache = cache;
150-
this.#maxStaleCacheManager = maxStaleCacheManager;
154+
this.#cacheMaxStaleManager = cacheMaxStaleManager;
151155
this.#discordInterface = discordInterface
152156
.setClientReadyHandler(this.#onClientReady.bind(this))
153157
.setMessageCreateHandler(this.#onMessageCreate.bind(this))
@@ -165,7 +169,7 @@ class IdBot {
165169

166170
close() {
167171
this.#discordInterface.close();
168-
this.#maxStaleCacheManager.stop();
172+
this.#cacheMaxStaleManager.stop();
169173
}
170174
}
171175

src/js/logger.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,12 @@ class Logger {
3535

3636
/**
3737
* @param {*} message
38-
* @param {*} [error]
38+
* @param {Error} [error]
3939
*/
4040
error = ((message, error) => {
4141
this.#console.error(this.#format(message, "ERROR"));
4242
if (error) {
43-
this.#console.error(error);
43+
this.#console.error(this.#format(error, "ERROR"));
4444
}
4545
});
4646

0 commit comments

Comments
 (0)