github.com/yoheimuta/protolint@v0.49.8-0.20240515023657-4ecaebb7575d/linter/disablerule/interpreter_test.go (about) 1 package disablerule_test 2 3 import ( 4 "reflect" 5 "testing" 6 7 "github.com/yoheimuta/protolint/linter/disablerule" 8 9 "github.com/yoheimuta/go-protoparser/v4/parser" 10 ) 11 12 func TestInterpreter_Interpret(t *testing.T) { 13 type inOut struct { 14 name string 15 inputComments []*parser.Comment 16 inputInlineComments []*parser.Comment 17 wantIsDisabled bool 18 } 19 tests := []struct { 20 name string 21 inputRuleID string 22 inOuts []inOut 23 }{ 24 { 25 name: "disable:next comments skip ENUM_FIELD_NAMES_UPPER_SNAKE_CASE", 26 inputRuleID: "ENUM_FIELD_NAMES_UPPER_SNAKE_CASE", 27 inOuts: []inOut{ 28 { 29 name: "rule is enabled when there are no comments", 30 }, 31 { 32 name: "rule is enabled when there are no correct disable:next comments", 33 inputComments: []*parser.Comment{ 34 { 35 Raw: `// disable:next ENUM_FIELD_NAMES_UPPER_SNAKE_CASE`, 36 }, 37 }, 38 }, 39 { 40 name: "rule is enabled when the ruleID does not match it", 41 inputComments: []*parser.Comment{ 42 { 43 Raw: `// protolint:disable:next ENUM_NAMES_UPPER_CAMEL_CASE`, 44 }, 45 }, 46 }, 47 { 48 name: "rule is disabled when there is a disable:next comment with a ruleID", 49 inputComments: []*parser.Comment{ 50 { 51 Raw: `// protolint:disable:next ENUM_FIELD_NAMES_UPPER_SNAKE_CASE`, 52 }, 53 }, 54 wantIsDisabled: true, 55 }, 56 { 57 name: "rule is disabled when there is a disable:next c-style comment with a ruleID", 58 inputComments: []*parser.Comment{ 59 { 60 Raw: `/* 61 protolint:disable:next ENUM_FIELD_NAMES_UPPER_SNAKE_CASE 62 */`, 63 }, 64 }, 65 wantIsDisabled: true, 66 }, 67 { 68 name: "rule is disabled when there are disable:next comments with ruleIDs", 69 inputComments: []*parser.Comment{ 70 { 71 Raw: `// protolint:disable:next ENUM_FIELD_NAMES_UPPER_SNAKE_CASE`, 72 }, 73 { 74 Raw: `// protolint:disable:next ENUM_NAMES_UPPER_CAMEL_CASE`, 75 }, 76 }, 77 wantIsDisabled: true, 78 }, 79 }, 80 }, 81 { 82 name: "disable:next comments skip SERVICE_NAMES_UPPER_CAMEL_CASE", 83 inputRuleID: "SERVICE_NAMES_UPPER_CAMEL_CASE", 84 inOuts: []inOut{ 85 { 86 name: "rule is enabled when the ruleID does not match it", 87 inputComments: []*parser.Comment{ 88 { 89 Raw: `// protolint:disable:next ENUM_NAMES_UPPER_CAMEL_CASE`, 90 }, 91 }, 92 }, 93 { 94 name: "rule is disabled when there is a disable:next comment with a ruleID", 95 inputComments: []*parser.Comment{ 96 { 97 Raw: `// protolint:disable:next SERVICE_NAMES_UPPER_CAMEL_CASE`, 98 }, 99 }, 100 wantIsDisabled: true, 101 }, 102 }, 103 }, 104 { 105 name: "disable:this comment skips SERVICE_NAMES_UPPER_CAMEL_CASE", 106 inputRuleID: "SERVICE_NAMES_UPPER_CAMEL_CASE", 107 inOuts: []inOut{ 108 { 109 name: "rule is enabled when the ruleID does not match it", 110 inputInlineComments: []*parser.Comment{ 111 { 112 Raw: `// protolint:disable:this ENUM_NAMES_UPPER_CAMEL_CASE`, 113 }, 114 }, 115 }, 116 { 117 name: "rule is disabled when there is a disable:this comment with a ruleID", 118 inputInlineComments: []*parser.Comment{ 119 { 120 Raw: `// protolint:disable:this SERVICE_NAMES_UPPER_CAMEL_CASE`, 121 }, 122 }, 123 wantIsDisabled: true, 124 }, 125 }, 126 }, 127 { 128 name: "disable SERVICE_NAMES_UPPER_CAMEL_CASE", 129 inputRuleID: "SERVICE_NAMES_UPPER_CAMEL_CASE", 130 inOuts: []inOut{ 131 { 132 name: "rule is not disabled when there is a disable comment with another ruleID", 133 inputComments: []*parser.Comment{ 134 { 135 Raw: `// protolint:disable ENUM_FIELD_NAMES_UPPER_SNAKE_CASE`, 136 }, 137 }, 138 }, 139 { 140 name: "rule is disabled when there is a disable comment with a ruleID", 141 inputComments: []*parser.Comment{ 142 { 143 Raw: `// protolint:disable SERVICE_NAMES_UPPER_CAMEL_CASE`, 144 }, 145 }, 146 wantIsDisabled: true, 147 }, 148 { 149 name: "rule is always disabled after a disable comment", 150 wantIsDisabled: true, 151 }, 152 { 153 name: "rule is disabled when there is a disable:next comment with a ruleID", 154 inputComments: []*parser.Comment{ 155 { 156 Raw: `// protolint:disable:next SERVICE_NAMES_UPPER_CAMEL_CASE`, 157 }, 158 }, 159 wantIsDisabled: true, 160 }, 161 { 162 name: "rule is always disabled after a disable comment", 163 wantIsDisabled: true, 164 }, 165 }, 166 }, 167 { 168 name: "enable SERVICE_NAMES_UPPER_CAMEL_CASE", 169 inputRuleID: "SERVICE_NAMES_UPPER_CAMEL_CASE", 170 inOuts: []inOut{ 171 { 172 name: "rule is disabled when there is a disable comment with a ruleID", 173 inputComments: []*parser.Comment{ 174 { 175 Raw: `// protolint:disable SERVICE_NAMES_UPPER_CAMEL_CASE`, 176 }, 177 }, 178 wantIsDisabled: true, 179 }, 180 { 181 name: "rule is not enabled when there is an enable comment with another ruleID", 182 inputComments: []*parser.Comment{ 183 { 184 Raw: `// protolint:enable ENUM_FIELD_NAMES_UPPER_SNAKE_CASE`, 185 }, 186 }, 187 wantIsDisabled: true, 188 }, 189 { 190 name: "rule is enabled when there is an enable comment with a same ruleID", 191 inputComments: []*parser.Comment{ 192 { 193 Raw: `// protolint:enable SERVICE_NAMES_UPPER_CAMEL_CASE`, 194 }, 195 }, 196 }, 197 { 198 name: "rule is always enabled after an enable comment", 199 }, 200 { 201 name: "rule is disabled when there is a disable:next comment with a ruleID", 202 inputComments: []*parser.Comment{ 203 { 204 Raw: `// protolint:disable:next SERVICE_NAMES_UPPER_CAMEL_CASE`, 205 }, 206 }, 207 wantIsDisabled: true, 208 }, 209 { 210 name: "rule is always enabled after an enable comment and a disable:next comment", 211 }, 212 }, 213 }, 214 } 215 216 for _, test := range tests { 217 test := test 218 t.Run(test.name, func(t *testing.T) { 219 interpreter := disablerule.NewInterpreter(test.inputRuleID) 220 221 for _, expect := range test.inOuts { 222 got := interpreter.Interpret(expect.inputComments, expect.inputInlineComments...) 223 if got != expect.wantIsDisabled { 224 t.Errorf("[%s] got %v, but want %v", expect.name, got, expect.wantIsDisabled) 225 } 226 } 227 }) 228 } 229 } 230 231 func TestInterpreter_CallEachIfValid(t *testing.T) { 232 type outputType struct { 233 index int 234 line string 235 } 236 tests := []struct { 237 name string 238 inputRuleID string 239 inputLines []string 240 wantOutputLines []outputType 241 }{ 242 { 243 name: "All lines are valid, so the function is called for each line.", 244 inputRuleID: "MAX_LINE_LENGTH", 245 inputLines: []string{ 246 `enum enumAllowingAlias {`, 247 `// disable:next MAX_LINE_LENGTH`, 248 `option allow_alias = true;`, 249 `}`, 250 }, 251 wantOutputLines: []outputType{ 252 { 253 index: 0, 254 line: `enum enumAllowingAlias {`, 255 }, 256 { 257 index: 1, 258 line: `// disable:next MAX_LINE_LENGTH`, 259 }, 260 { 261 index: 2, 262 line: `option allow_alias = true;`, 263 }, 264 { 265 index: 3, 266 line: `}`, 267 }, 268 }, 269 }, 270 { 271 name: "protolint:disable:next works.", 272 inputRuleID: "MAX_LINE_LENGTH", 273 inputLines: []string{ 274 `enum enumAllowingAlias {`, 275 `// protolint:disable:next MAX_LINE_LENGTH`, 276 `option allow_alias = true;`, 277 `}`, 278 }, 279 wantOutputLines: []outputType{ 280 { 281 index: 0, 282 line: `enum enumAllowingAlias {`, 283 }, 284 { 285 index: 1, 286 line: `// protolint:disable:next MAX_LINE_LENGTH`, 287 }, 288 { 289 index: 3, 290 line: `}`, 291 }, 292 }, 293 }, 294 { 295 name: "protolint:disable:this works.", 296 inputRuleID: "MAX_LINE_LENGTH", 297 inputLines: []string{ 298 `enum enumAllowingAlias { // protolint:disable:this MAX_LINE_LENGTH`, 299 `option allow_alias = true;`, 300 `}`, 301 }, 302 wantOutputLines: []outputType{ 303 { 304 index: 1, 305 line: `option allow_alias = true;`, 306 }, 307 { 308 index: 2, 309 line: `}`, 310 }, 311 }, 312 }, 313 { 314 name: "protolint:disable and protolint:enable works", 315 inputRuleID: "MAX_LINE_LENGTH", 316 inputLines: []string{ 317 `enum enumAllowingAlias {`, 318 `// protolint:disable MAX_LINE_LENGTH`, 319 `option allow_alias = true;`, 320 `UNKNOWN = 0;`, 321 `// protolint:enable MAX_LINE_LENGTH`, 322 `STARTED = 1;`, 323 `}`, 324 }, 325 wantOutputLines: []outputType{ 326 { 327 index: 0, 328 line: `enum enumAllowingAlias {`, 329 }, 330 { 331 index: 4, 332 line: `// protolint:enable MAX_LINE_LENGTH`, 333 }, 334 { 335 index: 5, 336 line: `STARTED = 1;`, 337 }, 338 { 339 index: 6, 340 line: `}`, 341 }, 342 }, 343 }, 344 { 345 name: "the mix of protolint:disable commands works", 346 inputRuleID: "MAX_LINE_LENGTH", 347 inputLines: []string{ 348 `// protolint:disable:next MAX_LINE_LENGTH`, 349 `enum enumAllowingAlias {`, 350 `// protolint:disable MAX_LINE_LENGTH`, 351 `option allow_alias = true; // protolint:disable:this MAX_LINE_LENGTH`, 352 `UNKNOWN = 0;`, 353 `// protolint:enable MAX_LINE_LENGTH`, 354 `STARTED = 1;`, 355 `RUNNING = 2; // protolint:disable:this MAX_LINE_LENGTH`, 356 `// protolint:disable:next MAX_LINE_LENGTH`, 357 `STOPPED = 3;`, 358 `}`, 359 }, 360 wantOutputLines: []outputType{ 361 { 362 index: 0, 363 line: `// protolint:disable:next MAX_LINE_LENGTH`, 364 }, 365 { 366 index: 5, 367 line: `// protolint:enable MAX_LINE_LENGTH`, 368 }, 369 { 370 index: 6, 371 line: `STARTED = 1;`, 372 }, 373 { 374 index: 8, 375 line: `// protolint:disable:next MAX_LINE_LENGTH`, 376 }, 377 { 378 index: 10, 379 line: `}`, 380 }, 381 }, 382 }, 383 { 384 name: "protolint:disable doesn't collide with protolint:disable that has a different ruleID", 385 inputRuleID: "MAX_LINE_LENGTH", 386 inputLines: []string{ 387 `// protolint:disable MAX_LINE_LENGTH`, 388 `syntax = "proto3";`, 389 `/** Schnufte test enumeration. */`, 390 `enum TestEnum {`, 391 ` TEST_ENUM_UNSPECIFIED = 0; // Unspecified.`, 392 ` FOO = 1; // protolint:disable:this ENUM_FIELD_NAMES_PREFIX`, 393 `}`, 394 }, 395 }, 396 } 397 398 for _, test := range tests { 399 test := test 400 t.Run(test.name, func(t *testing.T) { 401 interpreter := disablerule.NewInterpreter(test.inputRuleID) 402 403 var got []outputType 404 interpreter.CallEachIfValid(test.inputLines, func(index int, line string) { 405 got = append(got, outputType{ 406 index: index, 407 line: line, 408 }) 409 }) 410 if !reflect.DeepEqual(got, test.wantOutputLines) { 411 t.Errorf("got %v, but want %v", got, test.wantOutputLines) 412 } 413 }) 414 } 415 }