github.com/munnerz/test-infra@v0.0.0-20190108210205-ce3d181dc989/prow/plugins/golint/golint_test.go (about)

     1  /*
     2  Copyright 2017 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package golint
    18  
    19  import (
    20  	"fmt"
    21  	"reflect"
    22  	"strings"
    23  	"testing"
    24  
    25  	"github.com/sirupsen/logrus"
    26  
    27  	"k8s.io/test-infra/prow/git/localgit"
    28  	"k8s.io/test-infra/prow/github"
    29  	"k8s.io/test-infra/prow/plugins"
    30  )
    31  
    32  var initialFiles = map[string][]byte{
    33  	"bar.go": []byte(`// Package bar does an interesting thing.
    34  package bar
    35  
    36  // Foo does a thing.
    37  func Foo(wow int) int {
    38  	return 42 + wow
    39  }
    40  `),
    41  }
    42  
    43  var pullFiles = map[string][]byte{
    44  	"qux.go": []byte(`package bar
    45  
    46  func Qux() error {
    47  	return nil
    48  }
    49  `),
    50  	"zz_generated.wowza.go": []byte(`package bar
    51  
    52  func Qux() error {
    53  	return nil
    54  }
    55  `),
    56  }
    57  
    58  type ghc struct {
    59  	genfile     []byte
    60  	pr          github.PullRequest
    61  	changes     []github.PullRequestChange
    62  	oldComments []github.ReviewComment
    63  	comment     github.DraftReview
    64  }
    65  
    66  func (g *ghc) GetPullRequestChanges(org, repo string, number int) ([]github.PullRequestChange, error) {
    67  	return g.changes, nil
    68  }
    69  
    70  func (g *ghc) CreateReview(org, repo string, number int, r github.DraftReview) error {
    71  	g.comment = r
    72  	return nil
    73  }
    74  
    75  func (g *ghc) ListPullRequestComments(org, repo string, number int) ([]github.ReviewComment, error) {
    76  	return g.oldComments, nil
    77  }
    78  
    79  func (g *ghc) GetFile(org, repo, filepath, commit string) ([]byte, error) {
    80  	return g.genfile, nil
    81  }
    82  
    83  func (g *ghc) GetPullRequest(org, repo string, number int) (*github.PullRequest, error) {
    84  	return &g.pr, nil
    85  }
    86  
    87  var e = &github.GenericCommentEvent{
    88  	Action:     github.GenericCommentActionCreated,
    89  	IssueState: "open",
    90  	Body:       "/lint",
    91  	User:       github.User{Login: "cjwagner"},
    92  	Number:     42,
    93  	IsPR:       true,
    94  	Repo: github.Repo{
    95  		Owner:    github.User{Login: "foo"},
    96  		Name:     "bar",
    97  		FullName: "foo/bar",
    98  	},
    99  }
   100  
   101  func TestMinConfidence(t *testing.T) {
   102  	zero := float64(0)
   103  	half := 0.5
   104  	cases := []struct {
   105  		name     string
   106  		golint   *plugins.Golint
   107  		expected float64
   108  	}{
   109  		{
   110  			name:     "nothing set",
   111  			expected: defaultConfidence,
   112  		},
   113  		{
   114  			name:     "no confidence set",
   115  			golint:   &plugins.Golint{},
   116  			expected: defaultConfidence,
   117  		},
   118  		{
   119  			name:     "confidence set to zero",
   120  			golint:   &plugins.Golint{MinimumConfidence: &zero},
   121  			expected: zero,
   122  		},
   123  		{
   124  			name:     "confidence set positive",
   125  			golint:   &plugins.Golint{MinimumConfidence: &half},
   126  			expected: half,
   127  		},
   128  	}
   129  	for _, tc := range cases {
   130  		t.Run(tc.name, func(t *testing.T) {
   131  			actual := minConfidence(tc.golint)
   132  			if actual != tc.expected {
   133  				t.Errorf("minimum confidence %f != expected %f", actual, tc.expected)
   134  			}
   135  		})
   136  	}
   137  }
   138  
   139  func TestLint(t *testing.T) {
   140  	lg, c, err := localgit.New()
   141  	if err != nil {
   142  		t.Fatalf("Making localgit: %v", err)
   143  	}
   144  	defer func() {
   145  		if err := lg.Clean(); err != nil {
   146  			t.Errorf("Cleaning up localgit: %v", err)
   147  		}
   148  		if err := c.Clean(); err != nil {
   149  			t.Errorf("Cleaning up client: %v", err)
   150  		}
   151  	}()
   152  	if err := lg.MakeFakeRepo("foo", "bar"); err != nil {
   153  		t.Fatalf("Making fake repo: %v", err)
   154  	}
   155  	if err := lg.AddCommit("foo", "bar", initialFiles); err != nil {
   156  		t.Fatalf("Adding initial commit: %v", err)
   157  	}
   158  	if err := lg.CheckoutNewBranch("foo", "bar", "pull/42/head"); err != nil {
   159  		t.Fatalf("Checking out pull branch: %v", err)
   160  	}
   161  	if err := lg.AddCommit("foo", "bar", pullFiles); err != nil {
   162  		t.Fatalf("Adding PR commit: %v", err)
   163  	}
   164  
   165  	gh := &ghc{
   166  		genfile: []byte("file-prefix zz_generated"),
   167  		changes: []github.PullRequestChange{
   168  			{
   169  				Filename: "qux.go",
   170  				Patch:    "@@ -0,0 +1,5 @@\n+package bar\n+\n+func Qux() error {\n+   return nil\n+}",
   171  			},
   172  			{
   173  				Filename: "zz_generated.wowza.go",
   174  				Patch:    "@@ -0,0 +1,5 @@\n+package bar\n+\n+func Qux2() error {\n+   return nil\n+}",
   175  			},
   176  		},
   177  	}
   178  	if err := handle(0, gh, c, logrus.NewEntry(logrus.New()), e); err != nil {
   179  		t.Fatalf("Got error from handle: %v", err)
   180  	}
   181  	if len(gh.comment.Comments) != 2 {
   182  		t.Fatalf("Expected two comments, got %d: %v.", len(gh.comment.Comments), gh.comment.Comments)
   183  	}
   184  	for _, c := range gh.comment.Comments {
   185  		pos := c.Position
   186  		gh.oldComments = append(gh.oldComments, github.ReviewComment{
   187  			Path:     c.Path,
   188  			Position: &pos,
   189  			Body:     c.Body,
   190  		})
   191  	}
   192  	if err := handle(0, gh, c, logrus.NewEntry(logrus.New()), e); err != nil {
   193  		t.Fatalf("Got error from handle on second try: %v", err)
   194  	}
   195  	if len(gh.comment.Comments) != 0 {
   196  		t.Fatalf("Expected no comments, got %d: %v", len(gh.comment.Comments), gh.comment.Comments)
   197  	}
   198  
   199  	// Test that we limit comments.
   200  	badFileLines := []string{"package baz", ""}
   201  	for i := 0; i < maxComments+5; i++ {
   202  		badFileLines = append(badFileLines, fmt.Sprintf("type PublicType%d int", i))
   203  	}
   204  	gh.changes = append(gh.changes, github.PullRequestChange{
   205  		Filename: "baz.go",
   206  		Patch:    fmt.Sprintf("@@ -0,0 +1,%d @@\n+%s", len(badFileLines), strings.Join(badFileLines, "\n+")),
   207  	})
   208  	if err := lg.AddCommit("foo", "bar", map[string][]byte{"baz.go": []byte(strings.Join(badFileLines, "\n"))}); err != nil {
   209  		t.Fatalf("Adding PR commit: %v", err)
   210  	}
   211  	gh.oldComments = nil
   212  	if err := handle(0, gh, c, logrus.NewEntry(logrus.New()), e); err != nil {
   213  		t.Fatalf("Got error from handle on third try: %v", err)
   214  	}
   215  	if len(gh.comment.Comments) != maxComments {
   216  		t.Fatalf("Expected %d comments, got %d: %v", maxComments, len(gh.comment.Comments), gh.comment.Comments)
   217  	}
   218  }
   219  
   220  func TestLintCodeSuggestion(t *testing.T) {
   221  
   222  	var testcases = []struct {
   223  		name       string
   224  		codeChange string
   225  		pullFiles  map[string][]byte
   226  		comment    string
   227  	}{
   228  		{
   229  			name:       "Check names with underscore",
   230  			codeChange: "@@ -0,0 +1,7 @@\n+// Package bar comment\n+package bar\n+\n+// Qux_1 comment\n+func Qux_1_Func() error {\n+   return nil\n+}",
   231  			pullFiles: map[string][]byte{
   232  				"qux.go": []byte("// Package bar comment\npackage bar\n\n// Qux_1 comment\nfunc Qux_1() error {\n	return nil\n}\n"),
   233  			},
   234  			comment: "```suggestion\nfunc Qux1() error {\n```\nGolint naming: don't use underscores in Go names; func Qux_1 should be Qux1. [More info](http://golang.org/doc/effective_go.html#mixed-caps). <!-- golint -->",
   235  		},
   236  		{
   237  			name:       "Check names with all caps",
   238  			codeChange: "@@ -0,0 +1,7 @@\n+// Package bar comment\n+package bar\n+\n+// QUX_FUNC comment\n+func QUX_FUNC() error {\n+   return nil\n+}",
   239  			pullFiles: map[string][]byte{
   240  				"qux.go": []byte("// Package bar comment\npackage bar\n\n// QUX_FUNC comment\nfunc QUX_FUNC() error {\n       return nil\n}\n"),
   241  			},
   242  			comment: "```suggestion\nfunc QuxFunc() error {\n```\nGolint naming: don't use ALL_CAPS in Go names; use CamelCase. [More info](https://golang.org/wiki/CodeReviewComments#mixed-caps). <!-- golint -->",
   243  		},
   244  		{
   245  			name:       "Correct function name",
   246  			codeChange: "@@ -0,0 +1,7 @@\n+// Package bar comment\n+package bar\n+\n+// QuxFunc comment\n+func QuxFunc() error {\n+   return nil\n+}",
   247  			pullFiles: map[string][]byte{
   248  				"qux.go": []byte("// Package bar comment\npackage bar\n\n// QuxFunc comment\nfunc QuxFunc() error {\n       return nil\n}\n"),
   249  			},
   250  			comment: "",
   251  		},
   252  		{
   253  			name:       "Check stutter in function names",
   254  			codeChange: "@@ -0,0 +1,9 @@\n+/*\n+Package bar comment\n+*/\n+package bar\n+\n+// BarFunc comment\n+func BarFunc() error {\n+   return nil\n+}",
   255  			pullFiles: map[string][]byte{
   256  				"qux.go": []byte("/*\nPackage bar comment\n*/\npackage bar\n\n// BarFunc comment\nfunc BarFunc() error {\n   return nil\n}"),
   257  			},
   258  			comment: "```suggestion\nfunc Func() error {\n```\nGolint naming: func name will be used as bar.BarFunc by other packages, and that stutters; consider calling this Func. [More info](https://golang.org/wiki/CodeReviewComments#package-names). <!-- golint -->",
   259  		},
   260  		{
   261  			name:       "Check stutter in type names",
   262  			codeChange: "@@ -0,0 +1,8 @@\n+/*\n+Package bar comment\n+*/\n+package bar\n+\n+// BarMaker comment\n+type BarMaker struct{}\n+",
   263  			pullFiles: map[string][]byte{
   264  				"qux.go": []byte("/*\nPackage bar comment\n*/\npackage bar\n\n// BarMaker comment\ntype BarMaker struct{}\n"),
   265  			},
   266  			comment: "```suggestion\ntype Maker struct{}\n```\nGolint naming: type name will be used as bar.BarMaker by other packages, and that stutters; consider calling this Maker. [More info](https://golang.org/wiki/CodeReviewComments#package-names). <!-- golint -->",
   267  		},
   268  		{
   269  			name:       "Check stutter: no stutter",
   270  			codeChange: "@@ -0,0 +1,8 @@\n+/*\n+Package bar comment\n+*/\n+package bar\n+\n+// barMaker comment\n+type barMaker struct{}\n+",
   271  			pullFiles: map[string][]byte{
   272  				"qux.go": []byte("/*\nPackage bar comment\n*/\npackage bar\n\n// barMaker comment\ntype barMaker struct{}\n"),
   273  			},
   274  			comment: "",
   275  		},
   276  		{
   277  			name:       "Check errorf with errors",
   278  			codeChange: "@@ -0,0 +1,14 @@\n+/*\n+Package bar comment\n+*/\n+package bar\n+\n+import (\n+        \"errors\"\n+        \"fmt\"\n+)\n+\n+func f(x int) error {\n+        return errors.New(fmt.Sprintf(\"something %d\", x))\n+}\n+",
   279  			pullFiles: map[string][]byte{
   280  				"qux.go": []byte("/*\nPackage bar comment\n*/\npackage bar\n\nimport (\n        \"errors\"\n        \"fmt\"\n)\n\nfunc f(x int) error {\n        return errors.New(fmt.Sprintf(\"something %d\", x))\n}\n"),
   281  			},
   282  			comment: "```suggestion\n        return fmt.Errorf(\"something %d\", x)\n```\nGolint errors: should replace errors.New(fmt.Sprintf(...)) with fmt.Errorf(...). <!-- golint -->",
   283  		},
   284  		{
   285  			name:       "Check errorf: no error",
   286  			codeChange: "@@ -0,0 +1,14 @@\n+/*\n+Package bar comment\n+*/\n+package bar\n+\n+import (\n+        \"errors\"\n+        \"fmt\"\n+)\n+\n+func f(x int) error {\n+        return fmt.Errorf(\"something %!d(MISSING)\", x)\n+}\n+",
   287  			pullFiles: map[string][]byte{
   288  				"qux.go": []byte("/*\nPackage bar comment\n*/\npackage bar\n\nimport (\n        \"errors\"\n        \"fmt\"\n)\n\nfunc f(x int) error {        return fmt.Errorf(\"something %!d(MISSING)\", x)\n}\n"),
   289  			},
   290  			comment: "",
   291  		},
   292  		{
   293  			name:       "Check loop range: omit values",
   294  			codeChange: "@@ -0,0 +1,10 @@\n+/*\n+Package bar comment\n+*/\n+package bar\n+\n+func f() {\n+for _ = range m {\n+}\n+}\n+",
   295  			pullFiles: map[string][]byte{
   296  				"qux.go": []byte("/*\nPackage bar comment\n*/\npackage bar\n\nfunc f() {\nfor _ = range m {\n}\n}\n"),
   297  			},
   298  			comment: "```suggestion\nfor range m {\n```\nGolint range-loop: should omit values from range; this loop is equivalent to `for range ...`. <!-- golint -->",
   299  		},
   300  		{
   301  			name:       "Check loop range: omit two values",
   302  			codeChange: "@@ -0,0 +1,10 @@\n+/*\n+Package bar comment\n+*/\n+package bar\n+\n+func f() {\n+for _, _ = range m {\n+}\n+}\n+",
   303  			pullFiles: map[string][]byte{
   304  				"qux.go": []byte("/*\nPackage bar comment\n*/\npackage bar\n\nfunc f() {\nfor _, _ = range m {\n}\n}\n"),
   305  			},
   306  			comment: "```suggestion\nfor range m {\n```\nGolint range-loop: should omit values from range; this loop is equivalent to `for range ...`. <!-- golint -->",
   307  		},
   308  		{
   309  			name:       "Check loop range: omit 2nd value with =",
   310  			codeChange: "@@ -0,0 +1,11 @@\n+/*\n+Package bar comment\n+*/\n+package bar\n+\n+func f() {\n+var y = 0\n+for y, _ = range m {\n+}\n+}\n+",
   311  			pullFiles: map[string][]byte{
   312  				"qux.go": []byte("/*\nPackage bar comment\n*/\npackage bar\n\nfunc f() {\nvar y = 0\nfor y, _ = range m {\n}\n}\n"),
   313  			},
   314  			comment: "```suggestion\nfor y = range m {\n```\nGolint range-loop: should omit 2nd value from range; this loop is equivalent to `for y = range ...`. <!-- golint -->",
   315  		},
   316  		{
   317  			name:       "Check loop range: omit 2nd value with :=",
   318  			codeChange: "@@ -0,0 +1,10 @@\n+/*\n+Package bar comment\n+*/\n+package bar\n+\n+func f() {\n+for y, _ := range m {\n+}\n+}\n+",
   319  			pullFiles: map[string][]byte{
   320  				"qux.go": []byte("/*\nPackage bar comment\n*/\npackage bar\n\nfunc f() {\nfor y, _ := range m {\n}\n}\n"),
   321  			},
   322  			comment: "```suggestion\nfor y := range m {\n```\nGolint range-loop: should omit 2nd value from range; this loop is equivalent to `for y := range ...`. <!-- golint -->",
   323  		},
   324  		{
   325  			name:       "Check loop range: no error",
   326  			codeChange: "@@ -0,0 +1,10 @@\n+/*\n+Package bar comment\n+*/\n+package bar\n+\n+func f() {\n+for y := range m {\n+}\n+}\n+",
   327  			pullFiles: map[string][]byte{
   328  				"qux.go": []byte("/*\nPackage bar comment\n*/\npackage bar\n\nfunc f() {\nfor y := range m {\n}\n}\n"),
   329  			},
   330  			comment: "",
   331  		},
   332  	}
   333  
   334  	lg, c, err := localgit.New()
   335  	if err != nil {
   336  		t.Fatalf("Making localgit: %v", err)
   337  	}
   338  	defer func() {
   339  		if err := lg.Clean(); err != nil {
   340  			t.Errorf("Cleaning up localgit: %v", err)
   341  		}
   342  		if err := c.Clean(); err != nil {
   343  			t.Errorf("Cleaning up client: %v", err)
   344  		}
   345  	}()
   346  	if err := lg.MakeFakeRepo("foo", "bar"); err != nil {
   347  		t.Fatalf("Making fake repo: %v", err)
   348  	}
   349  	if err := lg.AddCommit("foo", "bar", initialFiles); err != nil {
   350  		t.Fatalf("Adding initial commit: %v", err)
   351  	}
   352  	if err := lg.CheckoutNewBranch("foo", "bar", "pull/42/head"); err != nil {
   353  		t.Fatalf("Checking out pull branch: %v", err)
   354  	}
   355  
   356  	for _, test := range testcases {
   357  		t.Logf("Running test case %q...", test.name)
   358  		if err := lg.AddCommit("foo", "bar", test.pullFiles); err != nil {
   359  			t.Fatalf("Adding PR commit: %v", err)
   360  		}
   361  		gh := &ghc{
   362  			changes: []github.PullRequestChange{
   363  				{
   364  					Filename: "qux.go",
   365  					Patch:    test.codeChange,
   366  				},
   367  			},
   368  		}
   369  		if err := handle(0, gh, c, logrus.NewEntry(logrus.New()), e); err != nil {
   370  			t.Fatalf("Got error from handle: %v", err)
   371  		}
   372  
   373  		if test.comment == "" {
   374  			if len(gh.comment.Comments) > 0 {
   375  				t.Fatalf("Expected no comment, got %d: %v.", len(gh.comment.Comments), gh.comment.Comments)
   376  			}
   377  		} else {
   378  			if len(gh.comment.Comments) != 1 {
   379  				t.Fatalf("Expected one comments, got %d: %v.", len(gh.comment.Comments), gh.comment.Comments)
   380  			}
   381  			if test.comment != gh.comment.Comments[0].Body {
   382  				t.Fatalf("Expected\n" + test.comment + "\n but got\n" + gh.comment.Comments[0].Body)
   383  			}
   384  		}
   385  	}
   386  }
   387  
   388  func TestAddedLines(t *testing.T) {
   389  	var testcases = []struct {
   390  		patch string
   391  		lines map[int]int
   392  		err   bool
   393  	}{
   394  		{
   395  			patch: "@@ -0,0 +1,5 @@\n+package bar\n+\n+func Qux() error {\n+   return nil\n+}",
   396  			lines: map[int]int{1: 1, 2: 2, 3: 3, 4: 4, 5: 5},
   397  		},
   398  		{
   399  			patch: "@@ -29,12 +29,14 @@ import (\n \t\"github.com/sirupsen/logrus\"\n \t\"sigs.k8s.io/yaml\"\n \n+\t\"k8s.io/test-infra/prow/config\"\n \t\"k8s.io/test-infra/prow/jenkins\"\n \t\"k8s.io/test-infra/prow/kube\"\n \t\"k8s.io/test-infra/prow/plank\"\n )\n \n var (\n+\tconfigPath   = flag.String(\"config-path\", \"/etc/config/config\", \"Path to config.yaml.\")\n \tbuildCluster = flag.String(\"build-cluster\", \"\", \"Path to file containing a YAML-marshalled kube.Cluster object. If empty, uses the local cluster.\")\n \n \tjenkinsURL       = flag.String(\"jenkins-url\", \"\", \"Jenkins URL\")\n@@ -47,18 +49,22 @@ var objReg = regexp.MustCompile(`^[\\w-]+$`)\n \n func main() {\n \tflag.Parse()\n-\n \tlogrus.SetFormatter(&logrus.JSONFormatter{})\n \n-\tkc, err := kube.NewClientInCluster(kube.ProwNamespace)\n+\tconfigAgent := &config.Agent{}\n+\tif err := configAgent.Start(*configPath); err != nil {\n+\t\tlogrus.WithError(err).Fatal(\"Error starting config agent.\")\n+\t}\n+\n+\tkc, err := kube.NewClientInCluster(configAgent.Config().ProwJobNamespace)\n \tif err != nil {\n \t\tlogrus.WithError(err).Fatal(\"Error getting client.\")\n \t}\n \tvar pkc *kube.Client\n \tif *buildCluster == \"\" {\n-\t\tpkc = kc.Namespace(kube.TestPodNamespace)\n+\t\tpkc = kc.Namespace(configAgent.Config().PodNamespace)\n \t} else {\n-\t\tpkc, err = kube.NewClientFromFile(*buildCluster, kube.TestPodNamespace)\n+\t\tpkc, err = kube.NewClientFromFile(*buildCluster, configAgent.Config().PodNamespace)\n \t\tif err != nil {\n \t\t\tlogrus.WithError(err).Fatal(\"Error getting kube client to build cluster.\")\n \t\t}",
   400  			lines: map[int]int{4: 32, 11: 39, 23: 54, 24: 55, 25: 56, 26: 57, 27: 58, 28: 59, 35: 65, 38: 67},
   401  		},
   402  		{
   403  			patch: "@@ -1 +0,0 @@\n-such",
   404  		},
   405  		{
   406  			patch: "@@ -1,3 +0,0 @@\n-such\n-a\n-doge",
   407  		},
   408  		{
   409  			patch: "@@ -0,0 +1 @@\n+wow",
   410  			lines: map[int]int{1: 1},
   411  		},
   412  		{
   413  			patch: "@@ -0,0 +1 @@\n+wow\n\\ No newline at end of file",
   414  			lines: map[int]int{1: 1},
   415  		},
   416  		{
   417  			patch: "@@ -1 +1 @@\n-doge\n+wow",
   418  			lines: map[int]int{2: 1},
   419  		},
   420  		{
   421  			patch: "something strange",
   422  			err:   true,
   423  		},
   424  		{
   425  			patch: "@@ -a,3 +0,0 @@\n-wow",
   426  			err:   true,
   427  		},
   428  		{
   429  			patch: "@@ -1 +1 @@",
   430  			err:   true,
   431  		},
   432  		{
   433  			patch: "",
   434  		},
   435  	}
   436  	for _, tc := range testcases {
   437  		als, err := AddedLines(tc.patch)
   438  		if err == nil == tc.err {
   439  			t.Errorf("For patch %s\nExpected error %v, got error %v", tc.patch, tc.err, err)
   440  			continue
   441  		}
   442  		if len(als) != len(tc.lines) {
   443  			t.Errorf("For patch %s\nAdded lines has wrong length. Got %v, expected %v", tc.patch, als, tc.lines)
   444  		}
   445  		for pl, l := range tc.lines {
   446  			if als[l] != pl {
   447  				t.Errorf("For patch %s\nExpected added line %d to be %d, but got %d", tc.patch, l, pl, als[l])
   448  			}
   449  		}
   450  	}
   451  }
   452  
   453  func TestModifiedGoFiles(t *testing.T) {
   454  	lg, c, err := localgit.New()
   455  	if err != nil {
   456  		t.Fatalf("Making localgit: %v", err)
   457  	}
   458  	defer func() {
   459  		if err := lg.Clean(); err != nil {
   460  			t.Errorf("Cleaning up localgit: %v", err)
   461  		}
   462  		if err := c.Clean(); err != nil {
   463  			t.Errorf("Cleaning up client: %v", err)
   464  		}
   465  	}()
   466  	if err := lg.MakeFakeRepo("foo", "bar"); err != nil {
   467  		t.Fatalf("Making fake repo: %v", err)
   468  	}
   469  	if err := lg.AddCommit("foo", "bar", initialFiles); err != nil {
   470  		t.Fatalf("Adding initial commit: %v", err)
   471  	}
   472  	if err := lg.CheckoutNewBranch("foo", "bar", "pull/42/head"); err != nil {
   473  		t.Fatalf("Checking out pull branch: %v", err)
   474  	}
   475  	if err := lg.AddCommit("foo", "bar", pullFiles); err != nil {
   476  		t.Fatalf("Adding PR commit: %v", err)
   477  	}
   478  
   479  	var testcases = []struct {
   480  		name                  string
   481  		gh                    *ghc
   482  		expectedModifiedFiles map[string]string
   483  	}{
   484  		{
   485  			name: "modified files include vendor file",
   486  			gh: &ghc{
   487  				changes: []github.PullRequestChange{
   488  					{
   489  						Filename: "qux.go",
   490  						Patch:    "@@ -0,0 +1,5 @@\n+package bar\n+\n+func Qux() error {\n+   return nil\n+}",
   491  					},
   492  					{
   493  						Filename: "vendor/foo/bar.go",
   494  						Patch:    "@@ -0,0 +1,5 @@\n+package bar\n+\n+func Qux2() error {\n+   return nil\n+}",
   495  					},
   496  				},
   497  			},
   498  			expectedModifiedFiles: map[string]string{
   499  				"qux.go": "@@ -0,0 +1,5 @@\n+package bar\n+\n+func Qux() error {\n+   return nil\n+}",
   500  			},
   501  		},
   502  		{
   503  			name: "modified files include non go file",
   504  			gh: &ghc{
   505  				changes: []github.PullRequestChange{
   506  					{
   507  						Filename: "qux.go",
   508  						Patch:    "@@ -0,0 +1,5 @@\n+package bar\n+\n+func Qux() error {\n+   return nil\n+}",
   509  					},
   510  					{
   511  						Filename: "foo.md",
   512  						Patch:    "@@ -1,3 +1,4 @@\n+TODO",
   513  					},
   514  				},
   515  			},
   516  			expectedModifiedFiles: map[string]string{
   517  				"qux.go": "@@ -0,0 +1,5 @@\n+package bar\n+\n+func Qux() error {\n+   return nil\n+}",
   518  			},
   519  		},
   520  		{
   521  			name: "modified files include generated file",
   522  			gh: &ghc{
   523  				genfile: []byte("file-prefix zz_generated"),
   524  				changes: []github.PullRequestChange{
   525  					{
   526  						Filename: "qux.go",
   527  						Patch:    "@@ -0,0 +1,5 @@\n+package bar\n+\n+func Qux() error {\n+   return nil\n+}",
   528  					},
   529  					{
   530  						Filename: "zz_generated.wowza.go",
   531  						Patch:    "@@ -0,0 +1,5 @@\n+package bar\n+\n+func Qux2() error {\n+   return nil\n+}",
   532  					},
   533  				},
   534  			},
   535  			expectedModifiedFiles: map[string]string{
   536  				"qux.go": "@@ -0,0 +1,5 @@\n+package bar\n+\n+func Qux() error {\n+   return nil\n+}",
   537  			},
   538  		},
   539  		{
   540  			name: "modified files include removed file",
   541  			gh: &ghc{
   542  				changes: []github.PullRequestChange{
   543  					{
   544  						Filename: "qux.go",
   545  						Patch:    "@@ -0,0 +1,5 @@\n+package bar\n+\n+func Qux() error {\n+   return nil\n+}",
   546  					},
   547  					{
   548  						Filename: "bar.go",
   549  						Status:   github.PullRequestFileRemoved,
   550  						Patch:    "@@ -1,5 +0,0 @@\n-package bar\n-\n-func Qux() error {\n-   return nil\n-}",
   551  					},
   552  				},
   553  			},
   554  			expectedModifiedFiles: map[string]string{
   555  				"qux.go": "@@ -0,0 +1,5 @@\n+package bar\n+\n+func Qux() error {\n+   return nil\n+}",
   556  			},
   557  		},
   558  		{
   559  			name: "modified files include renamed file",
   560  			gh: &ghc{
   561  				changes: []github.PullRequestChange{
   562  					{
   563  						Filename: "qux.go",
   564  						Patch:    "@@ -0,0 +1,5 @@\n+package bar\n+\n+func Qux() error {\n+   return nil\n+}",
   565  					},
   566  					{
   567  						Filename: "bar.go",
   568  						Status:   github.PullRequestFileRenamed,
   569  					},
   570  				},
   571  			},
   572  			expectedModifiedFiles: map[string]string{
   573  				"qux.go": "@@ -0,0 +1,5 @@\n+package bar\n+\n+func Qux() error {\n+   return nil\n+}",
   574  			},
   575  		},
   576  		{
   577  			name: "added and modified files",
   578  			gh: &ghc{
   579  				changes: []github.PullRequestChange{
   580  					{
   581  						Filename: "qux.go",
   582  						Status:   github.PullRequestFileAdded,
   583  						Patch:    "@@ -0,0 +1,5 @@\n+package bar\n+\n+func Qux() error {\n+   return nil\n+}",
   584  					},
   585  					{
   586  						Filename: "bar.go",
   587  						Patch:    "@@ -0,0 +1,5 @@\n+package baz\n+\n+func Bar() error {\n+   return nil\n+}",
   588  					},
   589  				},
   590  			},
   591  			expectedModifiedFiles: map[string]string{
   592  				"qux.go": "@@ -0,0 +1,5 @@\n+package bar\n+\n+func Qux() error {\n+   return nil\n+}",
   593  				"bar.go": "@@ -0,0 +1,5 @@\n+package baz\n+\n+func Bar() error {\n+   return nil\n+}",
   594  			},
   595  		},
   596  		{
   597  			name: "removed and renamed files",
   598  			gh: &ghc{
   599  				changes: []github.PullRequestChange{
   600  					{
   601  						Filename: "qux.go",
   602  						Status:   github.PullRequestFileRemoved,
   603  						Patch:    "@@ -1,5 +0,0 @@\n-package bar\n-\n-func Qux() error {\n-   return nil\n-}",
   604  					},
   605  					{
   606  						Filename: "bar.go",
   607  						Status:   github.PullRequestFileRenamed,
   608  					},
   609  				},
   610  			},
   611  			expectedModifiedFiles: map[string]string{},
   612  		},
   613  	}
   614  	for _, tc := range testcases {
   615  		actualModifiedFiles, _ := modifiedGoFiles(tc.gh, "foo", "bar", 9527, "0ebb33b")
   616  		if !reflect.DeepEqual(tc.expectedModifiedFiles, actualModifiedFiles) {
   617  			t.Errorf("Expected: %#v, Got %#v in case %s.", tc.expectedModifiedFiles, actualModifiedFiles, tc.name)
   618  		}
   619  	}
   620  }