github.com/golang/review@v0.0.0-20190122205339-266ee1edf5c3/git-codereview/gofmt_test.go (about) 1 // Copyright 2014 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package main 6 7 import ( 8 "fmt" 9 "io/ioutil" 10 "os" 11 "strings" 12 "testing" 13 ) 14 15 const ( 16 goodGo = "package good\n" 17 badGo = " package bad1 " 18 badGoFixed = "package bad1\n" 19 bad2Go = " package bad2 " 20 bad2GoFixed = "package bad2\n" 21 brokenGo = "package B R O K E N" 22 ) 23 24 func TestGofmt(t *testing.T) { 25 // Test of basic operations. 26 gt := newGitTest(t) 27 defer gt.done() 28 29 gt.work(t) 30 31 if err := os.MkdirAll(gt.client+"/test/bench", 0755); err != nil { 32 t.Fatal(err) 33 } 34 if err := os.MkdirAll(gt.client+"/vendor", 0755); err != nil { 35 t.Fatal(err) 36 } 37 write(t, gt.client+"/bad.go", badGo) 38 write(t, gt.client+"/good.go", goodGo) 39 write(t, gt.client+"/vendor/bad.go", badGo) 40 write(t, gt.client+"/test/bad.go", badGo) 41 write(t, gt.client+"/test/good.go", goodGo) 42 write(t, gt.client+"/test/bench/bad.go", badGo) 43 write(t, gt.client+"/test/bench/good.go", goodGo) 44 trun(t, gt.client, "git", "add", ".") // make files tracked 45 46 testMain(t, "gofmt", "-l") 47 testPrintedStdout(t, "bad.go\n", "!good.go", fromSlash("!test/bad"), fromSlash("test/bench/bad.go"), fromSlash("!vendor/bad.go")) 48 testMain(t, "gofmt", "-l") 49 testPrintedStdout(t, "bad.go\n", "!good.go", fromSlash("!test/bad"), fromSlash("test/bench/bad.go"), fromSlash("!vendor/bad.go")) 50 51 testMain(t, "gofmt") 52 testNoStdout(t) 53 54 testMain(t, "gofmt", "-l") 55 testNoStdout(t) 56 57 write(t, gt.client+"/bad.go", badGo) 58 write(t, gt.client+"/broken.go", brokenGo) 59 trun(t, gt.client, "git", "add", ".") 60 testMainDied(t, "gofmt", "-l") 61 testPrintedStdout(t, "bad.go") 62 testPrintedStderr(t, "gofmt reported errors", "broken.go") 63 } 64 65 func TestGofmtSubdir(t *testing.T) { 66 // Check that gofmt prints relative paths for files in or below the current directory. 67 gt := newGitTest(t) 68 defer gt.done() 69 70 gt.work(t) 71 72 mkdir(t, gt.client+"/dir1") 73 mkdir(t, gt.client+"/longnamedir2") 74 write(t, gt.client+"/dir1/bad1.go", badGo) 75 write(t, gt.client+"/longnamedir2/bad2.go", badGo) 76 trun(t, gt.client, "git", "add", ".") // make files tracked 77 78 chdir(t, gt.client) 79 testMain(t, "gofmt", "-l") 80 testPrintedStdout(t, fromSlash("dir1/bad1.go"), fromSlash("longnamedir2/bad2.go")) 81 82 chdir(t, gt.client+"/dir1") 83 testMain(t, "gofmt", "-l") 84 testPrintedStdout(t, "bad1.go", fromSlash("!/bad1.go"), fromSlash("longnamedir2/bad2.go")) 85 86 chdir(t, gt.client+"/longnamedir2") 87 testMain(t, "gofmt", "-l") 88 testPrintedStdout(t, "bad2.go", fromSlash("!/bad2.go"), fromSlash("dir1/bad1.go")) 89 90 mkdir(t, gt.client+"/z") 91 chdir(t, gt.client+"/z") 92 testMain(t, "gofmt", "-l") 93 testPrintedStdout(t, fromSlash("longnamedir2/bad2.go"), fromSlash("dir1/bad1.go")) 94 } 95 96 func TestGofmtSubdirIndexCheckout(t *testing.T) { 97 // Like TestGofmtSubdir but bad Go files are only in index, not working copy. 98 // Check also that prints a correct path (relative or absolute) for files outside the 99 // current directory, even when running with Git before 2.3.0 which doesn't 100 // handle those right in git checkout-index --temp. 101 102 gt := newGitTest(t) 103 defer gt.done() 104 105 gt.work(t) 106 107 mkdir(t, gt.client+"/dir1") 108 mkdir(t, gt.client+"/longnamedir2") 109 write(t, gt.client+"/dir1/bad1.go", badGo) 110 write(t, gt.client+"/longnamedir2/bad2.go", badGo) 111 trun(t, gt.client, "git", "add", ".") // put files in index 112 write(t, gt.client+"/dir1/bad1.go", goodGo) 113 write(t, gt.client+"/longnamedir2/bad2.go", goodGo) 114 115 chdir(t, gt.client) 116 testMain(t, "gofmt", "-l") 117 testPrintedStdout(t, fromSlash("dir1/bad1.go (staged)"), fromSlash("longnamedir2/bad2.go (staged)")) 118 119 chdir(t, gt.client+"/dir1") 120 testMain(t, "gofmt", "-l") 121 testPrintedStdout(t, "bad1.go (staged)", fromSlash("!/bad1.go"), fromSlash("longnamedir2/bad2.go (staged)")) 122 123 chdir(t, gt.client+"/longnamedir2") 124 testMain(t, "gofmt", "-l") 125 testPrintedStdout(t, "bad2.go (staged)", fromSlash("!/bad2.go"), fromSlash("dir1/bad1.go (staged)")) 126 127 mkdir(t, gt.client+"/z") 128 chdir(t, gt.client+"/z") 129 testMain(t, "gofmt", "-l") 130 testPrintedStdout(t, fromSlash("longnamedir2/bad2.go (staged)"), fromSlash("dir1/bad1.go (staged)")) 131 } 132 133 func TestGofmtUnstaged(t *testing.T) { 134 // Test when unstaged files are different from staged ones. 135 // See TestHookPreCommitUnstaged for an explanation. 136 // In this test we use two different kinds of bad files, so that 137 // we can test having a bad file in the index and a different 138 // bad file in the working directory. 139 140 gt := newGitTest(t) 141 defer gt.done() 142 gt.work(t) 143 144 name := []string{"good", "bad", "bad2", "broken"} 145 orig := []string{goodGo, badGo, bad2Go, brokenGo} 146 fixed := []string{goodGo, badGoFixed, bad2GoFixed, brokenGo} 147 const N = 4 148 149 var allFiles, wantOut, wantErr []string 150 writeFiles := func(n int) { 151 allFiles = nil 152 wantOut = nil 153 wantErr = nil 154 for i := 0; i < N*N*N; i++ { 155 // determine n'th digit of 3-digit base-N value i 156 j := i 157 for k := 0; k < (3 - 1 - n); k++ { 158 j /= N 159 } 160 text := orig[j%N] 161 file := fmt.Sprintf("%s-%s-%s.go", name[i/N/N], name[(i/N)%N], name[i%N]) 162 allFiles = append(allFiles, file) 163 write(t, gt.client+"/"+file, text) 164 165 if (i/N)%N != i%N { 166 staged := file + " (staged)" 167 switch { 168 case strings.Contains(file, "-bad-"), strings.Contains(file, "-bad2-"): 169 wantOut = append(wantOut, staged) 170 wantErr = append(wantErr, "!"+staged) 171 case strings.Contains(file, "-broken-"): 172 wantOut = append(wantOut, "!"+staged) 173 wantErr = append(wantErr, staged) 174 default: 175 wantOut = append(wantOut, "!"+staged) 176 wantErr = append(wantErr, "!"+staged) 177 } 178 } 179 switch { 180 case strings.Contains(file, "-bad.go"), strings.Contains(file, "-bad2.go"): 181 if (i/N)%N != i%N { 182 file += " (unstaged)" 183 } 184 wantOut = append(wantOut, file+"\n") 185 wantErr = append(wantErr, "!"+file+":", "!"+file+" (unstaged)") 186 case strings.Contains(file, "-broken.go"): 187 wantOut = append(wantOut, "!"+file+"\n", "!"+file+" (unstaged)") 188 wantErr = append(wantErr, file+":") 189 default: 190 wantOut = append(wantOut, "!"+file+"\n", "!"+file+":", "!"+file+" (unstaged)") 191 wantErr = append(wantErr, "!"+file+"\n", "!"+file+":", "!"+file+" (unstaged)") 192 } 193 } 194 } 195 196 // committed files 197 writeFiles(0) 198 trun(t, gt.client, "git", "add", ".") 199 trun(t, gt.client, "git", "commit", "-m", "msg") 200 201 // staged files 202 writeFiles(1) 203 trun(t, gt.client, "git", "add", ".") 204 205 // unstaged files 206 writeFiles(2) 207 208 // Check that gofmt -l shows the right output and errors. 209 testMainDied(t, "gofmt", "-l") 210 testPrintedStdout(t, wantOut...) 211 testPrintedStderr(t, wantErr...) 212 213 // Again (last command should not have written anything). 214 testMainDied(t, "gofmt", "-l") 215 testPrintedStdout(t, wantOut...) 216 testPrintedStderr(t, wantErr...) 217 218 // Reformat in place. 219 testMainDied(t, "gofmt") 220 testNoStdout(t) 221 testPrintedStderr(t, wantErr...) 222 223 // Read files to make sure unstaged did not bleed into staged. 224 for i, file := range allFiles { 225 if data, err := ioutil.ReadFile(gt.client + "/" + file); err != nil { 226 t.Errorf("%v", err) 227 } else if want := fixed[i%N]; string(data) != want { 228 t.Errorf("%s: working tree = %q, want %q", file, string(data), want) 229 } 230 if data, want := trun(t, gt.client, "git", "show", ":"+file), fixed[i/N%N]; data != want { 231 t.Errorf("%s: index = %q, want %q", file, data, want) 232 } 233 if data, want := trun(t, gt.client, "git", "show", "HEAD:"+file), orig[i/N/N]; data != want { 234 t.Errorf("%s: commit = %q, want %q", file, data, want) 235 } 236 } 237 238 // Check that gofmt -l still shows the errors. 239 testMainDied(t, "gofmt", "-l") 240 testNoStdout(t) 241 testPrintedStderr(t, wantErr...) 242 } 243 244 func TestGofmtAmbiguousRevision(t *testing.T) { 245 gt := newGitTest(t) 246 defer gt.done() 247 248 t.Logf("creating file that conflicts with revision parameter") 249 write(t, gt.client+"/HEAD", "foo") 250 251 testMain(t, "gofmt") 252 } 253 254 func TestGofmtFastForwardMerge(t *testing.T) { 255 gt := newGitTest(t) 256 defer gt.done() 257 258 // merge dev.branch into master 259 write(t, gt.server+"/file", "more work") 260 trun(t, gt.server, "git", "commit", "-m", "work", "file") 261 trun(t, gt.server, "git", "merge", "-m", "merge", "dev.branch") 262 263 // add bad go file on master 264 write(t, gt.server+"/bad.go", "package {\n") 265 trun(t, gt.server, "git", "add", "bad.go") 266 trun(t, gt.server, "git", "commit", "-m", "bad go") 267 268 // update client 269 trun(t, gt.client, "git", "checkout", "master") 270 trun(t, gt.client, "git", "pull") 271 testMain(t, "change", "dev.branch") 272 trun(t, gt.client, "git", "pull") 273 274 // merge master into dev.branch, fast forward merge 275 trun(t, gt.client, "git", "merge", "--ff-only", "master") 276 277 // verify that now client is in a state where just the tag is changing; there's no new commit. 278 masterHash := strings.TrimSpace(trun(t, gt.server, "git", "rev-parse", "master")) 279 devHash := strings.TrimSpace(trun(t, gt.client, "git", "rev-parse", "HEAD")) 280 281 if masterHash != devHash { 282 t.Logf("branches:\n%s", trun(t, gt.client, "git", "branch", "-a", "-v")) 283 t.Logf("log:\n%s", trun(t, gt.client, "git", "log", "--graph", "--decorate")) 284 t.Fatalf("setup wrong - got different commit hashes on master and dev branch") 285 } 286 287 // check that gofmt finds nothing to do, ignoring the bad (but committed) file1.go. 288 testMain(t, "gofmt") 289 testNoStdout(t) 290 testNoStderr(t) 291 }