github.com/nozzle/golangci-lint@v1.49.0-nz3/pkg/golinters/nolintlint/nolintlint_test.go (about)

     1  package nolintlint
     2  
     3  import (
     4  	"go/parser"
     5  	"go/token"
     6  	"testing"
     7  
     8  	"github.com/stretchr/testify/assert"
     9  	"github.com/stretchr/testify/require"
    10  
    11  	"github.com/golangci/golangci-lint/pkg/result"
    12  )
    13  
    14  //nolint:funlen
    15  func TestLinter_Run(t *testing.T) {
    16  	type issueWithReplacement struct {
    17  		issue       string
    18  		replacement *result.Replacement
    19  	}
    20  	testCases := []struct {
    21  		desc     string
    22  		needs    Needs
    23  		excludes []string
    24  		contents string
    25  		expected []issueWithReplacement
    26  	}{
    27  		{
    28  			desc:  "when no explanation is provided",
    29  			needs: NeedsExplanation,
    30  			contents: `
    31  package bar
    32  
    33  // example
    34  //nolint
    35  func foo() {
    36    bad() //nolint
    37    bad() //nolint //
    38    bad() //nolint // 
    39    good() //nolint // this is ok
    40  	other() //nolintother
    41  }`,
    42  			expected: []issueWithReplacement{
    43  				{issue: "directive `//nolint` should provide explanation such as `//nolint // this is why` at testing.go:5:1"},
    44  				{issue: "directive `//nolint` should provide explanation such as `//nolint // this is why` at testing.go:7:9"},
    45  				{issue: "directive `//nolint //` should provide explanation such as `//nolint // this is why` at testing.go:8:9"},
    46  				{issue: "directive `//nolint // ` should provide explanation such as `//nolint // this is why` at testing.go:9:9"},
    47  			},
    48  		},
    49  		{
    50  			desc:  "when multiple directives on multiple lines",
    51  			needs: NeedsExplanation,
    52  			contents: `
    53  package bar
    54  
    55  // example
    56  //nolint // this is ok
    57  //nolint:dupl
    58  func foo() {}`,
    59  			expected: []issueWithReplacement{
    60  				{issue: "directive `//nolint:dupl` should provide explanation such as `//nolint:dupl // this is why` at testing.go:6:1"},
    61  			},
    62  		},
    63  		{
    64  			desc:     "when no explanation is needed for a specific linter",
    65  			needs:    NeedsExplanation,
    66  			excludes: []string{"lll"},
    67  			contents: `
    68  package bar
    69  
    70  func foo() {
    71  	thisIsAReallyLongLine() //nolint:lll
    72  }`,
    73  		},
    74  		{
    75  			desc:  "when no specific linter is mentioned",
    76  			needs: NeedsSpecific,
    77  			contents: `
    78  package bar
    79  
    80  func foo() {
    81    good() //nolint:my-linter
    82    bad() //nolint
    83    bad() //nolint // because
    84  }`,
    85  			expected: []issueWithReplacement{
    86  				{issue: "directive `//nolint` should mention specific linter such as `//nolint:my-linter` at testing.go:6:9"},
    87  				{issue: "directive `//nolint // because` should mention specific linter such as `//nolint:my-linter` at testing.go:7:9"},
    88  			},
    89  		},
    90  		{
    91  			desc: "when machine-readable style isn't used",
    92  			contents: `
    93  package bar
    94  
    95  func foo() {
    96    bad() // nolint
    97    bad() //   nolint
    98    good() //nolint
    99  }`,
   100  			expected: []issueWithReplacement{
   101  				{
   102  					issue: "directive `// nolint` should be written without leading space as `//nolint` at testing.go:5:9",
   103  					replacement: &result.Replacement{
   104  						Inline: &result.InlineFix{
   105  							StartCol:  10,
   106  							Length:    1,
   107  							NewString: "",
   108  						},
   109  					},
   110  				},
   111  				{
   112  					issue: "directive `//   nolint` should be written without leading space as `//nolint` at testing.go:6:9",
   113  					replacement: &result.Replacement{
   114  						Inline: &result.InlineFix{
   115  							StartCol:  10,
   116  							Length:    3,
   117  							NewString: "",
   118  						},
   119  					},
   120  				},
   121  			},
   122  		},
   123  		{
   124  			desc: "spaces are allowed in comma-separated list of linters",
   125  			contents: `
   126  package bar
   127  
   128  func foo() {
   129    good() //nolint:linter1,linter-two
   130    bad() //nolint:linter1 linter2
   131    good() //nolint: linter1,linter2
   132    good() //nolint: linter1, linter2
   133  }`,
   134  			expected: []issueWithReplacement{
   135  				{issue: "directive `//nolint:linter1 linter2` should match `//nolint[:<comma-separated-linters>] [// <explanation>]` at testing.go:6:9"}, //nolint:lll // this is a string
   136  			},
   137  		},
   138  		{
   139  			desc: "multi-line comments don't confuse parser",
   140  			contents: `
   141  package bar
   142  
   143  func foo() {
   144    //nolint:test
   145    // something else
   146  }`,
   147  		},
   148  		{
   149  			desc:  "needs unused without specific linter generates replacement",
   150  			needs: NeedsUnused,
   151  			contents: `
   152  package bar
   153  
   154  func foo() {
   155    bad() //nolint
   156  }`,
   157  			expected: []issueWithReplacement{
   158  				{
   159  					issue: "directive `//nolint` is unused at testing.go:5:9",
   160  					replacement: &result.Replacement{
   161  						Inline: &result.InlineFix{
   162  							StartCol:  8,
   163  							Length:    8,
   164  							NewString: "",
   165  						},
   166  					},
   167  				},
   168  			},
   169  		},
   170  		{
   171  			desc:  "needs unused with one specific linter generates replacement",
   172  			needs: NeedsUnused,
   173  			contents: `
   174  package bar
   175  
   176  func foo() {
   177    bad() //nolint:somelinter
   178  }`,
   179  			expected: []issueWithReplacement{
   180  				{
   181  					issue: "directive `//nolint:somelinter` is unused for linter \"somelinter\" at testing.go:5:9",
   182  					replacement: &result.Replacement{
   183  						Inline: &result.InlineFix{
   184  							StartCol:  8,
   185  							Length:    19,
   186  							NewString: "",
   187  						},
   188  					},
   189  				},
   190  			},
   191  		},
   192  		{
   193  			desc:  "needs unused with multiple specific linters does not generate replacements",
   194  			needs: NeedsUnused,
   195  			contents: `
   196  package bar
   197  
   198  func foo() {
   199    bad() //nolint:linter1,linter2
   200  }`,
   201  			expected: []issueWithReplacement{
   202  				{
   203  					issue: "directive `//nolint:linter1,linter2` is unused for linter \"linter1\" at testing.go:5:9",
   204  				},
   205  				{
   206  					issue: "directive `//nolint:linter1,linter2` is unused for linter \"linter2\" at testing.go:5:9",
   207  				},
   208  			},
   209  		},
   210  	}
   211  
   212  	for _, test := range testCases {
   213  		test := test
   214  		t.Run(test.desc, func(t *testing.T) {
   215  			t.Parallel()
   216  
   217  			linter, _ := NewLinter(test.needs, test.excludes)
   218  
   219  			fset := token.NewFileSet()
   220  			expr, err := parser.ParseFile(fset, "testing.go", test.contents, parser.ParseComments)
   221  			require.NoError(t, err)
   222  
   223  			actualIssues, err := linter.Run(fset, expr)
   224  			require.NoError(t, err)
   225  
   226  			actualIssuesWithReplacements := make([]issueWithReplacement, 0, len(actualIssues))
   227  			for _, i := range actualIssues {
   228  				actualIssuesWithReplacements = append(actualIssuesWithReplacements, issueWithReplacement{
   229  					issue:       i.String(),
   230  					replacement: i.Replacement(),
   231  				})
   232  			}
   233  
   234  			assert.ElementsMatch(t, test.expected, actualIssuesWithReplacements,
   235  				"expected %s \nbut got %s", test.expected, actualIssuesWithReplacements)
   236  		})
   237  	}
   238  }