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  }