github.com/powerman/golang-tools@v0.1.11-0.20220410185822-5ad214d8d803/go/analysis/validate_test.go (about) 1 // Copyright 2020 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 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 }