package fiesta import ( "os" "os/exec" "strings" "testing" ) // Fiesta is the design system on its own. Rastrillo adopts it, so a // path from here back to Rastrillo would be a cycle, and a user who // links the CSS from a static page has no Go at all. The two tests // below are the two halves of that promise, executable: no build of // this module reaches amadan.net/rastrillo/rastrillo, and the packages // a Go program imports from Fiesta pull in no browser. // rastrilloModule is the import path that must never appear in this // module's dependency graph, and never in its go.mod. const rastrilloModule = "amadan.net/rastrillo/rastrillo" // listDeps runs go list with the given arguments and returns its // output, one import path per line. A go list that cannot run fails // the test rather than listing nothing: piped straight into a check, // an empty listing would pass as clean, which is how a toolchain that // could not fetch itself once passed rastrillo's own graph check. func listDeps(t *testing.T, args ...string) []string { t.Helper() cmd := exec.Command("go", append([]string{"list"}, args...)...) out, err := cmd.CombinedOutput() if err != nil { t.Fatalf("go list %s: %v\n%s", strings.Join(args, " "), err, out) } lines := strings.Split(strings.TrimRight(string(out), "\n"), "\n") if len(lines) == 0 || lines[0] == "" { t.Fatalf("go list %s printed nothing", strings.Join(args, " ")) } return lines } // requireListed is the precondition that keeps either check honest: a // listing that does not name this module's own package is not a // listing of this module, whatever else it says. func requireListed(t *testing.T, lines []string, args string) { t.Helper() for _, l := range lines { if l == "amadan.net/rastrillo/fiesta" { return } } t.Fatalf("go list %s did not list amadan.net/rastrillo/fiesta itself; the check below would be looking at nothing:\n%s", args, strings.Join(lines, "\n")) } // TestFiestaNeverImportsRastrillo is the global constraint "No // Rastrillo dependency" as a test: every package of this module, its // tests included and with the browser tag on (a strict superset of the // plain build), imports nothing from amadan.net/rastrillo/rastrillo, // and go.mod never requires it. The go.mod half catches a requirement // nobody imports yet, which `go list -deps` alone would not see. func TestFiestaNeverImportsRastrillo(t *testing.T) { mod, err := os.ReadFile("go.mod") if err != nil { t.Fatalf("reading go.mod: %v", err) } if strings.Contains(string(mod), rastrilloModule) { t.Errorf("go.mod mentions %s; Fiesta never requires Rastrillo", rastrilloModule) } args := "-deps -test -tags browser ./..." lines := listDeps(t, "-deps", "-test", "-tags", "browser", "./...") requireListed(t, lines, args) for _, l := range lines { if strings.HasPrefix(l, rastrilloModule) { t.Errorf("go list %s reaches %s; Fiesta never imports Rastrillo in any build, tag or test", args, l) } } } // TestThePublicPackagesLinkNoBrowser is the other half: the packages // a Go program imports from Fiesta, the root and example, never link // chromedp. The browser is for check/ and the drives, and an app that // embeds the CSS must not take on a Chrome driver to do it. func TestThePublicPackagesLinkNoBrowser(t *testing.T) { args := "-deps . ./example" lines := listDeps(t, "-deps", ".", "./example") requireListed(t, lines, args) for _, l := range lines { if strings.Contains(l, "chromedp") { t.Errorf("go list %s reaches %s; the public packages never link a browser", args, l) } } }