diff options
author | João Augusto Costa Branco Marado Torres <torres.dev@disroot.org> | 2025-06-24 12:08:41 -0300 |
---|---|---|
committer | João Augusto Costa Branco Marado Torres <torres.dev@disroot.org> | 2025-06-24 12:50:43 -0300 |
commit | f9a77c5c27aede4e5978eb55d9b7af781b680a1d (patch) | |
tree | d545e325ba1ae756fc2eac66fac1001b6753c40d /src/lib/pgp/create.test.ts |
feat!: initial commit
Signed-off-by: João Augusto Costa Branco Marado Torres <torres.dev@disroot.org>
Diffstat (limited to 'src/lib/pgp/create.test.ts')
-rw-r--r-- | src/lib/pgp/create.test.ts | 130 |
1 files changed, 130 insertions, 0 deletions
diff --git a/src/lib/pgp/create.test.ts b/src/lib/pgp/create.test.ts new file mode 100644 index 0000000..e9e9f41 --- /dev/null +++ b/src/lib/pgp/create.test.ts @@ -0,0 +1,130 @@ +import { beforeEach, describe, it } from "@std/testing/bdd"; +import { + createInMemoryFile, + generateKeyPair, + startMockFs, +} from "../../../tests/fixtures/setup.ts"; +import { + armored, + binary, + createKeysFromFs, + DEFAULT_KEY_DISCOVERY_RULES, +} from "./create.ts"; +import { assertEquals, assertRejects } from "@std/assert"; +import { stub } from "@std/testing/mock"; + +startMockFs(); + +describe("createKeysFromFs", () => { + let keyPair: Awaited<ReturnType<typeof generateKeyPair>>; + + beforeEach(async () => { + keyPair = await generateKeyPair("Alice"); + }); + + it("loads a single armored key file", async () => { + const url = createInMemoryFile( + new URL("file:///mock/alice.asc"), + keyPair.privateKey.armor(), + ); + + const keys = []; + for await (const key of createKeysFromFs(url)) { + keys.push(key); + } + + assertEquals(keys.length, 1); + }); + + it("loads a single binary key file", async () => { + const binaryData = keyPair.privateKey.write(); + const url = createInMemoryFile( + new URL("file:///mock/alice.gpg"), + binaryData as Uint8Array<ArrayBuffer>, + ); + + const keys = []; + for await (const key of createKeysFromFs(url)) { + keys.push(key); + } + + assertEquals(keys.length, 1); + }); + + it("ignores unsupported file extensions", async () => { + const url = createInMemoryFile( + new URL("file:///mock/ignored.txt"), + "This is not a key", + ); + + const keys = []; + for await (const key of createKeysFromFs(url)) { + keys.push(key); + } + + assertEquals(keys.length, 0); + }); + + it("throws on overlapping discovery formats", async () => { + const rules = { + formats: { + [armored]: new Set(["asc", "gpg"]), + [binary]: new Set(["gpg"]), + }, + }; + + const url = new URL("file:///mock/bogus.gpg"); + + await assertRejects(() => createKeysFromFs(url, rules).next()); + }); + + it("handles recursive directory traversal", async () => { + const aliceURL = new URL("file:///mock/keys/alice.asc"); + const bobURL = new URL("file:///mock/keys/sub/bob.asc"); + + createInMemoryFile(aliceURL, keyPair.privateKey.armor()); + createInMemoryFile(bobURL, keyPair.privateKey.armor()); + + const mockedDirTree = { + "file:///mock/keys/": [ + { name: "alice.asc", isFile: true, isDirectory: false }, + { name: "sub", isFile: false, isDirectory: true }, + ], + "file:///mock/keys/sub/": [ + { name: "bob.asc", isFile: true, isDirectory: false }, + ], + }; + + stub(Deno, "stat", (url: URL | string) => { + const href = new URL(url).href; + return Promise.resolve({ + isDirectory: href.endsWith("/") || href.includes("/sub"), + isFile: href.endsWith(".asc"), + isSymlink: false, + } as Deno.FileInfo); + }); + + stub(Deno, "readDir", async function* (url: URL | string) { + const href = new URL(url).href; + for ( + const entry of mockedDirTree[href as keyof typeof mockedDirTree] ?? [] + ) { + yield entry as Deno.DirEntry; + } + }); + + const root = new URL("file:///mock/keys/"); + const keys = []; + + for await ( + const key of createKeysFromFs( + root, + { ...DEFAULT_KEY_DISCOVERY_RULES, recursive: true }, + ) + ) { + keys.push(key); + } + + assertEquals(keys.length, 2); + }); +}); |