diff --git a/cmd/lab/main.go b/cmd/lab/main.go index 3b56333..b6d4936 100644 --- a/cmd/lab/main.go +++ b/cmd/lab/main.go @@ -50,6 +50,31 @@ const ( exitCannot = 2 ) +// The three documents the last paragraph of the usage text names. They are +// named rather than restated, because a paraphrase printed by a binary somebody +// downloaded months ago is a copy of a document that has since moved on, and the +// reader has no way to tell which of the two they are holding. +// +// TWO LIMITS THAT BELONG HERE RATHER THAN ONLY IN THE ISSUE. A notice is not a +// control. Printing it stops nothing, and it should not be counted as a thing +// that prevents misuse when somebody later asks what does. And a notice an +// operator has to run a verb to see is weaker than one sitting in the download +// beside the binary, because the operator who most needs it is the one who runs +// the thing without asking it for help first. Both routes exist for that +// reason rather than either alone; the download half is issue #36 and has no +// archive to be carried in yet. +// +// Nothing outside this package holds these strings to the tree. The paths leg +// of the invariants scan reads this repository's own documents, which is the +// files at the root and everything under docs/, and a path named inside the +// runner is outside that subject by the leg's own reckoning. So the guard is +// the test beside this declaration and there is no second one. +var documentsAnOperatorIsOwed = []string{ + "NOTICE.md", + "LICENSE", + "docs/privacy.md", +} + const usage = `lab reads this repository and reports what it examined. lab check [path] walk the tree at path, default ".", and report @@ -58,6 +83,10 @@ const usage = `lab reads this repository and reports what it examined. lab help print this text lab writes nothing to the tree it reads. + +NOTICE.md says what this program is for, LICENSE carries the terms it is under, +and docs/privacy.md says what stays on the host. Reading them is on you; this +text only says where they are. ` // THIS IS WHERE THE RUNNER READS THE TIME, and it is read once. Everything diff --git a/cmd/lab/main_test.go b/cmd/lab/main_test.go index 4c152f7..4e258f0 100644 --- a/cmd/lab/main_test.go +++ b/cmd/lab/main_test.go @@ -3,6 +3,8 @@ package main import ( "bytes" "errors" + "os" + "path/filepath" "strings" "testing" "time" @@ -215,3 +217,33 @@ func TestTheDocumentedCodesAreTheNumbersTheRecordFixes(t *testing.T) { } } } + +// TestHelpNamesTheDocumentsAnOperatorIsOwed holds the last paragraph of the +// usage text to the three files it points at. An operator who reads that +// paragraph and then looks for one of the files is the reader this asserts for, +// and both halves of the walk they make are here: that the text names the file, +// and that the file is in the tree to be found. +// +// The second half is the one that earns its place. A pointer in the runner is +// outside the subject of the invariants paths leg, which reads the files at the +// root and everything under docs/ and holds those to the paths they name. So a +// document deleted or moved under this paragraph reddens nothing anywhere else, +// and a binary would go on telling operators to read a file that is not there. +// +// What it does not judge is whether any of the three says what it should. That +// is a reading of prose and no test here makes it. +func TestHelpNamesTheDocumentsAnOperatorIsOwed(t *testing.T) { + var out, errOut bytes.Buffer + if got := run([]string{"help"}, &out, &errOut, ordinary(realWalk)); got != exitClean { + t.Fatalf("exit code %d, want %d", got, exitClean) + } + + for _, document := range documentsAnOperatorIsOwed { + if !strings.Contains(out.String(), document) { + t.Errorf("the help output does not name %s:\n%s", document, out.String()) + } + if _, err := os.Stat(filepath.Join("..", "..", filepath.FromSlash(document))); err != nil { + t.Errorf("the help output names %s and it is not in this tree: %v", document, err) + } + } +}