package axe import ( "crypto/sha256" "encoding/hex" "io/fs" "os" "os/exec" "path/filepath" "regexp" "strings" "testing" "amadan.net/rastrillo/fiesta" ) // axe-core is vendored here for the accessibility gate. It is test // data, and this test is what "test data" means here: it is what the // README says it is. // // It runs without a build tag, on every `go test ./...`, because the // day somebody replaces the file is a day this has to fail loudly and // not only when a browser is available. const axeDir = "." // axeReadme parses the pin out of the README beside the file: the // version line and the sha256 line, in the indented block near the top. // The README is the documentation and the manifest at once, so there is // no second place for the two to disagree. var ( axeVersionLine = regexp.MustCompile(`(?m)^\s+version\s+(\S+)\s*$`) axeSHALine = regexp.MustCompile(`(?m)^\s+sha256\s+([0-9a-f]{64})\s*$`) ) func TestVendoredAxeIsThePinnedVersion(t *testing.T) { readme, err := os.ReadFile(filepath.Join(axeDir, "README.md")) if err != nil { t.Fatalf("the vendored axe has no README: %v", err) } vm := axeVersionLine.FindSubmatch(readme) sm := axeSHALine.FindSubmatch(readme) if vm == nil || sm == nil { t.Fatalf("%s/README.md does not name a version and a sha256 in its pin block", axeDir) } body, err := os.ReadFile(filepath.Join(axeDir, "axe.min.js")) if err != nil { t.Fatalf("reading the vendored axe: %v", err) } sum := sha256.Sum256(body) if got := hex.EncodeToString(sum[:]); got != string(sm[1]) { t.Errorf("axe.min.js is sha256 %s; the README pins %s", got, sm[1]) } // Deque stamps the version into the banner comment, so the file // says its own version and the README cannot drift from it quietly. want := "axe v" + string(vm[1]) if head := string(body[:min(len(body), 200)]); !strings.Contains(head, want) { t.Errorf("the README pins %s, but the file's banner does not say %q", vm[1], want) } } // TestTheShippedTreeCarriesNoAxe is the other half of "test data": the // engine reaches nothing a Go program imports from Fiesta. The root // package embeds its tree by directory, so the check is of what those // directories hold, by the banner every build of axe-core carries and // no hand-written asset does; and the packages a program imports, the // root and example, pull this package into no build. The release has // the same check over its own files, TestVendoredAxeIsNotAShippedAsset // in internal/build. func TestTheShippedTreeCarriesNoAxe(t *testing.T) { const marker = "Deque Systems" if !strings.Contains(script, marker) { t.Fatalf("the vendored engine does not carry %q; the check below would be looking for nothing", marker) } files := 0 err := fs.WalkDir(fiesta.FS(), ".", func(p string, d fs.DirEntry, err error) error { if err != nil { return err } if d.IsDir() { return nil } files++ b, err := fs.ReadFile(fiesta.FS(), p) if err != nil { return err } if strings.Contains(string(b), marker) { t.Errorf("%s carries the vendored axe-core: it is test data and must not ship", p) } return nil }) if err != nil { t.Fatal(err) } if files == 0 { t.Fatal("the embedded tree holds no files; the walk above checked nothing") } out, err := exec.Command("go", "list", "-deps", "amadan.net/rastrillo/fiesta", "amadan.net/rastrillo/fiesta/example").CombinedOutput() if err != nil { t.Fatalf("go list -deps: %v\n%s", err, out) } deps := strings.Split(strings.TrimSpace(string(out)), "\n") listed := false for _, dep := range deps { listed = listed || dep == "amadan.net/rastrillo/fiesta" if strings.HasSuffix(dep, "/internal/axe") { t.Errorf("the public packages import %s; the engine is for the drives alone", dep) } } if !listed { t.Fatalf("go list -deps did not list the root package itself:\n%s", out) } }