1
16
17 package main
18
19 import (
20 "path/filepath"
21 "reflect"
22 "strings"
23 "testing"
24
25 "golang.org/x/tools/go/packages"
26 )
27
28 func TestRemoveLastDir(t *testing.T) {
29 table := map[string]struct{ newPath, removedDir string }{
30 "a/b/c": {"a/c", "b"},
31 }
32 for slashInput, expect := range table {
33 input := filepath.FromSlash(slashInput)
34
35 gotPath, gotRemoved := removeLastDir(input)
36 if e, a := filepath.FromSlash(expect.newPath), gotPath; e != a {
37 t.Errorf("%v: wanted %v, got %v", input, e, a)
38 }
39 if e, a := filepath.FromSlash(expect.removedDir), gotRemoved; e != a {
40 t.Errorf("%v: wanted %v, got %v", input, e, a)
41 }
42 }
43 }
44
45 func TestTransitiveClosure(t *testing.T) {
46 cases := []struct {
47 name string
48 in map[string][]string
49 expected map[string][]string
50 }{
51 {
52 name: "no transition",
53 in: map[string][]string{
54 "a": {"b"},
55 "c": {"d"},
56 },
57 expected: map[string][]string{
58 "a": {"b"},
59 "c": {"d"},
60 },
61 },
62 {
63 name: "simple",
64 in: map[string][]string{
65 "a": {"b"},
66 "b": {"c"},
67 "c": {"d"},
68 },
69 expected: map[string][]string{
70 "a": {"b", "c", "d"},
71 "b": {"c", "d"},
72 "c": {"d"},
73 },
74 },
75 }
76
77 for _, c := range cases {
78 t.Run(c.name, func(t *testing.T) {
79 out := transitiveClosure(c.in)
80 if !reflect.DeepEqual(c.expected, out) {
81 t.Errorf("expected: %#v, got %#v", c.expected, out)
82 }
83 })
84 }
85 }
86
87 func TestHasTestFiles(t *testing.T) {
88 cases := []struct {
89 input []string
90 expect bool
91 }{{
92 input: nil,
93 expect: false,
94 }, {
95 input: []string{},
96 expect: false,
97 }, {
98 input: []string{"foo.go"},
99 expect: false,
100 }, {
101 input: []string{"foo.go", "bar.go"},
102 expect: false,
103 }, {
104 input: []string{"foo_test.go"},
105 expect: true,
106 }, {
107 input: []string{"foo.go", "foo_test.go"},
108 expect: true,
109 }, {
110 input: []string{"foo.go", "foo_test.go", "bar.go", "bar_test.go"},
111 expect: true,
112 }}
113
114 for _, tc := range cases {
115 ret := hasTestFiles(tc.input)
116 if ret != tc.expect {
117 t.Errorf("expected %v, got %v: %q", tc.expect, ret, tc.input)
118 }
119 }
120 }
121
122 func TestPackageDir(t *testing.T) {
123 cases := []struct {
124 input *packages.Package
125 expect string
126 }{{
127 input: &packages.Package{
128 PkgPath: "example.com/foo/bar/qux",
129 GoFiles: []string{"/src/prj/file.go"},
130 IgnoredFiles: []string{"/otherdir/file.go"},
131 },
132 expect: "/src/prj",
133 }, {
134 input: &packages.Package{
135 PkgPath: "example.com/foo/bar/qux",
136 IgnoredFiles: []string{"/src/prj/file.go"},
137 },
138 expect: "/src/prj",
139 }, {
140 input: &packages.Package{
141 PkgPath: "example.com/foo/bar/qux",
142 },
143 expect: "",
144 }}
145
146 for i, tc := range cases {
147 ret := packageDir(tc.input)
148 if ret != tc.expect {
149 t.Errorf("[%d] expected %v, got %v: %q", i, tc.expect, ret, tc.input)
150 }
151 }
152 }
153
154 func TestHasPathPrefix(t *testing.T) {
155 cases := []struct {
156 base string
157 pfx string
158 expect bool
159 }{{
160 base: "",
161 pfx: "",
162 expect: true,
163 }, {
164 base: "/foo/bar",
165 pfx: "",
166 expect: true,
167 }, {
168 base: "",
169 pfx: "/foo",
170 expect: false,
171 }, {
172 base: "/foo",
173 pfx: "/foo",
174 expect: true,
175 }, {
176 base: "/foo/bar",
177 pfx: "/foo",
178 expect: true,
179 }, {
180 base: "/foobar/qux",
181 pfx: "/foo",
182 expect: false,
183 }, {
184 base: "/foo/bar/bat/qux/zrb",
185 pfx: "/foo/bar/bat",
186 expect: true,
187 }}
188
189 for _, tc := range cases {
190 ret := hasPathPrefix(tc.base, tc.pfx)
191 if ret != tc.expect {
192 t.Errorf("expected %v, got %v: (%q, %q)", tc.expect, ret, tc.base, tc.pfx)
193 }
194 }
195 }
196
197 func checkAllErrorStrings(t *testing.T, errs []error, expect []string) {
198 t.Helper()
199 if len(errs) != len(expect) {
200 t.Fatalf("expected %d errors, got %d: %q", len(expect), len(errs), errs)
201 }
202
203 for _, str := range expect {
204 found := false
205 for _, err := range errs {
206 if strings.HasPrefix(err.Error(), str) {
207 found = true
208 break
209 }
210 }
211 if !found {
212 t.Errorf("did not find error %q", str)
213 t.Logf("\tseek: %s\n\t in:", str)
214 for _, err := range errs {
215 t.Logf("\t %s", err.Error())
216 }
217 }
218 }
219 }
220
221 func TestSimpleForward(t *testing.T) {
222 pkgs, err := loadPkgs("./testdata/simple-fwd/aaa")
223 if err != nil {
224 t.Fatalf("unexpected failure: %v", err)
225 }
226 if len(pkgs) != 1 {
227 t.Fatalf("expected 1 pkg result, got %d", len(pkgs))
228 }
229 if pkgs[0].PkgPath != "k8s.io/kubernetes/cmd/import-boss/testdata/simple-fwd/aaa" {
230 t.Fatalf("wrong PkgPath: %q", pkgs[0].PkgPath)
231 }
232
233 boss := newBoss(pkgs)
234 errs := boss.Verify(pkgs[0])
235
236 expect := []string{
237 `"k8s.io/kubernetes/cmd/import-boss/testdata/simple-fwd/aaa" -> "k8s.io/kubernetes/cmd/import-boss/testdata/simple-fwd/forbidden" is forbidden`,
238 `"k8s.io/kubernetes/cmd/import-boss/testdata/simple-fwd/aaa" -> "k8s.io/kubernetes/cmd/import-boss/testdata/simple-fwd/forbidden/f1" is forbidden`,
239 `"k8s.io/kubernetes/cmd/import-boss/testdata/simple-fwd/aaa" -> "k8s.io/kubernetes/cmd/import-boss/testdata/simple-fwd/neither" did not match any rule`,
240 `"k8s.io/kubernetes/cmd/import-boss/testdata/simple-fwd/aaa" -> "k8s.io/kubernetes/cmd/import-boss/testdata/simple-fwd/neither/n1" did not match any rule`,
241 }
242
243 checkAllErrorStrings(t, errs, expect)
244 }
245
246 func TestNestedForward(t *testing.T) {
247 pkgs, err := loadPkgs("./testdata/nested-fwd/aaa")
248 if err != nil {
249 t.Fatalf("unexpected failure: %v", err)
250 }
251 if len(pkgs) != 1 {
252 t.Fatalf("expected 1 pkg result, got %d", len(pkgs))
253 }
254 if pkgs[0].PkgPath != "k8s.io/kubernetes/cmd/import-boss/testdata/nested-fwd/aaa" {
255 t.Fatalf("wrong PkgPath: %q", pkgs[0].PkgPath)
256 }
257
258 boss := newBoss(pkgs)
259 errs := boss.Verify(pkgs[0])
260
261 expect := []string{
262 `"k8s.io/kubernetes/cmd/import-boss/testdata/nested-fwd/aaa" -> "k8s.io/kubernetes/cmd/import-boss/testdata/nested-fwd/forbidden-by-both" is forbidden`,
263 `"k8s.io/kubernetes/cmd/import-boss/testdata/nested-fwd/aaa" -> "k8s.io/kubernetes/cmd/import-boss/testdata/nested-fwd/forbidden-by-root" is forbidden`,
264 `"k8s.io/kubernetes/cmd/import-boss/testdata/nested-fwd/aaa" -> "k8s.io/kubernetes/cmd/import-boss/testdata/nested-fwd/forbidden-by-sub" is forbidden`,
265 `"k8s.io/kubernetes/cmd/import-boss/testdata/nested-fwd/aaa" -> "k8s.io/kubernetes/cmd/import-boss/testdata/nested-fwd/neither/n1" did not match any rule`,
266 }
267
268 checkAllErrorStrings(t, errs, expect)
269 }
270
271 func TestInverse(t *testing.T) {
272 pkgs, err := loadPkgs("./testdata/inverse/...")
273 if err != nil {
274 t.Fatalf("unexpected failure: %v", err)
275 }
276 if len(pkgs) != 10 {
277 t.Fatalf("expected 10 pkg results, got %d", len(pkgs))
278 }
279
280 boss := newBoss(pkgs)
281
282 var errs []error
283 for _, pkg := range pkgs {
284 errs = append(errs, boss.Verify(pkg)...)
285 }
286
287 expect := []string{
288 `"k8s.io/kubernetes/cmd/import-boss/testdata/inverse/forbidden" <- "k8s.io/kubernetes/cmd/import-boss/testdata/inverse/aaa" is forbidden`,
289 `"k8s.io/kubernetes/cmd/import-boss/testdata/inverse/forbidden/f1" <- "k8s.io/kubernetes/cmd/import-boss/testdata/inverse/aaa" is forbidden`,
290 `"k8s.io/kubernetes/cmd/import-boss/testdata/inverse/allowed/a2" <- "k8s.io/kubernetes/cmd/import-boss/testdata/inverse/allowed" did not match any rule`,
291 `"k8s.io/kubernetes/cmd/import-boss/testdata/inverse/forbidden/f2" <- "k8s.io/kubernetes/cmd/import-boss/testdata/inverse/allowed" did not match any rule`,
292 }
293
294 checkAllErrorStrings(t, errs, expect)
295 }
296
297 func TestTransitive(t *testing.T) {
298 pkgs, err := loadPkgs("./testdata/transitive/...")
299 if err != nil {
300 t.Fatalf("unexpected failure: %v", err)
301 }
302 if len(pkgs) != 10 {
303 t.Fatalf("expected 10 pkg results, got %d", len(pkgs))
304 }
305
306 boss := newBoss(pkgs)
307
308 var errs []error
309 for _, pkg := range pkgs {
310 errs = append(errs, boss.Verify(pkg)...)
311 }
312
313 expect := []string{
314 `"k8s.io/kubernetes/cmd/import-boss/testdata/transitive/forbidden" <- "k8s.io/kubernetes/cmd/import-boss/testdata/transitive/aaa" is forbidden`,
315 `"k8s.io/kubernetes/cmd/import-boss/testdata/transitive/forbidden/f1" <- "k8s.io/kubernetes/cmd/import-boss/testdata/transitive/aaa" is forbidden`,
316 `"k8s.io/kubernetes/cmd/import-boss/testdata/transitive/forbidden/f2" <-- "k8s.io/kubernetes/cmd/import-boss/testdata/transitive/aaa" is forbidden`,
317 `"k8s.io/kubernetes/cmd/import-boss/testdata/transitive/allowed/a2" <- "k8s.io/kubernetes/cmd/import-boss/testdata/transitive/allowed" did not match any rule`,
318 `"k8s.io/kubernetes/cmd/import-boss/testdata/transitive/forbidden/f2" <- "k8s.io/kubernetes/cmd/import-boss/testdata/transitive/allowed" did not match any rule`,
319 }
320
321 checkAllErrorStrings(t, errs, expect)
322 }
323
View as plain text