github.com/krishnamiriyala/courtney@v0.3.2/scanner/scanner_test.go (about) 1 package scanner_test 2 3 import ( 4 "strconv" 5 "strings" 6 "testing" 7 8 "path/filepath" 9 10 "github.com/krishnamiriyala/courtney/scanner" 11 "github.com/krishnamiriyala/courtney/shared" 12 "github.com/krishnamiriyala/patsy" 13 "github.com/krishnamiriyala/patsy/builder" 14 "github.com/krishnamiriyala/patsy/vos" 15 ) 16 17 func TestSingle(t *testing.T) { 18 tests := map[string]string{ 19 "single": `package a 20 21 func wrap(error) error 22 23 func a() error { 24 var a bool 25 var err error 26 if err != nil { 27 if a { // this line will not be excluded! 28 return wrap(err) // * 29 } 30 return wrap(err) // * 31 } 32 return nil 33 } 34 `, 35 } 36 test(t, tests) 37 } 38 39 func TestSwitchCase(t *testing.T) { 40 tests := map[string]string{ 41 "simple switch": `package a 42 43 func a() error { 44 var err error 45 switch { 46 case err != nil: 47 return err // * 48 } 49 return nil 50 } 51 `, 52 "switch multi": `package a 53 54 func a() error { 55 var a bool 56 var err error 57 switch { 58 case err == nil, a: 59 return err 60 default: 61 return err // * 62 } 63 return nil 64 } 65 `, 66 "simple switch ignored": `package a 67 68 func a() error { 69 var a bool 70 var err error 71 switch a { 72 case err != nil: 73 return err 74 } 75 return nil 76 } 77 `, 78 "complex switch": `package a 79 80 func foo() error { 81 var err error 82 var b, c bool 83 var d int 84 switch { 85 case err == nil && (b && d > 0) || c: 86 return err 87 case d <= 0 || c: 88 return err 89 case b: 90 return err // * 91 } 92 return err 93 } 94 `, 95 } 96 test(t, tests) 97 } 98 99 func TestNamedParameters(t *testing.T) { 100 tests := map[string]string{ 101 "named parameters simple": `package a 102 103 func a() (err error) { 104 if err != nil { 105 return // * 106 } 107 return 108 } 109 `, 110 "named parameters ignored": `package a 111 112 func a() { 113 var err error 114 if err != nil { 115 return 116 } 117 return 118 } 119 `, 120 "named parameters 2": `package a 121 122 func a() (i int, err error) { 123 i = 1 124 if err != nil { 125 return // * 126 } 127 return 128 } 129 `, 130 "named parameters must be last": `package a 131 132 func a() (err error, i int) { 133 i = 1 134 if err != nil { 135 return 136 } 137 return 138 } 139 `, 140 "named parameters must be not nil": `package a 141 142 func a() (err error) { 143 return 144 } 145 `, 146 "named parameters func lit": `package a 147 148 func a() { 149 func () (err error) { 150 if err != nil { 151 return // * 152 } 153 return 154 }() 155 } 156 `, 157 } 158 test(t, tests) 159 } 160 161 func TestBool(t *testing.T) { 162 tests := map[string]string{ 163 "wrap1": `package a 164 165 func a() error { 166 var wrap func(error) error 167 var err error 168 if err != nil { 169 return wrap(err) // * 170 } 171 return nil 172 } 173 `, 174 "wrap ignored": `package a 175 176 func a() int { 177 var wrap func(error) int 178 var err error 179 if err != nil { 180 return wrap(err) 181 } 182 return 0 183 } 184 `, 185 "wrap2": `package a 186 187 func a() error { 188 var wrap func(error) error 189 var err error 190 if err != nil { 191 w := wrap(err) 192 return w // * 193 } 194 return nil 195 } 196 `, 197 "wrap3": `package a 198 199 func a() error { 200 var wrap func(error) error 201 var err error 202 var w error 203 if err != nil { 204 w = wrap(err) 205 return w // * 206 } 207 return nil 208 } 209 `, 210 "wrap4": `package a 211 212 func a() error { 213 var wrap func(error) error 214 var err error 215 if err != nil { 216 var w = wrap(err) 217 return w // * 218 } 219 return nil 220 } 221 `, 222 "wrap5": `package a 223 224 func a() error { 225 var wrap func(error) error 226 var err error 227 if err != nil { 228 var w error = wrap(err) 229 return w // * 230 } 231 return nil 232 } 233 `, 234 "wrap no tuple": `package a 235 236 func a() (int, error) { 237 var wrap func(error) (int, error) 238 var err error 239 if err != nil { 240 return wrap(err) 241 } 242 return 0, nil 243 } 244 `, 245 "logical and first": `package a 246 247 import "fmt" 248 249 func a() error { 250 _, err := fmt.Println() 251 if err != nil && 1 == 1 { 252 return err // * 253 } 254 return nil 255 } 256 `, 257 "logical and second": `package a 258 259 import "fmt" 260 261 func a() error { 262 _, err := fmt.Println() 263 if 1 == 1 && err != nil { 264 return err // * 265 } 266 return nil 267 } 268 `, 269 "logical and third": `package a 270 271 import "fmt" 272 273 func a() error { 274 _, err := fmt.Println() 275 if 1 == 1 && 2 == 2 && err != nil { 276 return err // * 277 } 278 return nil 279 } 280 `, 281 "logical and brackets": `package a 282 283 import "fmt" 284 285 func a() error { 286 _, err := fmt.Println() 287 if 1 == 1 && (2 == 2 && err != nil) { 288 return err // * 289 } 290 return nil 291 } 292 `, 293 "logical or first": `package a 294 295 import "fmt" 296 297 func a() error { 298 _, err := fmt.Println() 299 if err == nil || 1 == 1 { 300 return err 301 } else { 302 return err // * 303 } 304 return nil 305 } 306 `, 307 "logical or second": `package a 308 309 import "fmt" 310 311 func a() error { 312 _, err := fmt.Println() 313 if 1 == 1 || err == nil { 314 return err 315 } else { 316 return err // * 317 } 318 return nil 319 } 320 `, 321 "logical or third": `package a 322 323 import "fmt" 324 325 func a() error { 326 _, err := fmt.Println() 327 if 1 == 1 || 2 == 2 || err == nil { 328 return err 329 } else { 330 return err // * 331 } 332 return nil 333 } 334 `, 335 "logical or brackets": `package a 336 337 import "fmt" 338 339 func a() error { 340 _, err := fmt.Println() 341 if 1 == 1 || (2 == 2 || err == nil) { 342 return err 343 } else { 344 return err // * 345 } 346 return nil 347 } 348 `, 349 "complex": `package a 350 351 func foo() error { 352 var err error 353 var b, c bool 354 var d int 355 if err == nil && (b && d > 0) || c { 356 return err 357 } else if d <= 0 || c { 358 return err 359 } else if b { 360 return err // * 361 } 362 return err 363 } 364 `, 365 } 366 test(t, tests) 367 } 368 369 func TestGeneral(t *testing.T) { 370 tests := map[string]string{ 371 "simple": `package a 372 373 import "fmt" 374 375 func a() error { 376 _, err := fmt.Println() 377 if err != nil { 378 return err // * 379 } 380 return nil 381 } 382 `, 383 "wrong way round": `package a 384 385 import "fmt" 386 387 func a() error { 388 _, err := fmt.Println() 389 if nil != err { 390 return err // * 391 } 392 return nil 393 } 394 `, 395 "not else block": `package a 396 397 import "fmt" 398 399 func a() error { 400 _, err := fmt.Println() 401 if err != nil { 402 return err // * 403 } else { 404 return err 405 } 406 return nil 407 } 408 `, 409 "any name": `package a 410 411 import "fmt" 412 413 func a() error { 414 _, foo := fmt.Println() 415 if foo != nil { 416 return foo // * 417 } 418 return nil 419 } 420 `, 421 "don't mark if ==": `package a 422 423 import "fmt" 424 425 func a() error { 426 _, err := fmt.Println() 427 if err == nil { 428 return err 429 } 430 return nil 431 } 432 `, 433 "use else block if err == nil": `package a 434 435 import "fmt" 436 437 func a() error { 438 _, err := fmt.Println() 439 if err == nil { 440 return err 441 } else { 442 return err // * 443 } 444 return nil 445 } 446 `, 447 "support if with init form": `package a 448 449 import "fmt" 450 451 func a() error { 452 if _, err := fmt.Println(); err != nil { 453 return err // * 454 } 455 return nil 456 } 457 `, 458 "only in if block": `package foo 459 460 import "fmt" 461 462 func Baz() error { 463 return fmt.Errorf("foo") 464 } 465 `, 466 } 467 test(t, tests) 468 } 469 470 func TestZeroValues(t *testing.T) { 471 tests := map[string]string{ 472 "only return if all other return vars are zero": `package a 473 474 import "fmt" 475 476 type iface interface{} 477 478 type strct struct { 479 a int 480 b string 481 } 482 483 func Foo() (iface, bool, int, string, float32, strct, strct, error) { 484 if _, err := fmt.Println(); err != nil { 485 return 1, false, 0, "", 0.0, strct{0, ""}, strct{a: 0, b: ""}, err 486 } 487 if _, err := fmt.Println(); err != nil { 488 return nil, true, 0, "", 0.0, strct{0, ""}, strct{a: 0, b: ""}, err 489 } 490 if _, err := fmt.Println(); err != nil { 491 return nil, false, 1, "", 0.0, strct{0, ""}, strct{a: 0, b: ""}, err 492 } 493 if _, err := fmt.Println(); err != nil { 494 return nil, false, 0, "a", 0.0, strct{0, ""}, strct{a: 0, b: ""}, err 495 } 496 if _, err := fmt.Println(); err != nil { 497 return nil, false, 0, "", 1.0, strct{0, ""}, strct{a: 0, b: ""}, err 498 } 499 if _, err := fmt.Println(); err != nil { 500 return nil, false, 0, "", 0.0, strct{1, ""}, strct{a: 0, b: ""}, err 501 } 502 if _, err := fmt.Println(); err != nil { 503 return nil, false, 0, "", 0.0, strct{0, "a"}, strct{a: 0, b: ""}, err 504 } 505 if _, err := fmt.Println(); err != nil { 506 return nil, false, 0, "", 0.0, strct{0, ""}, strct{a: 1, b: ""}, err 507 } 508 if _, err := fmt.Println(); err != nil { 509 return nil, false, 0, "", 0.0, strct{0, ""}, strct{a: 0, b: "a"}, err 510 } 511 if _, err := fmt.Println(); err != nil { 512 return nil, false, 0, "", 0.0, strct{0, ""}, strct{a: 0, b: ""}, err // * 513 } 514 return nil, false, 0, "", 0.0, strct{0, ""}, strct{a: 0, b: ""}, nil 515 } 516 `, 517 } 518 test(t, tests) 519 } 520 521 func TestSelectorExpressions(t *testing.T) { 522 tests := map[string]string{ 523 "selector expression": `package foo 524 525 func Baz() error { 526 type T struct { 527 Err error 528 } 529 var b T 530 if b.Err != nil { 531 return b.Err // * 532 } 533 return nil 534 } 535 `, 536 } 537 test(t, tests) 538 } 539 540 func TestFunctionExpressions(t *testing.T) { 541 tests := map[string]string{ 542 "function expression": `package foo 543 544 func Baz() error { 545 var f func(int) error 546 if f(5) != nil { 547 return f(5) // * 548 } 549 return nil 550 } 551 `, 552 "function expression params": `package foo 553 554 func Baz() error { 555 var f func(int) error 556 if f(4) != nil { 557 return f(5) 558 } 559 return nil 560 } 561 `, 562 "function expression params 2": `package foo 563 564 func Baz() error { 565 var f func(...int) error 566 if f(4) != nil { 567 return f(4, 4) 568 } 569 return nil 570 } 571 `, 572 "function expression elipsis": `package foo 573 574 func Baz() error { 575 var f func(...interface{}) error 576 var a []interface{} 577 if f(a) != nil { 578 return f(a...) 579 } 580 return nil 581 } 582 `, 583 "function expression elipsis 2": `package foo 584 585 func Baz() error { 586 var f func(...interface{}) error 587 var a []interface{} 588 if f(a) != nil { 589 return f(a) // * 590 } 591 return nil 592 } 593 `, 594 } 595 test(t, tests) 596 } 597 598 func TestPanic(t *testing.T) { 599 tests := map[string]string{ 600 "panic": `package foo 601 602 func Baz() error { 603 panic("") // * 604 } 605 `, 606 } 607 test(t, tests) 608 } 609 610 func TestComments(t *testing.T) { 611 tests := map[string]string{ 612 "scope": `package foo 613 614 func Baz() int { 615 i := 1 616 if i > 1 { 617 return i 618 } 619 620 //notest 621 // * 622 if i > 2 { // * 623 return i // * 624 } // * 625 return 0 // * 626 } 627 `, 628 "scope if": `package foo 629 630 func Baz(i int) int { 631 if i > 2 { 632 //notest 633 return i // * 634 } 635 return 0 636 } 637 `, 638 "scope file": `package foo 639 640 //notest 641 // * 642 func Baz(i int) int { // * 643 if i > 2 { // * 644 return i // * 645 } // * 646 return 0 // * 647 } // * 648 // * 649 func Foo(i int) int { // * 650 return 0 // * 651 } 652 `, 653 "complex comments": `package foo 654 655 type Logger struct { 656 Enabled bool 657 } 658 func (l Logger) Print(i ...interface{}) {} 659 660 func Foo() { 661 var logger Logger 662 var tokens []interface{} 663 if logger.Enabled { 664 // TODO: notest 665 for i, token := range tokens { // * 666 logger.Print("[", i, "] ", token) // * 667 } // * 668 } 669 } 670 `, 671 "case block": `package foo 672 673 func Foo() bool { 674 switch { 675 case true: 676 // TODO: notest 677 if true { // * 678 return true // * 679 } // * 680 return false // * 681 } 682 return false 683 } 684 `, 685 } 686 test(t, tests) 687 } 688 689 func test(t *testing.T, tests map[string]string) { 690 for name, source := range tests { 691 env := vos.Mock() 692 b, err := builder.New(env, "ns", true) 693 if err != nil { 694 t.Fatalf("Error creating builder in %s: %+v", name, err) 695 } 696 defer b.Cleanup() 697 698 ppath, pdir, err := b.Package("a", map[string]string{ 699 "a.go": source, 700 }) 701 if err != nil { 702 t.Fatalf("Error creating package in %s: %+v", name, err) 703 } 704 705 paths := patsy.NewCache(env) 706 setup := &shared.Setup{ 707 Env: env, 708 Paths: paths, 709 } 710 if err := setup.Parse([]string{ppath}); err != nil { 711 t.Fatalf("Error parsing args in %s: %+v", name, err) 712 } 713 714 cm := scanner.New(setup) 715 716 if err := cm.LoadProgram(); err != nil { 717 t.Fatalf("Error loading program in %s: %+v", name, err) 718 } 719 720 if err := cm.ScanPackages(); err != nil { 721 t.Fatalf("Error scanning packages in %s: %+v", name, err) 722 } 723 724 result := cm.Excludes[filepath.Join(pdir, "a.go")] 725 726 for i, line := range strings.Split(source, "\n") { 727 expected := strings.HasSuffix(line, "// *") || 728 strings.HasSuffix(line, "// TODO: notest") 729 if result[i+1] != expected { 730 t.Fatalf("Unexpected state in %s, line %d: %s\n", name, i, strconv.Quote(strings.Trim(line, "\t"))) 731 } 732 } 733 } 734 }