package main import ( "os" "testing" ) // A retired word's plural is the word; anything else joined on is another word. func TestPatternMatchesTheWordAndItsPlural(t *testing.T) { cases := []struct { word, text string want bool }{ {"control plane", "ask the control plane", true}, {"control plane", "two control planes", true}, {"control plane", "two control\n\tplanes", true}, {"substrate", "the substrates", true}, {"flavor", "flavors of a module", true}, {"flavor", "flavored", false}, {"node tools", "node toolsets", false}, {"mesh-console", "the mesh-consoles", true}, {"mesh-console", "mesh-console-x", false}, } for _, c := range cases { if got := pattern(c.word).MatchString(c.text); got != c.want { t.Errorf("pattern(%q) on %q = %v, want %v", c.word, c.text, got, c.want) } } } // A daemon's line is found whole — the daemon, its command, and an argument where the command is a line only with // one — and prose that merely names the daemon beside a word is not one (novox/hq ADR 0272). func TestADaemonsLineIsFoundWhole(t *testing.T) { push := retiredLine{daemon: "mesh-controller", command: "push"} module := retiredLine{daemon: "mesh-controller", command: "module", withArgument: true} handOver := retiredLine{daemon: "nox-mesh-host", command: "hand-over"} cases := []struct { line retiredLine text string want bool }{ {push, "run `mesh-controller push laptop` after", true}, {push, "mesh-controller push", true}, {push, "mesh-controller\n push", true}, {push, "mesh-controller pushed it", false}, {push, "the mesh-controller pushes", false}, {push, "mesh-controller-push", false}, {module, "`mesh-controller module check modules/*/module.json`", true}, {module, "run\n $ mesh-controller module check x", true}, {module, "the mesh-controller module is assigned", false}, {module, "mesh-controller module", false}, {module, "`mesh-controller module`", false}, {handOver, "`nox-mesh-host hand-over /srv/x` at the machine", true}, {handOver, "`nox node hand-over laptop /srv/x`", false}, {retiredLine{daemon: "mesh-host", command: "hand-over"}, "nox-mesh-host hand-over", false}, } for _, c := range cases { if got := linePattern(c.line).MatchString(c.text); got != c.want { t.Errorf("%s %s on %q = %v, want %v", c.line.daemon, c.line.command, c.text, got, c.want) } } found := checkLines([]retiredLine{push, module}, []text{{file: "m/a.go", line: 3, s: "say\n`mesh-controller push`"}, {file: "m/b.go", line: 1, s: "the mesh-controller module"}}) if len(found) != 1 || found[0] != "m/a.go:4: `mesh-controller push` is a daemon's line — the operator types `nox …` (novox/hq ADR 0272) — in \"say `mesh-controller push`\"" { t.Fatalf("found %q", found) } } // The list's lines read as ` `, a trailing ` …` meaning an argument must follow; anything else is // refused rather than read as some line. func TestRetiredLinesAreReadAsDaemonAndCommand(t *testing.T) { dir := t.TempDir() path := dir + "/retired-lines" if err := os.WriteFile(path, []byte("# the list\nmesh-controller push\nmesh-controller module …\n\nnox-mesh-host hand-over\n"), 0o644); err != nil { t.Fatal(err) } lines, err := readLines(path) if err != nil || len(lines) != 3 || lines[0] != (retiredLine{daemon: "mesh-controller", command: "push"}) || lines[1] != (retiredLine{daemon: "mesh-controller", command: "module", withArgument: true}) || lines[2] != (retiredLine{daemon: "nox-mesh-host", command: "hand-over"}) { t.Fatalf("read %+v, %v", lines, err) } if err := os.WriteFile(path, []byte("mesh-controller\n"), 0o644); err != nil { t.Fatal(err) } if _, err := readLines(path); err == nil { t.Fatal("a line with no command was read") } }