| 1 | package fiesta |
| 2 | |
| 3 | import ( |
| 4 | "os" |
| 5 | "os/exec" |
| 6 | "strings" |
| 7 | "testing" |
| 8 | ) |
| 9 | |
| 10 | // Fiesta is the design system on its own. Rastrillo adopts it, so a |
| 11 | // path from here back to Rastrillo would be a cycle, and a user who |
| 12 | // links the CSS from a static page has no Go at all. The two tests |
| 13 | // below are the two halves of that promise, executable: no build of |
| 14 | // this module reaches amadan.net/rastrillo/rastrillo, and the packages |
| 15 | // a Go program imports from Fiesta pull in no browser. |
| 16 | |
| 17 | // rastrilloModule is the import path that must never appear in this |
| 18 | // module's dependency graph, and never in its go.mod. |
| 19 | const rastrilloModule = "amadan.net/rastrillo/rastrillo" |
| 20 | |
| 21 | // listDeps runs go list with the given arguments and returns its |
| 22 | // output, one import path per line. A go list that cannot run fails |
| 23 | // the test rather than listing nothing: piped straight into a check, |
| 24 | // an empty listing would pass as clean, which is how a toolchain that |
| 25 | // could not fetch itself once passed rastrillo's own graph check. |
| 26 | func listDeps(t *testing.T, args ...string) []string { |
| 27 | t.Helper() |
| 28 | cmd := exec.Command("go", append([]string{"list"}, args...)...) |
| 29 | out, err := cmd.CombinedOutput() |
| 30 | if err != nil { |
| 31 | t.Fatalf("go list %s: %v\n%s", strings.Join(args, " "), err, out) |
| 32 | } |
| 33 | lines := strings.Split(strings.TrimRight(string(out), "\n"), "\n") |
| 34 | if len(lines) == 0 || lines[0] == "" { |
| 35 | t.Fatalf("go list %s printed nothing", strings.Join(args, " ")) |
| 36 | } |
| 37 | return lines |
| 38 | } |
| 39 | |
| 40 | // requireListed is the precondition that keeps either check honest: a |
| 41 | // listing that does not name this module's own package is not a |
| 42 | // listing of this module, whatever else it says. |
| 43 | func requireListed(t *testing.T, lines []string, args string) { |
| 44 | t.Helper() |
| 45 | for _, l := range lines { |
| 46 | if l == "amadan.net/rastrillo/fiesta" { |
| 47 | return |
| 48 | } |
| 49 | } |
| 50 | 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")) |
| 51 | } |
| 52 | |
| 53 | // TestFiestaNeverImportsRastrillo is the global constraint "No |
| 54 | // Rastrillo dependency" as a test: every package of this module, its |
| 55 | // tests included and with the browser tag on (a strict superset of the |
| 56 | // plain build), imports nothing from amadan.net/rastrillo/rastrillo, |
| 57 | // and go.mod never requires it. The go.mod half catches a requirement |
| 58 | // nobody imports yet, which `go list -deps` alone would not see. |
| 59 | func TestFiestaNeverImportsRastrillo(t *testing.T) { |
| 60 | mod, err := os.ReadFile("go.mod") |
| 61 | if err != nil { |
| 62 | t.Fatalf("reading go.mod: %v", err) |
| 63 | } |
| 64 | if strings.Contains(string(mod), rastrilloModule) { |
| 65 | t.Errorf("go.mod mentions %s; Fiesta never requires Rastrillo", rastrilloModule) |
| 66 | } |
| 67 | |
| 68 | args := "-deps -test -tags browser ./..." |
| 69 | lines := listDeps(t, "-deps", "-test", "-tags", "browser", "./...") |
| 70 | requireListed(t, lines, args) |
| 71 | for _, l := range lines { |
| 72 | if strings.HasPrefix(l, rastrilloModule) { |
| 73 | t.Errorf("go list %s reaches %s; Fiesta never imports Rastrillo in any build, tag or test", args, l) |
| 74 | } |
| 75 | } |
| 76 | } |
| 77 | |
| 78 | // TestThePublicPackagesLinkNoBrowser is the other half: the packages |
| 79 | // a Go program imports from Fiesta, the root and example, never link |
| 80 | // chromedp. The browser is for check/ and the drives, and an app that |
| 81 | // embeds the CSS must not take on a Chrome driver to do it. |
| 82 | func TestThePublicPackagesLinkNoBrowser(t *testing.T) { |
| 83 | args := "-deps . ./example" |
| 84 | lines := listDeps(t, "-deps", ".", "./example") |
| 85 | requireListed(t, lines, args) |
| 86 | for _, l := range lines { |
| 87 | if strings.Contains(l, "chromedp") { |
| 88 | t.Errorf("go list %s reaches %s; the public packages never link a browser", args, l) |
| 89 | } |
| 90 | } |
| 91 | } |
| 92 | |