// Package lexicon_meta_cover holds the Cover lexicon firewall (REQ-055, // D-088) — the 4th lexicon meta-test. // // It is a NEW sibling meta-test created in v0.7 P1 that MIRRORS the v0.6 // web firewall (lexicon_meta_web/lexicon_meta_web_test.go, package // lexicon_meta_web) but scans the Cover module surface (x/cover/**/*.go) // for BOTH the 10 project-wide banned terms (lexicon.FindBannedTerm) AND // the 4 Cover-specific banned terms (lexicon.FindCoverBannedTerm — D-088). // It uses the SAME lexicon.FindBannedTerm + lexicon.FindCoverBannedTerm // (word-boundary, case-insensitive) — NO detection reimplementation — so // the four firewalls (x/*.go project-wide, docs, web, cover) share a // single source of truth for the banned terms. The Cover-specific 4 terms // (insurance, premium, claim, policy — assembled from fragments by // lexicon.CoverBannedTerms) are the Cover-module superset layer: the // project-wide 10 terms ALSO apply to x/cover; this firewall adds the 4 // Cover-specific terms on top. // // Placement: this file lives in lexicon_meta_cover/ (a subdirectory of the // repo root) because Go does not permit two distinct packages in the same // directory; the v0.2 firewall is package lexicon_meta at the repo root, // the v0.3 firewall is package lexicon_meta_docs in lexicon_meta_docs/, // and the v0.6 firewall is package lexicon_meta_web in lexicon_meta_web/. // The invocation `go test ./lexicon_meta_cover/...` (PLANS v0.7 P1) // resolves to this package. Run via `go test ./...` from the repo root. // // G-013 walk-coverage: TestLexiconMetaCoverWalkCoverage injects synthetic // banned-term .go files into a temp x/cover/ subtree and asserts the walk // FINDS them — one for a project-wide term, one for a Cover-specific term. // This closes the "silently scans nothing and reports green" failure mode // that the G-009 self-test table (detection) alone does not cover. // // G-014 self-test drift: the self-test tables reuse // lexicon.SyntheticBannedStrings() (project-wide) + // lexicon.SyntheticCoverBannedStrings() (Cover-specific) — the single // sources of truth shared with the other three meta-tests. // // G-024: this test file stays stdlib + lexicon-only (no cosmos-sdk import). package lexicon_meta_cover import ( "os" "path/filepath" "runtime" "strings" "testing" "github.com/oy/openyield/lexicon" ) // repoRoot returns the absolute path to the repo root by walking up from // this test file (the test lives at /lexicon_meta_cover/). func repoRoot(t *testing.T) string { t.Helper() _, file, _, ok := runtime.Caller(0) if !ok { t.Fatal("runtime.Caller failed") } // file = .../oy/lexicon_meta_cover/lexicon_meta_cover_test.go // repo root = filepath.Dir(filepath.Dir(file)) return filepath.Dir(filepath.Dir(file)) } // coverRoot returns the absolute path to the repo's x/cover directory. func coverRoot(t *testing.T) string { t.Helper() return filepath.Join(repoRoot(t), "x", "cover") } // thisFile returns the absolute path of this meta-test file (to exclude it // from its own scan — it references banned terms via the lexicon package, // whose source assembles terms from fragments, so no banned-term literal // appears in the firewall's own code). func thisFile(t *testing.T) string { t.Helper() _, file, _, ok := runtime.Caller(0) if !ok { t.Fatal("runtime.Caller failed") } return file } // isCoverTarget reports whether path (relative to repo root) is a .go file // under x/cover/ (production + test). Non-.go files under x/cover/ are // skipped. func isCoverTarget(rel string) bool { prefix := strings.Join([]string{"x", "cover", ""}, string(filepath.Separator)) if !strings.HasPrefix(rel, prefix) { return false } return strings.HasSuffix(rel, ".go") } // TestLexiconMetaCoverNoBannedTerms is the Cover firewall (D-088). It walks // x/cover/**/*.go (production + test), reads each file's source, and // asserts no banned term (project-wide OR Cover-specific) is present // (word-boundary, case-insensitive). Excludes this test file itself // (self-exclusion via runtime.Caller(0) — though this file lives outside // x/cover/, the exclusion is belt-and-suspenders in case the walk root is // ever broadened). // // Passes at P1 with the x/cover module lexicon-clean by construction. The // x/cover/types/types_test.go per-package lexicon assertion // (TestLexiconNoBannedTermsInCover) is the in-module firewall; this // meta-test is the repo-wide Cover firewall (run via `go test ./...`). func TestLexiconMetaCoverNoBannedTerms(t *testing.T) { root := coverRoot(t) this := thisFile(t) hits := []string{} err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error { if err != nil { return err } if info.IsDir() { // Skip the walk-coverage fixture dir (G-013): // TestLexiconMetaCoverWalkCoverage creates // x/cover/.lexicon_fixture/ with synthetic banned-term .go // files. Those fixtures are test artifacts, NOT production // code; skip the dir to avoid a self-trip if cleanup is // delayed. if info.Name() == ".lexicon_fixture" { return filepath.SkipDir } return nil } if !strings.HasSuffix(path, ".go") { return nil } // Self-exclusion: skip this meta-test file (belt-and-suspenders; // this file lives outside x/cover/ so the walk would not reach it // anyway, but the exclusion is robust to a future walk-root change). if path == this { return nil } bz, rerr := os.ReadFile(path) if rerr != nil { return rerr } src := string(bz) // Project-wide 10 terms. if found, ok := lexicon.FindBannedTerm(src); ok { rel, _ := filepath.Rel(root, path) hits = append(hits, rel+" contains project-wide banned term "+found) } // Cover-specific 4 terms. if found, ok := lexicon.FindCoverBannedTerm(src); ok { rel, _ := filepath.Rel(root, path) hits = append(hits, rel+" contains Cover-specific banned term "+found) } return nil }) if err != nil { t.Fatalf("walk: %v", err) } if len(hits) > 0 { t.Errorf("REQ-055/D-088 Cover lexicon firewall violations:\n %s", strings.Join(hits, "\n ")) } } // TestLexiconMetaCoverSelfTestTable (G-009 for cover) is the firewall's own // detection-coverage guard. Each synthetic string embeds exactly one // banned term in a plausible sentence context and is asserted to trigger // detection, so the firewall's detection logic is durably verified — if // detection ever breaks, this test fails before the firewall silently // passes a real violation in a Cover source file. // // This test exercises BOTH the project-wide terms (lexicon.SyntheticBannedStrings // + lexicon.FindBannedTerm) AND the Cover-specific terms // (lexicon.SyntheticCoverBannedStrings + lexicon.FindCoverBannedTerm), // so both layers of the Cover firewall are durably verified. func TestLexiconMetaCoverSelfTestTable(t *testing.T) { // Project-wide layer. terms := lexicon.BannedTerms() if len(terms) != 10 { t.Fatalf("BannedTerms() len = %d, want 10", len(terms)) } synthetic := lexicon.SyntheticBannedStrings() if len(synthetic) != len(terms) { t.Fatalf("SyntheticBannedStrings() len = %d, want %d", len(synthetic), len(terms)) } for i, s := range synthetic { found, ok := lexicon.FindBannedTerm(s) if !ok { t.Errorf("G-009 cover self-test (project-wide) [%d]: synthetic string did not trigger detection: %q", i, s) continue } if found != terms[i] { t.Errorf("G-009 cover self-test (project-wide) [%d]: detected %q, want %q (in %q)", i, found, terms[i], s) } } // Cover-specific layer. coverTerms := lexicon.CoverBannedTerms() if len(coverTerms) != 4 { t.Fatalf("CoverBannedTerms() len = %d, want 4 (D-088)", len(coverTerms)) } coverSynthetic := lexicon.SyntheticCoverBannedStrings() if len(coverSynthetic) != len(coverTerms) { t.Fatalf("SyntheticCoverBannedStrings() len = %d, want %d (must match CoverBannedTerms())", len(coverSynthetic), len(coverTerms)) } for i, s := range coverSynthetic { found, ok := lexicon.FindCoverBannedTerm(s) if !ok { t.Errorf("G-009 cover self-test (Cover-specific) [%d]: synthetic string did not trigger detection: %q", i, s) continue } if found != coverTerms[i] { t.Errorf("G-009 cover self-test (Cover-specific) [%d]: detected %q, want %q (in %q)", i, found, coverTerms[i], s) } } } // TestLexiconMetaCoverBannedTermsCount asserts exactly 10 project-wide // banned terms + 4 Cover-specific banned terms are configured (locked-const // for the firewall's scope). Derived from lexicon.BannedTerms() + // lexicon.CoverBannedTerms() — the single sources — so a count change // breaks the firewalls (G-014 drift prevention). func TestLexiconMetaCoverBannedTermsCount(t *testing.T) { terms := lexicon.BannedTerms() if len(terms) != 10 { t.Errorf("BannedTerms() len = %d, want 10 (REQ-012)", len(terms)) } coverTerms := lexicon.CoverBannedTerms() if len(coverTerms) != 4 { t.Errorf("CoverBannedTerms() len = %d, want 4 (D-088)", len(coverTerms)) } seen := map[string]bool{} for _, tr := range terms { if seen[tr] { t.Errorf("duplicate project-wide banned term %q", tr) } seen[tr] = true } for _, tr := range coverTerms { if seen[tr] { t.Errorf("Cover-specific banned term %q duplicates a project-wide term", tr) } seen[tr] = true } } // TestLexiconMetaCoverNoFalsePositiveOnClaimant asserts the field name // "ClaimantReachID" (used by types.CoverCall) does NOT trigger the // Cover-specific banned term that looks like a substring of "Claimant" // (word-boundary matching must not match substrings of identifiers). This // is the regression firewall for the word-boundary detection design on the // Cover-specific layer — mirrors the project-wide // TestLexiconMetaNoFalsePositiveOnOpenYield. func TestLexiconMetaCoverNoFalsePositiveOnClaimant(t *testing.T) { cases := []string{ "ClaimantReachID", "ClaimantReachID string", "the ClaimantReachID field", "c.ClaimantReachID", } for _, s := range cases { if _, ok := lexicon.FindCoverBannedTerm(s); ok { t.Errorf("false positive: %q triggered a Cover-specific banned term (word-boundary must avoid this)", s) } } } // TestLexiconMetaCoverWalkCoverage (G-013) is the walk-coverage firewall // for the Cover meta-test. The G-009 self-test table (above) verifies // DETECTION (FindBannedTerm / FindCoverBannedTerm on synthetic strings) // but NOT the WALK (which files are scanned). A walk bug — e.g. wrong path // prefix, missing x/cover/ recursion — would silently scan nothing and // report green on zero files. This test closes that gap by injecting // synthetic banned-term .go files into a fixture dir under the real // x/cover/ path the walk scans and asserting the walk FINDS them — one // fixture for a project-wide term, one for a Cover-specific term. // // The fixtures are created under x/cover/.lexicon_fixture/ (a real x/cover/ // subtree the walk reaches) and removed via defer so they never leak into // the repo. If the walk logic misses either fixture, this test fails loudly // instead of letting a broken walk pass the firewall green on zero files // scanned. func TestLexiconMetaCoverWalkCoverage(t *testing.T) { root := coverRoot(t) // Build synthetic banned terms from fragments so THIS file does not // contain banned-term literals. terms := lexicon.BannedTerms() if len(terms) == 0 { t.Fatal("BannedTerms() returned no terms — cannot run walk-coverage") } coverTerms := lexicon.CoverBannedTerms() if len(coverTerms) == 0 { t.Fatal("CoverBannedTerms() returned no terms — cannot run walk-coverage") } // Project-wide fixture: use the first banned term ("bank") reassembled. pwTerm := terms[0][:2] + terms[0][2:] // Cover-specific fixture: use the first Cover term reassembled. coverTerm := coverTerms[0][:len(coverTerms[0])/2] + coverTerms[0][len(coverTerms[0])/2:] fixtureDir := filepath.Join(root, ".lexicon_fixture") if err := os.MkdirAll(fixtureDir, 0o755); err != nil { t.Fatalf("mkdir fixture: %v", err) } defer os.RemoveAll(fixtureDir) // Project-wide fixture .go file. pwFixture := filepath.Join(fixtureDir, "bad_pw_fixture.go") pwContent := []byte("// fixture\n// this file contains a project-wide banned term: " + pwTerm + "\npackage lexicon_fixture\n") if err := os.WriteFile(pwFixture, pwContent, 0o644); err != nil { t.Fatalf("write pw fixture: %v", err) } // Cover-specific fixture .go file. coverFixture := filepath.Join(fixtureDir, "bad_cover_fixture.go") coverContent := []byte("// fixture\n// this file contains a Cover-specific banned term: " + coverTerm + "\npackage lexicon_fixture\n") if err := os.WriteFile(coverFixture, coverContent, 0o644); err != nil { t.Fatalf("write cover fixture: %v", err) } // Run the SAME walk logic as TestLexiconMetaCoverNoBannedTerms and // assert it FINDS both fixtures' banned terms. A walk that returns zero // hits here proves the walk logic is broken. pwHits := []string{} coverHits := []string{} err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error { if err != nil { return err } if info.IsDir() { return nil } if !strings.HasSuffix(path, ".go") { return nil } bz, rerr := os.ReadFile(path) if rerr != nil { return rerr } src := string(bz) if found, ok := lexicon.FindBannedTerm(src); ok { rel, _ := filepath.Rel(root, path) pwHits = append(pwHits, rel+":"+found) } if found, ok := lexicon.FindCoverBannedTerm(src); ok { rel, _ := filepath.Rel(root, path) coverHits = append(coverHits, rel+":"+found) } return nil }) if err != nil { t.Fatalf("walk: %v", err) } // Assert the project-wide fixture was found. foundPW := false for _, h := range pwHits { if strings.Contains(h, "bad_pw_fixture.go") && strings.Contains(h, pwTerm) { foundPW = true break } } if !foundPW { t.Errorf("G-013 walk-coverage (project-wide): the walk did NOT find the synthetic project-wide banned-term fixture at %s — the Cover firewall walk logic is broken (it would silently scan nothing and report green). pwHits=%v", pwFixture, pwHits) } // Assert the Cover-specific fixture was found. foundCover := false for _, h := range coverHits { if strings.Contains(h, "bad_cover_fixture.go") && strings.Contains(h, coverTerm) { foundCover = true break } } if !foundCover { t.Errorf("G-013 walk-coverage (Cover-specific): the walk did NOT find the synthetic Cover-specific banned-term fixture at %s — the Cover firewall walk logic is broken. coverHits=%v", coverFixture, coverHits) } }