package adapter_test import ( "fmt" "go/parser" "go/token" "io/fs" "os" "path/filepath" "runtime" "strconv" "strings" "testing" ) const ( scriptoriumModulePath = "gitea.maximumdirect.net/eric/scriptorium" promptkitInternalPath = "gitea.maximumdirect.net/eric/promptkit/internal" ) var ( removedFrameworkPackageRoots = []string{ scriptoriumModulePath + "/internal/artifact", scriptoriumModulePath + "/internal/domain", scriptoriumModulePath + "/internal/filecatalog", scriptoriumModulePath + "/internal/llm", scriptoriumModulePath + "/internal/profile", scriptoriumModulePath + "/internal/prompt", scriptoriumModulePath + "/internal/promptdef", scriptoriumModulePath + "/internal/usecase", scriptoriumModulePath + "/internal/validate", } removedFrameworkDirectories = []string{ "internal/artifact", "internal/domain", "internal/filecatalog", "internal/llm", "internal/profile", "internal/prompt", "internal/promptdef", "internal/usecase", "internal/validate", } nonSourceDirectories = map[string]struct{}{ ".cache": {}, ".codebase-memory": {}, ".git": {}, "build": {}, "coverage": {}, "dist": {}, "node_modules": {}, "out": {}, "testdata": {}, "vendor": {}, } ) type forbiddenImport struct { filePath string importPath string } func TestApplicationBoundary(t *testing.T) { moduleRoot := moduleRootFromTestFile(t) violations, err := findForbiddenProductionImports(moduleRoot) if err != nil { t.Fatalf("scan production imports: %v", err) } for _, violation := range violations { t.Errorf("%s imports forbidden package %s", violation.filePath, violation.importPath) } assertFrameworkImplementationAbsent(t, moduleRoot) } func TestForbiddenImportScannerDetectsFormerRoot(t *testing.T) { root := t.TempDir() sourcePath := writeGoSource(t, root, "nested/consumer/root.go", scriptoriumModulePath) violations, err := findForbiddenProductionImports(root) if err != nil { t.Fatalf("scan source fixture: %v", err) } assertSingleViolation(t, violations, sourcePath, scriptoriumModulePath) } func TestForbiddenImportScannerDetectsFormerFrameworkFamily(t *testing.T) { root := t.TempDir() importPath := scriptoriumModulePath + "/internal/profile/builtin" sourcePath := writeGoSource(t, root, "nested/consumer/profile.go", importPath) violations, err := findForbiddenProductionImports(root) if err != nil { t.Fatalf("scan source fixture: %v", err) } assertSingleViolation(t, violations, sourcePath, importPath) } func TestForbiddenImportScannerDetectsPromptkitInternalPackages(t *testing.T) { tests := []struct { name string importPath string }{ {name: "exact internal root", importPath: promptkitInternalPath}, {name: "internal descendant", importPath: promptkitInternalPath + "/domain"}, } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { root := t.TempDir() sourcePath := writeGoSource(t, root, "nested/consumer/promptkit.go", tc.importPath) violations, err := findForbiddenProductionImports(root) if err != nil { t.Fatalf("scan source fixture: %v", err) } assertSingleViolation(t, violations, sourcePath, tc.importPath) }) } } func TestForbiddenImportScannerAllowsRetainedApplicationPackages(t *testing.T) { root := t.TempDir() sourcePath := filepath.Join(root, "nested/consumer/application.go") if err := os.MkdirAll(filepath.Dir(sourcePath), 0o755); err != nil { t.Fatalf("create source fixture directory: %v", err) } source := `package consumer import ( _ "gitea.maximumdirect.net/eric/promptkit" _ "gitea.maximumdirect.net/eric/scriptorium/internal/adapter/http" _ "gitea.maximumdirect.net/eric/scriptorium/internal/config" _ "gitea.maximumdirect.net/eric/scriptorium/internal/defaults" _ "gitea.maximumdirect.net/eric/scriptorium/internal/format" ) ` if err := os.WriteFile(sourcePath, []byte(source), 0o644); err != nil { t.Fatalf("write source fixture: %v", err) } violations, err := findForbiddenProductionImports(root) if err != nil { t.Fatalf("scan source fixture: %v", err) } if len(violations) != 0 { t.Fatalf("expected retained application imports to be allowed, got %#v", violations) } } func findForbiddenProductionImports(root string) ([]forbiddenImport, error) { var violations []forbiddenImport err := filepath.WalkDir(root, func(path string, entry fs.DirEntry, err error) error { if err != nil { return err } if entry.IsDir() { if path != root && shouldSkipSourceDirectory(entry.Name()) { return filepath.SkipDir } return nil } if !strings.HasSuffix(entry.Name(), ".go") || strings.HasSuffix(entry.Name(), "_test.go") { return nil } file, err := parser.ParseFile(token.NewFileSet(), path, nil, parser.ImportsOnly) if err != nil { return fmt.Errorf("parse imports in %s: %w", path, err) } for _, imported := range file.Imports { importPath, err := strconv.Unquote(imported.Path.Value) if err != nil { return fmt.Errorf("parse import path in %s: %w", path, err) } if isForbiddenProductionImport(importPath) { violations = append(violations, forbiddenImport{ filePath: path, importPath: importPath, }) } } return nil }) if err != nil { return nil, fmt.Errorf("walk repository root %s: %w", root, err) } return violations, nil } func shouldSkipSourceDirectory(name string) bool { _, skip := nonSourceDirectories[name] return skip } func isForbiddenProductionImport(importPath string) bool { if importPath == scriptoriumModulePath { return true } if importPath == promptkitInternalPath || strings.HasPrefix(importPath, promptkitInternalPath+"/") { return true } for _, root := range removedFrameworkPackageRoots { if importPath == root || strings.HasPrefix(importPath, root+"/") { return true } } return false } func moduleRootFromTestFile(t *testing.T) string { t.Helper() _, testFile, _, ok := runtime.Caller(0) if !ok { t.Fatal("locate dependency guard source") } root, err := findModuleRoot(filepath.Dir(testFile)) if err != nil { t.Fatal(err) } return root } func findModuleRoot(start string) (string, error) { dir, err := filepath.Abs(start) if err != nil { return "", fmt.Errorf("resolve module search path: %w", err) } for { goMod := filepath.Join(dir, "go.mod") if info, err := os.Stat(goMod); err == nil && !info.IsDir() { return dir, nil } else if err != nil && !os.IsNotExist(err) { return "", fmt.Errorf("inspect %s: %w", goMod, err) } parent := filepath.Dir(dir) if parent == dir { return "", fmt.Errorf("locate go.mod from %s", start) } dir = parent } } func assertFrameworkImplementationAbsent(t *testing.T, moduleRoot string) { t.Helper() entries, err := os.ReadDir(moduleRoot) if err != nil { t.Fatalf("read module root: %v", err) } for _, entry := range entries { if !entry.IsDir() && strings.HasSuffix(entry.Name(), ".go") && !strings.HasSuffix(entry.Name(), "_test.go") { t.Errorf("module root contains production Go file %s", entry.Name()) } } for _, relativePath := range removedFrameworkDirectories { path := filepath.Join(moduleRoot, filepath.FromSlash(relativePath)) if _, err := os.Stat(path); err == nil { t.Errorf("removed framework directory still exists: %s", relativePath) } else if !os.IsNotExist(err) { t.Errorf("inspect removed framework directory %s: %v", relativePath, err) } } } func writeGoSource(t *testing.T, root, relativePath, importPath string) string { t.Helper() sourcePath := filepath.Join(root, filepath.FromSlash(relativePath)) if err := os.MkdirAll(filepath.Dir(sourcePath), 0o755); err != nil { t.Fatalf("create source fixture directory: %v", err) } source := fmt.Sprintf("package consumer\n\nimport _ %q\n", importPath) if err := os.WriteFile(sourcePath, []byte(source), 0o644); err != nil { t.Fatalf("write source fixture: %v", err) } return sourcePath } func assertSingleViolation(t *testing.T, violations []forbiddenImport, sourcePath, importPath string) { t.Helper() if len(violations) != 1 { t.Fatalf("expected one forbidden import, got %#v", violations) } if violations[0].filePath != sourcePath { t.Fatalf("unexpected importing file: %q", violations[0].filePath) } if violations[0].importPath != importPath { t.Fatalf("unexpected forbidden import: %q", violations[0].importPath) } }