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