v0.3.0 99dc266

boundary_test.go RawHistoryFolder

1package main_test
2
3import (
4	"go/parser"
5	"go/token"
6	"io/fs"
7	"path/filepath"
8	"strings"
9	"testing"
10)
11
12// boundaryRule expresses a single import-boundary constraint: no .go file
13// under root may import a package whose path has disallowedPrefix.
14type boundaryRule struct {
15	name             string
16	root             string
17	disallowedPrefix string
18}
19
20func TestImportBoundaries(t *testing.T) {
21	rules := []boundaryRule{
22		{
23			name:             "pkg must not import internal",
24			root:             "pkg",
25			disallowedPrefix: "github.com/bnema/vev/internal",
26		},
27		{
28			name:             "usecase must not import adapters",
29			root:             "internal/usecase",
30			disallowedPrefix: "github.com/bnema/vev/internal/adapters",
31		},
32		{
33			name:             "usecase must not import platform",
34			root:             "internal/usecase",
35			disallowedPrefix: "github.com/bnema/vev/internal/platform",
36		},
37	}
38
39	for _, rule := range rules {
40		t.Run(rule.name, func(t *testing.T) {
41			violations := findImportViolations(t, rule.root, rule.disallowedPrefix)
42			if len(violations) > 0 {
43				t.Errorf("found disallowed imports of %q under %q:\n%s", rule.disallowedPrefix, rule.root, strings.Join(violations, "\n"))
44			}
45		})
46	}
47}
48
49// findImportViolations walks root, parses each .go file's imports, and
50// returns a description for every import whose path starts with
51// disallowedPrefix.
52func findImportViolations(t *testing.T, root, disallowedPrefix string) []string {
53	t.Helper()
54
55	var violations []string
56	fset := token.NewFileSet()
57
58	err := filepath.WalkDir(root, func(path string, d fs.DirEntry, err error) error {
59		if err != nil {
60			return err
61		}
62		if d.IsDir() || !strings.HasSuffix(path, ".go") {
63			return nil
64		}
65
66		f, err := parser.ParseFile(fset, path, nil, parser.ImportsOnly)
67		if err != nil {
68			return err
69		}
70
71		for _, imp := range f.Imports {
72			importPath := strings.Trim(imp.Path.Value, `"`)
73			if strings.HasPrefix(importPath, disallowedPrefix) {
74				violations = append(violations, path+": imports "+importPath)
75			}
76		}
77		return nil
78	})
79	if err != nil {
80		t.Fatalf("walking %s: %v", root, err)
81	}
82
83	return violations
84}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 12

Tags 11

↑↓ moveenter openesc close