golang.org/x/tools@v0.21.0/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  }