2023-06-30 14:05:57 +00:00
|
|
|
import {
|
|
|
|
assertEquals,
|
|
|
|
assertInstanceOf,
|
|
|
|
assertNotEquals,
|
|
|
|
fail,
|
|
|
|
} from "https://deno.land/std@0.176.0/testing/asserts.ts";
|
|
|
|
import {
|
|
|
|
blobToBase64,
|
|
|
|
decryptNostrEvent,
|
|
|
|
InMemoryAccountContext,
|
|
|
|
NostrEvent,
|
|
|
|
NostrKind,
|
|
|
|
prepareNormalNostrEvent,
|
2023-08-28 17:58:05 +00:00
|
|
|
} from "./lib/nostr-ts/nostr.ts";
|
2023-06-30 14:05:57 +00:00
|
|
|
import {
|
|
|
|
computeThreads,
|
2023-07-13 09:06:35 +00:00
|
|
|
getTags,
|
2023-06-30 14:05:57 +00:00
|
|
|
groupImageEvents,
|
2023-07-15 05:58:03 +00:00
|
|
|
Parsed_Event,
|
|
|
|
parsedTagsEvent,
|
2023-06-30 14:05:57 +00:00
|
|
|
prepareNostrImageEvents,
|
|
|
|
prepareReplyEvent,
|
|
|
|
reassembleBase64ImageFromEvents,
|
|
|
|
} from "./nostr.ts";
|
|
|
|
import { LamportTime } from "./time.ts";
|
2023-08-28 17:58:05 +00:00
|
|
|
import { PrivateKey, PublicKey } from "./lib/nostr-ts/key.ts";
|
|
|
|
import { utf8Decode } from "./lib/nostr-ts/ende.ts";
|
2023-06-30 14:05:57 +00:00
|
|
|
|
|
|
|
Deno.test("prepareNostrImageEvents", async (t) => {
|
|
|
|
const pri = PrivateKey.Generate();
|
2023-07-11 09:19:57 +00:00
|
|
|
const pub = pri.toPublicKey();
|
2023-06-30 14:05:57 +00:00
|
|
|
|
|
|
|
let randomData = new Uint8Array(1024 * 48); // 48KB raw data
|
|
|
|
for (let i = 0; i < randomData.length; i++) {
|
|
|
|
randomData.fill(Math.floor(Math.random() * 128), i); // https://en.wikipedia.org/wiki/UTF-8
|
|
|
|
}
|
|
|
|
let randomStr = utf8Decode(randomData);
|
|
|
|
|
|
|
|
const blob = new Blob([randomStr]);
|
|
|
|
const imgEvents = await prepareNostrImageEvents(
|
|
|
|
InMemoryAccountContext.New(pri),
|
|
|
|
pub,
|
|
|
|
blob,
|
|
|
|
NostrKind.DIRECT_MESSAGE,
|
|
|
|
);
|
|
|
|
if (imgEvents instanceof Error) {
|
|
|
|
fail(imgEvents.message);
|
|
|
|
}
|
|
|
|
const [events, _] = imgEvents;
|
|
|
|
await t.step("full", async () => {
|
|
|
|
const decryptedEvents = [];
|
|
|
|
for (const e of events) {
|
2023-07-11 09:19:57 +00:00
|
|
|
const decryptedEvent = await decryptNostrEvent(e, InMemoryAccountContext.New(pri), pub.hex);
|
2023-06-30 14:05:57 +00:00
|
|
|
if (decryptedEvent instanceof Error) {
|
|
|
|
fail(decryptedEvent.message);
|
|
|
|
}
|
|
|
|
decryptedEvents.push(decryptedEvent);
|
|
|
|
}
|
|
|
|
const content = reassembleBase64ImageFromEvents(decryptedEvents);
|
|
|
|
if (content instanceof Error) {
|
|
|
|
fail(content.message);
|
|
|
|
}
|
|
|
|
assertEquals(await blobToBase64(blob), content);
|
|
|
|
});
|
|
|
|
await t.step("partial, should fail", async () => {
|
|
|
|
const decryptedEvents = [];
|
|
|
|
const partialEvents = events.slice(0, 1); // not enough events
|
|
|
|
for (const e of partialEvents) {
|
2023-07-11 09:19:57 +00:00
|
|
|
const decryptedEvent = await decryptNostrEvent(e, InMemoryAccountContext.New(pri), pub.hex);
|
2023-06-30 14:05:57 +00:00
|
|
|
if (decryptedEvent instanceof Error) {
|
|
|
|
fail(decryptedEvent.message);
|
|
|
|
}
|
|
|
|
decryptedEvents.push(decryptedEvent);
|
|
|
|
}
|
|
|
|
const content = reassembleBase64ImageFromEvents(decryptedEvents);
|
|
|
|
assertInstanceOf(content, Error);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
Deno.test("groupImageEvents", async () => {
|
|
|
|
const pri = PrivateKey.Generate();
|
2023-07-11 09:19:57 +00:00
|
|
|
const pub = pri.toPublicKey();
|
2023-06-30 14:05:57 +00:00
|
|
|
|
|
|
|
let randomData = new Uint8Array(1024 * 17);
|
|
|
|
for (let i = 0; i < randomData.length; i++) {
|
|
|
|
randomData.fill(Math.floor(Math.random() * 128), i); // https://en.wikipedia.org/wiki/UTF-8
|
|
|
|
}
|
|
|
|
let randomStr = utf8Decode(randomData);
|
|
|
|
|
|
|
|
const blob = new Blob([randomStr]);
|
|
|
|
const imgEvents1 = await prepareNostrImageEvents(
|
|
|
|
InMemoryAccountContext.New(pri),
|
|
|
|
pub,
|
|
|
|
blob,
|
|
|
|
NostrKind.DIRECT_MESSAGE,
|
|
|
|
);
|
|
|
|
if (imgEvents1 instanceof Error) {
|
|
|
|
fail(imgEvents1.message);
|
|
|
|
}
|
|
|
|
const [events1, id1] = imgEvents1;
|
|
|
|
const imgEvents2 = await prepareNostrImageEvents(
|
|
|
|
InMemoryAccountContext.New(pri),
|
|
|
|
pub,
|
|
|
|
blob,
|
|
|
|
NostrKind.DIRECT_MESSAGE,
|
|
|
|
);
|
|
|
|
if (imgEvents2 instanceof Error) {
|
|
|
|
fail(imgEvents2.message);
|
|
|
|
}
|
|
|
|
const [events2, id2] = imgEvents2;
|
2023-07-16 15:04:23 +00:00
|
|
|
const groups = groupImageEvents(
|
|
|
|
events1.concat(events2).map((e): Parsed_Event => ({
|
|
|
|
...e,
|
|
|
|
kind: e.kind as NostrKind.DIRECT_MESSAGE,
|
|
|
|
publicKey: PublicKey.FromHex(e.pubkey) as PublicKey,
|
|
|
|
parsedTags: getTags(e),
|
|
|
|
})),
|
|
|
|
);
|
2023-06-30 14:05:57 +00:00
|
|
|
assertEquals(groups.size, 2);
|
|
|
|
|
2023-07-16 15:04:23 +00:00
|
|
|
const group1 = groups.get(id1)?.map((e): NostrEvent => ({
|
|
|
|
content: e.content,
|
|
|
|
created_at: e.created_at,
|
|
|
|
id: e.id,
|
|
|
|
kind: e.kind,
|
|
|
|
pubkey: e.pubkey,
|
|
|
|
sig: e.sig,
|
|
|
|
tags: e.tags,
|
|
|
|
}));
|
2023-06-30 14:05:57 +00:00
|
|
|
assertNotEquals(group1, undefined);
|
|
|
|
assertEquals(group1, events1);
|
|
|
|
|
2023-07-16 15:04:23 +00:00
|
|
|
const group2 = groups.get(id2)?.map((e): NostrEvent => ({
|
|
|
|
content: e.content,
|
|
|
|
created_at: e.created_at,
|
|
|
|
id: e.id,
|
|
|
|
kind: e.kind,
|
|
|
|
pubkey: e.pubkey,
|
|
|
|
sig: e.sig,
|
|
|
|
tags: e.tags,
|
|
|
|
}));
|
2023-06-30 14:05:57 +00:00
|
|
|
assertNotEquals(group2, undefined);
|
|
|
|
assertEquals(group2, events2);
|
|
|
|
});
|
|
|
|
|
|
|
|
Deno.test("Generate reply event", async () => {
|
|
|
|
const userAPrivateKey = PrivateKey.Generate();
|
|
|
|
const userBPrivateKey = PrivateKey.Generate();
|
|
|
|
const userAContext = InMemoryAccountContext.New(userAPrivateKey);
|
|
|
|
|
|
|
|
const message1 = await prepareNormalNostrEvent(
|
|
|
|
userAContext,
|
|
|
|
NostrKind.DIRECT_MESSAGE,
|
|
|
|
[],
|
|
|
|
"text message 1",
|
|
|
|
);
|
|
|
|
|
|
|
|
const replyMessage1WithText = await prepareReplyEvent(
|
|
|
|
userAContext,
|
|
|
|
message1,
|
|
|
|
[],
|
|
|
|
"aaaa",
|
|
|
|
) as NostrEvent;
|
|
|
|
|
|
|
|
assertEquals(replyMessage1WithText.kind, message1.kind);
|
2023-07-01 14:51:28 +00:00
|
|
|
assertEquals(replyMessage1WithText.pubkey, userAPrivateKey.toPublicKey().hex);
|
2023-06-30 14:05:57 +00:00
|
|
|
assertEquals(replyMessage1WithText.tags, [[
|
|
|
|
"e",
|
|
|
|
message1.id,
|
|
|
|
"",
|
|
|
|
"reply",
|
|
|
|
]]);
|
|
|
|
});
|
|
|
|
|
|
|
|
Deno.test("Group reply messages", async (t) => {
|
|
|
|
const userAPrivateKey = PrivateKey.Generate();
|
|
|
|
const userBPrivateKey = PrivateKey.Generate();
|
|
|
|
const userAContext = InMemoryAccountContext.New(userAPrivateKey);
|
|
|
|
const userBContext = InMemoryAccountContext.New(userBPrivateKey);
|
|
|
|
const lamport = new LamportTime(0);
|
|
|
|
|
|
|
|
await t.step("has reply", async () => {
|
|
|
|
const message1 = await prepareNormalNostrEvent(
|
|
|
|
userAContext,
|
|
|
|
NostrKind.DIRECT_MESSAGE,
|
|
|
|
[
|
|
|
|
["lamport", String(lamport.now())],
|
|
|
|
],
|
|
|
|
"text message 1",
|
|
|
|
);
|
|
|
|
const message2 = await prepareReplyEvent(
|
|
|
|
userAContext,
|
|
|
|
message1,
|
|
|
|
[["lamport", String(lamport.now())]],
|
|
|
|
"text message 2, text message 1's reply",
|
|
|
|
);
|
|
|
|
const message3 = await prepareReplyEvent(
|
|
|
|
userBContext,
|
|
|
|
message1,
|
|
|
|
[["lamport", String(lamport.now())]],
|
|
|
|
"text message 3, text message 1's reply",
|
|
|
|
) as NostrEvent;
|
|
|
|
const message4 = await prepareReplyEvent(
|
|
|
|
userAContext,
|
|
|
|
message3,
|
|
|
|
[["lamport", String(lamport.now())]],
|
|
|
|
"text message 4, text message 3's reply",
|
|
|
|
);
|
|
|
|
const message5 = await prepareReplyEvent(
|
|
|
|
userBContext,
|
|
|
|
message3,
|
|
|
|
[["lamport", String(lamport.now())]],
|
|
|
|
"text message 5, text message 3's reply",
|
|
|
|
) as NostrEvent;
|
|
|
|
|
2023-07-01 14:51:28 +00:00
|
|
|
const message6LeadEventID = PrivateKey.Generate().hex;
|
2023-06-30 14:05:57 +00:00
|
|
|
const message6 = await prepareNormalNostrEvent(
|
|
|
|
userBContext,
|
|
|
|
NostrKind.DIRECT_MESSAGE,
|
|
|
|
[
|
|
|
|
[
|
|
|
|
"image",
|
|
|
|
message6LeadEventID,
|
|
|
|
"3",
|
|
|
|
"0",
|
|
|
|
],
|
|
|
|
["lamport", String(lamport.now())],
|
|
|
|
],
|
|
|
|
"image message 6",
|
|
|
|
);
|
|
|
|
const message7 = await prepareNormalNostrEvent(
|
|
|
|
userBContext,
|
|
|
|
NostrKind.DIRECT_MESSAGE,
|
|
|
|
[
|
|
|
|
[
|
|
|
|
"image",
|
|
|
|
message6LeadEventID,
|
|
|
|
"3",
|
|
|
|
"1",
|
|
|
|
],
|
|
|
|
["lamport", String(lamport.now())],
|
|
|
|
],
|
|
|
|
"image message 7",
|
|
|
|
);
|
|
|
|
const message8 = await prepareNormalNostrEvent(
|
|
|
|
userBContext,
|
|
|
|
NostrKind.DIRECT_MESSAGE,
|
|
|
|
[
|
|
|
|
[
|
|
|
|
"image",
|
|
|
|
message6LeadEventID,
|
|
|
|
"3",
|
|
|
|
"2",
|
|
|
|
],
|
|
|
|
["lamport", String(lamport.now())],
|
|
|
|
],
|
|
|
|
"image message 8",
|
|
|
|
);
|
2023-07-01 14:51:28 +00:00
|
|
|
const message9LeadEventID = PrivateKey.Generate().hex;
|
2023-06-30 14:05:57 +00:00
|
|
|
const message9 = await prepareReplyEvent(
|
|
|
|
userAContext,
|
|
|
|
message6,
|
|
|
|
[
|
|
|
|
[
|
|
|
|
"image",
|
|
|
|
message9LeadEventID,
|
|
|
|
"3",
|
|
|
|
"0",
|
|
|
|
],
|
|
|
|
["lamport", String(lamport.now())],
|
|
|
|
],
|
|
|
|
"image message 9, image message 6's reply",
|
|
|
|
);
|
|
|
|
const message10 = await prepareReplyEvent(
|
|
|
|
userAContext,
|
|
|
|
message6,
|
|
|
|
[
|
|
|
|
[
|
|
|
|
"image",
|
|
|
|
message9LeadEventID,
|
|
|
|
"3",
|
|
|
|
"1",
|
|
|
|
],
|
|
|
|
["lamport", String(lamport.now())],
|
|
|
|
],
|
|
|
|
"image message 10, image message 6's reply",
|
|
|
|
);
|
|
|
|
const message11 = await prepareReplyEvent(
|
|
|
|
userAContext,
|
|
|
|
message6,
|
|
|
|
[
|
|
|
|
[
|
|
|
|
"image",
|
|
|
|
message9LeadEventID,
|
|
|
|
"3",
|
|
|
|
"2",
|
|
|
|
],
|
|
|
|
["lamport", String(lamport.now())],
|
|
|
|
],
|
|
|
|
"image message 11, image message 6's reply",
|
|
|
|
);
|
|
|
|
const message12 = await prepareReplyEvent(
|
|
|
|
userAContext,
|
|
|
|
message5,
|
|
|
|
[
|
|
|
|
["lamport", String(lamport.now())],
|
|
|
|
],
|
|
|
|
"text message 12, text message 5's reply",
|
|
|
|
);
|
|
|
|
|
2023-07-13 09:06:35 +00:00
|
|
|
const testEvent = [
|
2023-06-30 14:05:57 +00:00
|
|
|
message1,
|
|
|
|
message2 as NostrEvent,
|
|
|
|
message3 as NostrEvent,
|
|
|
|
message4 as NostrEvent,
|
|
|
|
message5 as NostrEvent,
|
|
|
|
message6,
|
|
|
|
message7,
|
|
|
|
message8,
|
|
|
|
message9 as NostrEvent,
|
|
|
|
message10 as NostrEvent,
|
|
|
|
message11 as NostrEvent,
|
|
|
|
message12 as NostrEvent,
|
2023-07-15 05:58:03 +00:00
|
|
|
].map((e): parsedTagsEvent => {
|
2023-07-13 09:06:35 +00:00
|
|
|
return {
|
|
|
|
...e,
|
|
|
|
parsedTags: getTags(e),
|
|
|
|
};
|
|
|
|
});
|
2023-06-30 14:05:57 +00:00
|
|
|
|
|
|
|
const validResult = new Set<Set<NostrEvent>>([
|
|
|
|
new Set([
|
|
|
|
message1 as NostrEvent,
|
|
|
|
message2 as NostrEvent,
|
|
|
|
message3 as NostrEvent,
|
|
|
|
message4 as NostrEvent,
|
|
|
|
message5 as NostrEvent,
|
|
|
|
message12 as NostrEvent,
|
2023-07-15 05:58:03 +00:00
|
|
|
].map((e): parsedTagsEvent => {
|
2023-07-13 09:06:35 +00:00
|
|
|
return {
|
|
|
|
...e,
|
|
|
|
parsedTags: getTags(e),
|
|
|
|
};
|
|
|
|
})),
|
2023-06-30 14:05:57 +00:00
|
|
|
new Set([
|
|
|
|
message6 as NostrEvent,
|
|
|
|
message7 as NostrEvent,
|
|
|
|
message8 as NostrEvent,
|
|
|
|
message9 as NostrEvent,
|
|
|
|
message10 as NostrEvent,
|
|
|
|
message11 as NostrEvent,
|
2023-07-15 05:58:03 +00:00
|
|
|
].map((e): parsedTagsEvent => {
|
2023-07-13 09:06:35 +00:00
|
|
|
return {
|
|
|
|
...e,
|
|
|
|
parsedTags: getTags(e),
|
|
|
|
};
|
|
|
|
})),
|
2023-06-30 14:05:57 +00:00
|
|
|
]);
|
|
|
|
|
|
|
|
for (let i = 0; i < 10; i++) {
|
|
|
|
const result = computeThreads(testEvent.sort((a, b) => 0.5 - Math.random()));
|
|
|
|
const res = new Set(result.map((r) => new Set(r)));
|
|
|
|
assertEquals(res, validResult);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
await t.step("no reply", async () => {
|
|
|
|
const message1 = await prepareNormalNostrEvent(
|
|
|
|
userAContext,
|
|
|
|
NostrKind.DIRECT_MESSAGE,
|
|
|
|
[],
|
|
|
|
"text message 1",
|
|
|
|
);
|
|
|
|
|
2023-07-01 14:51:28 +00:00
|
|
|
const message2LeadEventID = PrivateKey.Generate().hex;
|
2023-06-30 14:05:57 +00:00
|
|
|
const message2 = await prepareNormalNostrEvent(
|
|
|
|
userBContext,
|
|
|
|
NostrKind.DIRECT_MESSAGE,
|
|
|
|
[
|
|
|
|
[
|
|
|
|
"image",
|
|
|
|
message2LeadEventID,
|
|
|
|
"3",
|
|
|
|
"0",
|
|
|
|
],
|
|
|
|
],
|
|
|
|
"text message 2",
|
|
|
|
);
|
|
|
|
const message3 = await prepareNormalNostrEvent(
|
|
|
|
userBContext,
|
|
|
|
NostrKind.DIRECT_MESSAGE,
|
|
|
|
[
|
|
|
|
[
|
|
|
|
"image",
|
|
|
|
message2LeadEventID,
|
|
|
|
"3",
|
|
|
|
"1",
|
|
|
|
],
|
|
|
|
],
|
|
|
|
"text message 3",
|
|
|
|
);
|
|
|
|
const message4 = await prepareNormalNostrEvent(
|
|
|
|
userBContext,
|
|
|
|
NostrKind.DIRECT_MESSAGE,
|
|
|
|
[
|
|
|
|
[
|
|
|
|
"image",
|
|
|
|
message2LeadEventID,
|
|
|
|
"3",
|
|
|
|
"2",
|
|
|
|
],
|
|
|
|
],
|
|
|
|
"text message 4",
|
|
|
|
);
|
|
|
|
|
|
|
|
const testEvent = [
|
|
|
|
message1,
|
|
|
|
message2,
|
|
|
|
message3,
|
|
|
|
message4,
|
2023-07-15 05:58:03 +00:00
|
|
|
].map((e): parsedTagsEvent => {
|
2023-07-13 09:06:35 +00:00
|
|
|
return {
|
|
|
|
...e,
|
|
|
|
parsedTags: getTags(e),
|
|
|
|
};
|
|
|
|
});
|
2023-06-30 14:05:57 +00:00
|
|
|
|
|
|
|
const validResult = new Set([
|
|
|
|
new Set([
|
|
|
|
message1,
|
2023-07-15 05:58:03 +00:00
|
|
|
].map((e): parsedTagsEvent => {
|
2023-07-13 09:06:35 +00:00
|
|
|
return {
|
|
|
|
...e,
|
|
|
|
parsedTags: getTags(e),
|
|
|
|
};
|
|
|
|
})),
|
2023-06-30 14:05:57 +00:00
|
|
|
new Set([
|
|
|
|
message2,
|
|
|
|
message3,
|
|
|
|
message4,
|
2023-07-15 05:58:03 +00:00
|
|
|
].map((e): parsedTagsEvent => {
|
2023-07-13 09:06:35 +00:00
|
|
|
return {
|
|
|
|
...e,
|
|
|
|
parsedTags: getTags(e),
|
|
|
|
};
|
|
|
|
})),
|
2023-06-30 14:05:57 +00:00
|
|
|
]);
|
|
|
|
|
|
|
|
for (let i = 0; i < 10; i++) {
|
|
|
|
const result = computeThreads(testEvent.sort((a, b) => 0.5 - Math.random()));
|
|
|
|
const res = new Set(result.map((r) => new Set(r)));
|
|
|
|
assertEquals(res, validResult);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
await t.step("has reply but no root", async () => {
|
|
|
|
const message1 = await prepareNormalNostrEvent(
|
|
|
|
userAContext,
|
|
|
|
NostrKind.DIRECT_MESSAGE,
|
|
|
|
[],
|
|
|
|
"text message 1",
|
|
|
|
);
|
|
|
|
|
|
|
|
const notUsed = await prepareNormalNostrEvent(
|
|
|
|
userAContext,
|
|
|
|
NostrKind.DIRECT_MESSAGE,
|
|
|
|
[],
|
|
|
|
"not used",
|
|
|
|
);
|
|
|
|
|
|
|
|
const message2 = await prepareReplyEvent(
|
|
|
|
userAContext,
|
|
|
|
notUsed,
|
|
|
|
[],
|
|
|
|
"text",
|
|
|
|
) as NostrEvent;
|
|
|
|
|
|
|
|
const message3 = await prepareReplyEvent(
|
|
|
|
userAContext,
|
|
|
|
notUsed,
|
|
|
|
[[
|
|
|
|
"image",
|
2023-07-01 14:51:28 +00:00
|
|
|
PrivateKey.Generate().hex,
|
2023-06-30 14:05:57 +00:00
|
|
|
"1",
|
|
|
|
"0",
|
|
|
|
]],
|
|
|
|
"image",
|
|
|
|
) as NostrEvent;
|
|
|
|
|
|
|
|
const testEvent = [
|
|
|
|
message1,
|
|
|
|
message2,
|
|
|
|
message3,
|
2023-07-15 05:58:03 +00:00
|
|
|
].map((e): parsedTagsEvent => {
|
2023-07-13 09:06:35 +00:00
|
|
|
return {
|
|
|
|
...e,
|
|
|
|
parsedTags: getTags(e),
|
|
|
|
};
|
|
|
|
});
|
2023-06-30 14:05:57 +00:00
|
|
|
|
|
|
|
const validResult = new Set([
|
|
|
|
new Set([
|
|
|
|
message1,
|
2023-07-15 05:58:03 +00:00
|
|
|
].map((e): parsedTagsEvent => {
|
2023-07-13 09:06:35 +00:00
|
|
|
return {
|
|
|
|
...e,
|
|
|
|
parsedTags: getTags(e),
|
|
|
|
};
|
|
|
|
})),
|
2023-06-30 14:05:57 +00:00
|
|
|
new Set([
|
|
|
|
message2,
|
|
|
|
message3,
|
2023-07-15 05:58:03 +00:00
|
|
|
].map((e): parsedTagsEvent => {
|
2023-07-13 09:06:35 +00:00
|
|
|
return {
|
|
|
|
...e,
|
|
|
|
parsedTags: getTags(e),
|
|
|
|
};
|
|
|
|
})),
|
2023-06-30 14:05:57 +00:00
|
|
|
]);
|
|
|
|
|
|
|
|
for (let i = 0; i < 10; i++) {
|
|
|
|
const result = computeThreads(testEvent.sort((a, b) => 0.5 - Math.random()));
|
|
|
|
const res = new Set(result.map((r) => new Set(r)));
|
|
|
|
assertEquals(res, validResult);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
await t.step("if one of reply has both reply tag and root tag", async () => {
|
|
|
|
const userAPrivateKey = PrivateKey.Generate();
|
|
|
|
const userBPrivateKey = PrivateKey.Generate();
|
|
|
|
const userAContext = InMemoryAccountContext.New(userAPrivateKey);
|
|
|
|
const userBContext = InMemoryAccountContext.New(userBPrivateKey);
|
|
|
|
const message1 = await prepareNormalNostrEvent(
|
|
|
|
userAContext,
|
|
|
|
NostrKind.TEXT_NOTE,
|
|
|
|
[],
|
|
|
|
"message 1",
|
|
|
|
);
|
|
|
|
const message2 = await prepareReplyEvent(
|
|
|
|
userAContext,
|
|
|
|
message1,
|
|
|
|
[],
|
|
|
|
"message2, message1's reply",
|
|
|
|
) as NostrEvent;
|
|
|
|
const message3 = await prepareReplyEvent(
|
|
|
|
userBContext,
|
|
|
|
message1,
|
|
|
|
[],
|
|
|
|
"message3, message1's reply",
|
|
|
|
) as NostrEvent;
|
|
|
|
const message4 = await prepareReplyEvent(
|
|
|
|
userAContext,
|
|
|
|
message2,
|
|
|
|
[
|
|
|
|
[
|
|
|
|
"e",
|
|
|
|
message1.id,
|
|
|
|
"",
|
|
|
|
"root",
|
|
|
|
],
|
|
|
|
],
|
|
|
|
"message4, message 2' reply",
|
|
|
|
) as NostrEvent;
|
|
|
|
|
|
|
|
const testEvent = [
|
|
|
|
message1,
|
|
|
|
message2,
|
|
|
|
message3,
|
|
|
|
message4,
|
2023-07-15 05:58:03 +00:00
|
|
|
].map((e): parsedTagsEvent => {
|
2023-07-13 09:06:35 +00:00
|
|
|
return {
|
|
|
|
...e,
|
|
|
|
parsedTags: getTags(e),
|
|
|
|
};
|
|
|
|
});
|
2023-06-30 14:05:57 +00:00
|
|
|
|
|
|
|
const validResult = new Set([
|
|
|
|
new Set([
|
|
|
|
message1,
|
|
|
|
message2,
|
|
|
|
message3,
|
|
|
|
message4,
|
2023-07-15 05:58:03 +00:00
|
|
|
].map((e): parsedTagsEvent => {
|
2023-07-13 09:06:35 +00:00
|
|
|
return {
|
|
|
|
...e,
|
|
|
|
parsedTags: getTags(e),
|
|
|
|
};
|
|
|
|
})),
|
2023-06-30 14:05:57 +00:00
|
|
|
]);
|
|
|
|
|
|
|
|
for (let i = 0; i < 10; i++) {
|
|
|
|
const data = testEvent.sort((a, b) => 0.5 - Math.random());
|
|
|
|
console.log(data);
|
|
|
|
const result = computeThreads(data);
|
|
|
|
const res = new Set(result.map((r) => new Set(r)));
|
|
|
|
assertEquals(res, validResult);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|