import { expect, test } from "bun:test"; import { mkdir, readdir, symlink, writeFile } from "node:fs/promises"; import { join } from "node:path"; import { folderName, folderNumber, importCodeRepo } from "../src/jobs/code-repo"; import { importPacktVideo } from "../src/jobs/packt-video"; import { makeEnv } from "./harness"; import { makePacktZip, makeRepoZip, tmp } from "./fixtures"; test("folder names split into number and name", () => { expect(folderNumber("S08 - Containerizing Applications")).toBe(8); expect(folderName("S08 - Containerizing Applications")).toBe("Containerizing Applications"); expect(folderNumber("Section 3: Images")).toBe(3); expect(folderNumber("Bonus Extras")).toBeNull(); }); async function target() { const env = await makeEnv(); const r = await importPacktVideo(env.deps, { path: await makePacktZip(await tmp()), options: { title: "Docker Test" } }, env.jc); return { env, id: r.courseId }; } test("zip repo: folders attach to modules by number, PDFs become deck and attachment", async () => { const { env, id } = await target(); const zip = await makeRepoZip(await tmp()); const res = await importCodeRepo(env.deps, { kind: "code-repo", path: zip, options: { courseId: id } }, env.jc); const c = env.deps.ctx.courses.get(id)!; expect(c.status).toBe("ok"); expect(c.manifest!.modules[0]!.code).toEqual({ dir: "code/S01 - Intro to Docker" }); expect(c.manifest!.modules[1]!.code).toEqual({ dir: "code/S02 - Images (Sample)" }); expect(env.deps.ctx.courses.resolvePath(id, "code/S02 - Images (Sample)/app/main.py")).toBeTruthy(); expect(env.deps.ctx.courses.resolvePath(id, "code/S02 - Images (Sample)/Ünïcode notes.txt")).toBeTruthy(); expect(c.manifest!.decks).toEqual([{ id: "d-slides-intro", file: "media/decks/Slides_Intro.pdf", title: "Slides Intro", attachTo: "m1" }]); expect(c.manifest!.attachments).toEqual([{ file: "media/files/Docker_CheatSheet.pdf", title: "Docker CheatSheet", module: "m1" }]); expect(await readdir(join(env.dataDir, "cache/decks", id, "d-slides-intro"))).toContain("p-003.jpg"); expect(await readdir(join(c.root, "code/S01 - Intro to Docker"))).toEqual([]); // PDFs are not duplicated into code expect(res.warnings).toEqual(['folder "Bonus Extras" matches no module and was skipped']); }); test("an unnumbered folder matches a module by name; symlinks are not copied; the input is untouched", async () => { const { env, id } = await target(); const top = join(await tmp(), "repo"); await mkdir(join(top, "Images Sample"), { recursive: true }); await writeFile(join(top, "Images Sample", "a.txt"), "a"); await symlink("/etc/passwd", join(top, "Images Sample", "link")); const res = await importCodeRepo(env.deps, { path: top, options: { courseId: id } }, env.jc); expect(res.warnings).toEqual([]); const c = env.deps.ctx.courses.get(id)!; expect(c.manifest!.modules[1]!.code).toEqual({ dir: "code/Images Sample" }); expect(await readdir(join(c.root, "code/Images Sample"))).toEqual(["a.txt"]); expect(await readdir(join(top, "Images Sample"))).toContain("link"); }); test("rejects unmanaged courses and bad git URLs without running git", async () => { const { env, id } = await target(); await expect(importCodeRepo(env.deps, { path: "/x", options: { courseId: "sample" } }, env.jc)).rejects.toThrow(/only edits courses it created/); await expect(importCodeRepo(env.deps, { path: "--upload-pack=touch /tmp/pwn", options: { courseId: id } }, env.jc)).rejects.toThrow(); });