package pipeline import ( "go/ast" "go/parser" "go/token" "os" "strconv" "strings" "testing" ) // flagseverity_test.go pins the chapter passport's "worst flag" ranking. // // ⚠ WHY THIS FILE EXISTS AT ALL. flagReasonSeverity had no test of any kind, and the shape of the bug it // carried is the one this project keeps meeting: a hand-written list that stopped tracking the constants it // lists. `off_target_lang` — the flag an entire pack was built to raise — was never added to the switch, so // it fell to the default and became the MOST BENIGN reason in the passport, below `length`. A chapter that // came back in the wrong language reported «length» as its worst problem. Nothing was wrong with the code; // the list was simply not tied to anything. // TestEveryFlagReasonIsRanked reads the FlagReason constants OUT OF THE SOURCE rather than retyping them // here, because a hand-written list in the test would rot exactly like the hand-written list in the code — // and would then certify the rot. This is the guarantee that the next flag someone adds cannot land in the // unknown bucket silently: it fails here on the day it is declared, not on the day it is misreported. func TestEveryFlagReasonIsRanked(t *testing.T) { // ⚠ EVERY FILE OF THE PACKAGE, not disposition.go alone — the first version of this test named one // file, and a planting that declared a FlagReason anywhere else walked straight past it while the test // still reported «every declared reason is ranked». The guarantee was one file narrower than its own // sentence, which is the defect class this file exists to prevent, committed by the file itself. entries, err := os.ReadDir(".") if err != nil { t.Fatalf("read the package directory: %v", err) } var sources []string for _, e := range entries { n := e.Name() if e.IsDir() || !strings.HasSuffix(n, ".go") || strings.HasSuffix(n, "_test.go") { continue } sources = append(sources, n) } if len(sources) < 10 { t.Fatalf("only %d source files found — the walk stopped seeing the package: %v", len(sources), sources) } fset := token.NewFileSet() var decls []ast.Decl for _, name := range sources { f, perr := parser.ParseFile(fset, name, nil, 0) if perr != nil { t.Fatalf("parse %s: %v", name, perr) } decls = append(decls, f.Decls...) } var found int for _, d := range decls { gd, ok := d.(*ast.GenDecl) if !ok || gd.Tok != token.CONST { continue } for _, sp := range gd.Specs { vs, ok := sp.(*ast.ValueSpec) if !ok { continue } // ⚠ THE TYPE MUST BE WRITTEN ON THIS SPEC. An earlier version carried the previous spec's type // forward, which is not how Go types a const block: a spec that has a VALUE and no type is its // own UNTYPED constant and inherits nothing. That version raised a FALSE ALARM — an ordinary // string constant placed after a FlagReason spec in the same block was accused of being an // unranked flag, and a doc-URL constant would have failed this test with a message about the // chapter passport. A test that accuses the innocent is not enforcing its own sentence, and this // one exists to say what IS a declared reason. // // ⚠ AND BOTH GO SPELLINGS COUNT. `X FlagReason = "…"` writes the type in the spec; the equally // ordinary `X = FlagReason("…")` writes it as a CONVERSION, leaving vs.Type nil — and a walk // that looked only at vs.Type was blind to it, which an adversarial pass exhibited as a pair: // the typed spelling of one declaration RED, the conversion spelling of the same declaration // SURVIVED. The sentence that used to stand here — «a missed declaration would trip the found // floor rather than pass silently» — was simply false: one missing constant leaves the count at // 16 against a floor of 15, and nothing trips. if len(vs.Values) == 0 { continue } var lit *ast.BasicLit switch { case isFlagReasonIdent(vs.Type): lit, _ = vs.Values[0].(*ast.BasicLit) default: call, isCall := vs.Values[0].(*ast.CallExpr) if !isCall || !isFlagReasonIdent(call.Fun) || len(call.Args) != 1 { continue } lit, _ = call.Args[0].(*ast.BasicLit) } if lit == nil || lit.Kind != token.STRING { continue } val, err := strconv.Unquote(lit.Value) if err != nil { t.Fatalf("%s: %v", vs.Names[0].Name, err) } if val == "" { continue // reasonOK — the sentinel for "not a flag", deliberately unranked } found++ if _, ranked := flagSeverity[FlagReason(val)]; !ranked { t.Errorf("%s (%q) has no entry in flagSeverity: it would rank %d — BELOW every real diagnosis, "+ "so it can never be reported as a chapter's worst flag", vs.Names[0].Name, val, severityUnknown) } } } // The reader of this test must know it actually read something: a parse that silently matched nothing // would pass forever and guard nothing — the same failure class one layer up. if found < 15 { t.Fatalf("only %d FlagReason constants were read out of the package's %d source files — the walk "+ "stopped matching the source, and this test is no longer checking anything", found, len(sources)) } if len(flagSeverity) != found { t.Errorf("flagSeverity has %d entries for %d declared reasons — a rank exists for a reason that no "+ "longer does", len(flagSeverity), found) } } // TestOffTargetLangIsRankedWithTheContentFailures is the specific harm, asserted as a number and not as a // membership: the flag must out-rank the budget symptoms, because those are what it was losing to. func TestOffTargetLangIsRankedWithTheContentFailures(t *testing.T) { off := flagReasonSeverity(string(FlagOffTargetLang)) if off == severityUnknown { t.Fatal("off_target_lang fell to the unknown bucket — the exact defect this file was written for") } for _, milder := range []FlagReason{FlagLength, FlagEmpty, FlagGlossaryMiss, FlagSanitizerStripped} { if off >= flagReasonSeverity(string(milder)) { t.Errorf("off_target_lang (%d) must be WORSE than %s (%d): a chapter in the wrong language is not "+ "a budget symptom", off, milder, flagReasonSeverity(string(milder))) } } // It is a content failure, ranked with the echo it sits beside in the classifier. if off != flagReasonSeverity(string(FlagCJKArtifact)) { t.Errorf("off_target_lang (%d) and cjk_artifact (%d) are the same class — «the output is not a "+ "translation of this text into the asked-for language» — and must rank together", off, flagReasonSeverity(string(FlagCJKArtifact))) } // A refusal still outranks both: the provider said no, which is a different and worse fact. if off <= flagReasonSeverity(string(FlagHardRefusal)) { t.Error("a hard refusal must still outrank an off-target completion") } } // isFlagReasonIdent reports whether an expression names the FlagReason type — as a spec's type or as the // function of a conversion. One helper for both spellings, so the walk cannot learn one and forget the other. func isFlagReasonIdent(e ast.Expr) bool { id, ok := e.(*ast.Ident) return ok && id.Name == "FlagReason" }