| // Copyright 2020 The Go Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file. | |
| package analysis | |
| import ( | |
| "strings" | |
| "testing" | |
| ) | |
| func TestValidate(t *testing.T) { | |
| var ( | |
| dependsOnSelf = &Analyzer{ | |
| Name: "dependsOnSelf", | |
| Doc: "this analyzer depends on itself", | |
| } | |
| inCycleA = &Analyzer{ | |
| Name: "inCycleA", | |
| Doc: "this analyzer depends on inCycleB", | |
| } | |
| inCycleB = &Analyzer{ | |
| Name: "inCycleB", | |
| Doc: "this analyzer depends on inCycleA and notInCycleA", | |
| } | |
| pointsToCycle = &Analyzer{ | |
| Name: "pointsToCycle", | |
| Doc: "this analyzer depends on inCycleA", | |
| } | |
| notInCycleA = &Analyzer{ | |
| Name: "notInCycleA", | |
| Doc: "this analyzer depends on notInCycleB and notInCycleC", | |
| } | |
| notInCycleB = &Analyzer{ | |
| Name: "notInCycleB", | |
| Doc: "this analyzer depends on notInCycleC", | |
| } | |
| notInCycleC = &Analyzer{ | |
| Name: "notInCycleC", | |
| Doc: "this analyzer has no dependencies", | |
| } | |
| ) | |
| dependsOnSelf.Requires = append(dependsOnSelf.Requires, dependsOnSelf) | |
| inCycleA.Requires = append(inCycleA.Requires, inCycleB) | |
| inCycleB.Requires = append(inCycleB.Requires, inCycleA, notInCycleA) | |
| pointsToCycle.Requires = append(pointsToCycle.Requires, inCycleA) | |
| notInCycleA.Requires = append(notInCycleA.Requires, notInCycleB, notInCycleC) | |
| notInCycleB.Requires = append(notInCycleB.Requires, notInCycleC) | |
| notInCycleC.Requires = []*Analyzer{} | |
| cases := []struct { | |
| analyzers []*Analyzer | |
| wantErr bool | |
| analyzersInCycle map[string]bool | |
| }{ | |
| { | |
| []*Analyzer{dependsOnSelf}, | |
| true, | |
| map[string]bool{"dependsOnSelf": true}, | |
| }, | |
| { | |
| []*Analyzer{inCycleA, inCycleB}, | |
| true, | |
| map[string]bool{"inCycleA": true, "inCycleB": true}, | |
| }, | |
| { | |
| []*Analyzer{pointsToCycle}, | |
| true, | |
| map[string]bool{"inCycleA": true, "inCycleB": true}, | |
| }, | |
| { | |
| []*Analyzer{notInCycleA}, | |
| false, | |
| map[string]bool{}, | |
| }, | |
| } | |
| for _, c := range cases { | |
| got := Validate(c.analyzers) | |
| if !c.wantErr { | |
| if got == nil { | |
| continue | |
| } | |
| t.Errorf("got unexpected error while validating analyzers %v: %v", c.analyzers, got) | |
| } | |
| if got == nil { | |
| t.Errorf("expected error while validating analyzers %v, but got nil", c.analyzers) | |
| } | |
| err, ok := got.(*CycleInRequiresGraphError) | |
| if !ok { | |
| t.Errorf("want CycleInRequiresGraphError, got %T", err) | |
| } | |
| for a := range c.analyzersInCycle { | |
| if !err.AnalyzerNames[a] { | |
| t.Errorf("analyzer %s should be in cycle", a) | |
| } | |
| } | |
| for a := range err.AnalyzerNames { | |
| if !c.analyzersInCycle[a] { | |
| t.Errorf("analyzer %s should not be in cycle", a) | |
| } | |
| } | |
| } | |
| } | |
| func TestCycleInRequiresGraphErrorMessage(t *testing.T) { | |
| err := CycleInRequiresGraphError{} | |
| errMsg := err.Error() | |
| wantSubstring := "cycle detected" | |
| if !strings.Contains(errMsg, wantSubstring) { | |
| t.Errorf("error string %s does not contain expected substring %q", errMsg, wantSubstring) | |
| } | |
| } |