Latest
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296import { env } from "../lib/env.ts";import { isFileTask, isNormalTask, normalizePath, normalizeTaskName, Task, TaskRegistry,} from "../lib/tasks.ts";import { DrakeError, readFile, stat, writeFile } from "../lib/utils.ts";import { assert, assertEquals, assertRejects, assertThrows, path,} from "./deps.ts";
Deno.test("normalizePathTest", function () { const tests: [string, string][] = [ ["foobar", "./foobar"], ["lib/io.ts", "lib/io.ts"], ["/tmp//foobar", "/tmp/foobar"], ["/tmp/./foobar", "/tmp/foobar"], ["/tmp/../foobar", "/foobar"], ]; for (const [name, expected] of tests) { assertEquals(normalizePath(name), normalizePath(expected)); }});
Deno.test("normalizeTaskNameTest", function () { const tests = [ [" foobar", "foobar"], ["lib/io.ts", "lib/io.ts"].map((p) => normalizePath(p)), ]; for (const [name, expected] of tests) { assertEquals(normalizeTaskName(name), expected); } assertThrows( () => normalizeTaskName(" "), DrakeError, "blank task name", ); const name = "**/*.ts"; assertThrows( () => normalizeTaskName(name), DrakeError, `wildcard task name not allowed: ${name}`, );});
Deno.test("isTasksTest", function () { const tests: [string, boolean][] = [ ["foobar", true], ["--foobar", false], ["_foo_bar_", true], ["42-foobar", true], ["./foobar", false], ["foobar.ts", false], ["/tmp/foobar", false], ["../foobar/", false], ["./foobar/quux", false], [".foobar", false], ]; for (const [name, expected] of tests) { assertEquals(isNormalTask(name), expected); assertEquals(isFileTask(name), !expected); }});
Deno.test("taskRegistryTest", async function () { env("--quiet", true); const taskRegistry = new TaskRegistry();
assertEquals( taskRegistry.cacheFile(), path.join(Deno.cwd(), ".drake.cache.json"), ); env("--cache", "tests/drake-test.cache.json"); assertEquals( env("--cache"), path.join(Deno.cwd(), "tests", "drake-test.cache.json"), ); env("--cache", ""); // Reset default value. assertEquals( taskRegistry.cacheFile(), path.join(Deno.cwd(), ".drake.cache.json"), );
assertThrows( () => taskRegistry.get("quux"), DrakeError, "missing task: quux", );
const log: string[] = []; const action = function (this: Task) { log.push(this.name); };
assertEquals(taskRegistry.list().length, 0, "zero tasks");
taskRegistry.desc("Task 1"); taskRegistry.register("1", ["2", "3"], action);
taskRegistry.desc("Task 2"); taskRegistry.register("2", ["3"], action);
taskRegistry.desc("Task 3"); taskRegistry.register("3", [], action);
assertEquals(taskRegistry.get("1").desc, "Task 1"); assertEquals( taskRegistry.resolveDependencies(["1", "3", "2"]).map((task) => task.name), ["3", "2", "1"], ); await taskRegistry.run("1", "2", "3"); assertEquals(log, ["3", "2", "1"], "execution log mismatch");
assertEquals( taskRegistry.list().map((s) => s.slice(-6)), ["Task 1", "Task 2", "Task 3"], "task list should have descriptions", ); taskRegistry.get("2").desc = ""; assertEquals( taskRegistry.list().map((s) => s.slice(-6)), ["Task 1", "Task 3"], "hidden tasks are not listed", ); env("--list-all", true); try { assertEquals( taskRegistry.list().length, 3, "--list-all lists hidden tasks", ); } finally { env("--list-all", false); }
taskRegistry.desc("Task 4"); taskRegistry.register("4", ["1", "4"], action); taskRegistry.get("2").prereqs.push("4"); await assertRejects( async () => await taskRegistry.run("4"), DrakeError, "cyclic dependency between '4' and '1', cyclic dependency between '4' and '4'", "cyclic dependency should throw error", );
taskRegistry.desc("Task 5"); assertThrows( () => taskRegistry.register("5", ["1", "6", "4", "6"], action), DrakeError, "5: duplicate prerequisite: 6", );});
Deno.test("fileTaskTest", async function () { env("--quiet", true); const taskRegistry = new TaskRegistry();
const target = normalizePath("./target"); const prereq = normalizePath("./prereq"); let taskRan = false; // deno-lint-ignore require-await taskRegistry.register(target, [prereq], async function () { taskRan = true; });
const dir = Deno.makeTempDirSync(); const savedCwd = Deno.cwd(); env("--directory", dir); try { const task = taskRegistry.get(target); writeFile(prereq, ""); assert( task.isOutOfDate(), "isOutOfDate should return true: no previous task cache", ); assert( task.isOutOfDate(), "isOutOfDate should return true: missing target file", ); writeFile(target, "quux"); task.updateCache(); taskRegistry.saveCache(taskRegistry.cacheFile()); taskRegistry.loadCache(taskRegistry.cacheFile()); assertEquals( task.cache![prereq].size, 0, "loaded file cache prereq size should match", ); assertEquals( task.cache![target].size, 4, "loaded file cache target size should match", );
writeFile(prereq, "baz"); assert( task.isOutOfDate(), "isOutOfDate should return true: modified prerequisite file", );
taskRegistry.saveCache(taskRegistry.cacheFile()); Deno.removeSync(prereq); await assertThrows( () => task.isOutOfDate(), DrakeError, "missing prerequisite file:", "isOutOfDate should throw error: missing prerequisite file", ); writeFile(prereq, ""); Deno.removeSync(target); taskRan = false; await taskRegistry.run(target); assert(taskRan, "task should have executed: no target file"); assert( stat(taskRegistry.cacheFile())?.isFile, `cache file should exist: ${taskRegistry.cacheFile()}`, );
writeFile(target, ""); taskRan = true; await taskRegistry.run(target); assert(taskRan, "task should have executed: new target file");
taskRan = false; await taskRegistry.run(target); assert(!taskRan, "task should not have executed: target file up to date");
taskRan = false; writeFile(prereq, "foobar"); await taskRegistry.run(target); assert(taskRan, "task should have executed: prerequisite changed");
taskRan = false; await taskRegistry.run(target); assert(!taskRan, "task should not have executed: target file up to date");
Deno.removeSync(prereq); await assertRejects( async () => await taskRegistry.run(target), DrakeError, "missing prerequisite file:", "missing prerequisite file should throw error", );
env("--dry-run", true); try { // Missing prerequisite should not throw error if --dry-run. await taskRegistry.run(target); } finally { env("--dry-run", false); }
const target2 = normalizePath("./target2"); // deno-lint-ignore require-await taskRegistry.register(target2, [target], async function () { throw new DrakeError(); }); writeFile(prereq, ""); const oldCache = readFile(taskRegistry.cacheFile()); let didThrow = false; try { await taskRegistry.run(target, target2); } catch { didThrow = true; } assert(didThrow, "target2 task should throw an error"); assert( readFile(taskRegistry.cacheFile()) !== oldCache, "cache file should have updated after the error was thrown", );
env("--cache", "drake-test.cache.json"); const expected = path.join(Deno.cwd(), "drake-test.cache.json"); assert(taskRegistry.cacheFile(), expected); Deno.removeSync(target); taskRan = false; await taskRegistry.run(target); assert(taskRan, "task should have executed: no target file"); assert( stat(expected)?.isFile, `cache file should exist: ${expected}`, ); } finally { env("--cache", ""); env("--directory", savedCwd); Deno.removeSync(dir, { recursive: true }); }});