--- /dev/null
+// 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)
+ }
+}