1
2
3
4
5 package analysis
6
7 import (
8 "strings"
9 "testing"
10 )
11
12 func TestValidate(t *testing.T) {
13 var (
14 run = func(p *Pass) (interface{}, error) {
15 return nil, nil
16 }
17 dependsOnSelf = &Analyzer{
18 Name: "dependsOnSelf",
19 Doc: "this analyzer depends on itself",
20 Run: run,
21 }
22 inCycleA = &Analyzer{
23 Name: "inCycleA",
24 Doc: "this analyzer depends on inCycleB",
25 Run: run,
26 }
27 inCycleB = &Analyzer{
28 Name: "inCycleB",
29 Doc: "this analyzer depends on inCycleA and notInCycleA",
30 Run: run,
31 }
32 pointsToCycle = &Analyzer{
33 Name: "pointsToCycle",
34 Doc: "this analyzer depends on inCycleA",
35 Run: run,
36 }
37 notInCycleA = &Analyzer{
38 Name: "notInCycleA",
39 Doc: "this analyzer depends on notInCycleB and notInCycleC",
40 Run: run,
41 }
42 notInCycleB = &Analyzer{
43 Name: "notInCycleB",
44 Doc: "this analyzer depends on notInCycleC",
45 Run: run,
46 }
47 notInCycleC = &Analyzer{
48 Name: "notInCycleC",
49 Doc: "this analyzer has no dependencies",
50 Run: run,
51 }
52 )
53
54 dependsOnSelf.Requires = append(dependsOnSelf.Requires, dependsOnSelf)
55 inCycleA.Requires = append(inCycleA.Requires, inCycleB)
56 inCycleB.Requires = append(inCycleB.Requires, inCycleA, notInCycleA)
57 pointsToCycle.Requires = append(pointsToCycle.Requires, inCycleA)
58 notInCycleA.Requires = append(notInCycleA.Requires, notInCycleB, notInCycleC)
59 notInCycleB.Requires = append(notInCycleB.Requires, notInCycleC)
60 notInCycleC.Requires = []*Analyzer{}
61
62 cases := []struct {
63 analyzers []*Analyzer
64 wantErr bool
65 analyzersInCycle map[string]bool
66 }{
67 {
68 []*Analyzer{dependsOnSelf},
69 true,
70 map[string]bool{"dependsOnSelf": true},
71 },
72 {
73 []*Analyzer{inCycleA, inCycleB},
74 true,
75 map[string]bool{"inCycleA": true, "inCycleB": true},
76 },
77 {
78 []*Analyzer{pointsToCycle},
79 true,
80 map[string]bool{"inCycleA": true, "inCycleB": true},
81 },
82 {
83 []*Analyzer{notInCycleA},
84 false,
85 map[string]bool{},
86 },
87 }
88
89 for _, c := range cases {
90 got := Validate(c.analyzers)
91
92 if !c.wantErr {
93 if got == nil {
94 continue
95 }
96 t.Errorf("got unexpected error while validating analyzers %v: %v", c.analyzers, got)
97 }
98
99 if got == nil {
100 t.Errorf("expected error while validating analyzers %v, but got nil", c.analyzers)
101 }
102
103 err, ok := got.(*CycleInRequiresGraphError)
104 if !ok {
105 t.Errorf("want CycleInRequiresGraphError, got %T", err)
106 }
107
108 for a := range c.analyzersInCycle {
109 if !err.AnalyzerNames[a] {
110 t.Errorf("analyzer %s should be in cycle", a)
111 }
112 }
113 for a := range err.AnalyzerNames {
114 if !c.analyzersInCycle[a] {
115 t.Errorf("analyzer %s should not be in cycle", a)
116 }
117 }
118 }
119 }
120
121 func TestCycleInRequiresGraphErrorMessage(t *testing.T) {
122 err := CycleInRequiresGraphError{}
123 errMsg := err.Error()
124 wantSubstring := "cycle detected"
125 if !strings.Contains(errMsg, wantSubstring) {
126 t.Errorf("error string %s does not contain expected substring %q", errMsg, wantSubstring)
127 }
128 }
129
130 func TestValidateEmptyDoc(t *testing.T) {
131 withoutDoc := &Analyzer{
132 Name: "withoutDoc",
133 Run: func(p *Pass) (interface{}, error) {
134 return nil, nil
135 },
136 }
137 err := Validate([]*Analyzer{withoutDoc})
138 if err == nil || !strings.Contains(err.Error(), "is undocumented") {
139 t.Errorf("got unexpected error while validating analyzers withoutDoc: %v", err)
140 }
141 }
142
143 func TestValidateNoRun(t *testing.T) {
144 withoutRun := &Analyzer{
145 Name: "withoutRun",
146 Doc: "this analyzer has no Run",
147 }
148 err := Validate([]*Analyzer{withoutRun})
149 if err == nil || !strings.Contains(err.Error(), "has nil Run") {
150 t.Errorf("got unexpected error while validating analyzers withoutRun: %v", err)
151 }
152 }
153
View as plain text