package main import ( "os" "path/filepath" "strings" "testing" ) func tree(t *testing.T, files map[string]string) string { t.Helper() root := t.TempDir() for p, c := range files { full := filepath.Join(root, p) if err := os.MkdirAll(filepath.Dir(full), 0o755); err != nil { t.Fatal(err) } if err := os.WriteFile(full, []byte(c), 0o644); err != nil { t.Fatal(err) } } return root } const aMod = "module git.novox.be/novox/r/a\n\ngo 1.22\n" const bMod = "module git.novox.be/novox/r/b/sub\n\ngo 1.22\n" // A module that imports a package of a mesh module its go.mod does not require is refused, in a test file and behind a // build tag too; the module's own packages, a required module's and a nested module's (only when required) are not. func TestAModuleImportsOnlyWhatItRequires(t *testing.T) { src := func(imp string) string { return "package x\n\nimport _ \"" + imp + "\"\n" } for _, row := range []struct { name string files map[string]string want string }{ {"its own package", map[string]string{"a/go.mod": aMod, "a/x.go": src("git.novox.be/novox/r/a/other")}, ""}, {"a required module", map[string]string{"a/go.mod": aMod + "\nrequire git.novox.be/novox/r/b/sub v0.0.0\n", "a/x.go": src("git.novox.be/novox/r/b/sub/pkg"), "b/go.mod": bMod}, ""}, {"a required module in a block", map[string]string{"a/go.mod": aMod + "\nrequire (\n\tgit.novox.be/novox/r/b/sub v0.0.0 // indirect\n)\n", "a/x.go": src("git.novox.be/novox/r/b/sub/pkg"), "b/go.mod": bMod}, ""}, {"a module not required", map[string]string{"a/go.mod": aMod, "a/x.go": src("git.novox.be/novox/r/b/sub/pkg"), "b/go.mod": bMod}, "x.go imports git.novox.be/novox/r/b/sub/pkg"}, {"a test file", map[string]string{"a/go.mod": aMod, "a/x_test.go": src("git.novox.be/novox/r/b/sub/pkg"), "b/go.mod": bMod}, "x_test.go imports"}, {"an integration file", map[string]string{"a/go.mod": aMod, "a/x.go": "//go:build integration\n\n" + src("git.novox.be/novox/r/b/sub/pkg"), "b/go.mod": bMod}, "x.go imports"}, {"a module the longest owner is not", map[string]string{"a/go.mod": aMod + "\nrequire git.novox.be/novox/r/b v0.0.0\n", "a/x.go": src("git.novox.be/novox/r/b/sub/pkg"), "b/go.mod": "module git.novox.be/novox/r/b\n", "b/sub/go.mod": bMod}, "does not require"}, {"a testdata fixture", map[string]string{"a/go.mod": aMod, "a/testdata/x.go": src("git.novox.be/novox/r/b/sub/pkg"), "a/x.go": "package x\n"}, ""}, {"an outside module", map[string]string{"a/go.mod": aMod, "a/x.go": src("github.com/x/y")}, ""}, } { t.Run(row.name, func(t *testing.T) { got, err := Findings([]string{tree(t, row.files)}, nil) if err != nil { t.Fatal(err) } if all := strings.Join(got, "\n"); (row.want == "") != (all == "") || !strings.Contains(all, row.want) { t.Fatalf("findings = %q, want one containing %q", all, row.want) } }) } } // The script's run of this check over the real tree (novox/hq ADR 0529 clause 2): the repositories cloned beside it, when // the check says where, tell which module owns a path. func TestEveryCatalogueModuleRequiresWhatItImports(t *testing.T) { var known []string if beside := os.Getenv("MESH_CHECK_BESIDE"); beside != "" { es, _ := os.ReadDir(beside) for _, e := range es { if e.IsDir() && e.Name() != "mesh-catalog" { known = append(known, filepath.Join(beside, e.Name())) } } } got, err := Findings([]string{filepath.Join("..", "..")}, known) if err != nil { t.Fatal(err) } for _, f := range got { t.Error(f) } }