github.com/jdhenke/godel@v0.0.0-20161213181855-abeb3861bf0d/apps/okgo/integration_test/integration_test.go (about) 1 // Copyright 2016 Palantir Technologies, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package integration_test 16 17 import ( 18 "fmt" 19 "io/ioutil" 20 "os" 21 "path" 22 "strings" 23 "testing" 24 25 "github.com/nmiyake/pkg/dirs" 26 "github.com/nmiyake/pkg/gofiles" 27 "github.com/palantir/amalgomate/amalgomated" 28 "github.com/stretchr/testify/assert" 29 "github.com/stretchr/testify/require" 30 31 "github.com/palantir/godel/apps/okgo/checkoutput" 32 "github.com/palantir/godel/apps/okgo/checks" 33 "github.com/palantir/godel/apps/okgo/cmd/cmdlib" 34 "github.com/palantir/godel/apps/okgo/config" 35 "github.com/palantir/godel/apps/okgo/params" 36 "github.com/palantir/godel/pkg/products" 37 ) 38 39 func TestCheckers(t *testing.T) { 40 cli, err := products.Bin("okgo") 41 require.NoError(t, err) 42 43 for i, currCase := range []struct { 44 check amalgomated.Cmd 45 want []string 46 }{ 47 { 48 check: cmdlib.Instance().MustNewCmd("deadcode"), 49 want: []string{ 50 "pkg1/bad.go:27:1: deadcode is unused", 51 "pkg1/bad.go:40:1: varcheck is unused", 52 "pkg2/bad2.go:27:1: deadcode is unused", 53 "pkg2/bad2.go:40:1: varcheck is unused", 54 }, 55 }, 56 { 57 check: cmdlib.Instance().MustNewCmd("errcheck"), 58 want: []string{ 59 "pkg1/bad.go:11:8: helper()", 60 "pkg2/bad2.go:11:8: helper()", 61 }, 62 }, 63 { 64 check: cmdlib.Instance().MustNewCmd("golint"), 65 want: []string{ 66 `pkg1/bad.go:49:1: comment on exported function Lint should be of the form "Lint ..."`, 67 `pkg2/bad2.go:49:1: comment on exported function Lint should be of the form "Lint ..."`, 68 }, 69 }, 70 { 71 check: cmdlib.Instance().MustNewCmd("govet"), 72 want: []string{ 73 "pkg1/bad.go:23: self-assignment of foo to foo", 74 "pkg2/bad2.go:23: self-assignment of foo to foo", 75 }, 76 }, 77 { 78 check: cmdlib.Instance().MustNewCmd("ineffassign"), 79 want: []string{ 80 "pkg1/bad.go:34:2: ineffectual assignment to kvs", 81 "pkg1/bad.go:36:2: ineffectual assignment to kvs", 82 "pkg2/bad2.go:34:2: ineffectual assignment to kvs", 83 "pkg2/bad2.go:36:2: ineffectual assignment to kvs", 84 }, 85 }, 86 { 87 check: cmdlib.Instance().MustNewCmd("outparamcheck"), 88 want: []string{ 89 `github.com/palantir/godel/apps/okgo/integration_test/testdata/standard/pkg1/bad.go:16:26: _ = json.Unmarshal(nil, "") // 2nd argument of 'Unmarshal' requires '&'`, 90 `github.com/palantir/godel/apps/okgo/integration_test/testdata/standard/pkg2/bad2.go:16:26: _ = json.Unmarshal(nil, "") // 2nd argument of 'Unmarshal' requires '&'`, 91 }, 92 }, 93 { 94 check: cmdlib.Instance().MustNewCmd("unconvert"), 95 want: []string{ 96 "pkg1/bad.go:45:14: unnecessary conversion", 97 "pkg2/bad2.go:45:14: unnecessary conversion", 98 }, 99 }, 100 { 101 check: cmdlib.Instance().MustNewCmd("varcheck"), 102 want: []string{ 103 "pkg1/bad.go:40:7: varcheck", 104 "pkg2/bad2.go:40:7: varcheck", 105 }, 106 }, 107 } { 108 checker, err := checks.GetChecker(currCase.check) 109 require.NoError(t, err) 110 111 runner := amalgomated.PathCmder(cli, amalgomated.ProxyCmdPrefix+currCase.check.Name()) 112 lineInfo, err := checker.Check(runner, "./testdata/standard", params.OKGo{}) 113 require.NoError(t, err, "Case %d", i) 114 115 assert.Equal(t, currCase.want, toStringSlice(lineInfo), "Case %d", i) 116 } 117 } 118 119 func TestCompilesChecker(t *testing.T) { 120 cli, err := products.Bin("okgo") 121 require.NoError(t, err) 122 123 wd, err := os.Getwd() 124 require.NoError(t, err) 125 126 tmpDir, cleanup, err := dirs.TempDir(wd, "") 127 defer cleanup() 128 require.NoError(t, err) 129 130 for i, currCase := range []struct { 131 check amalgomated.Cmd 132 filesToWrite []gofiles.GoFileSpec 133 pathToCheck func(projectDir string) string 134 want func(files map[string]gofiles.GoFile) []string 135 customMatcher func(caseNum int, expected, actual []string) 136 }{ 137 { 138 check: cmdlib.Instance().MustNewCmd("compiles"), 139 filesToWrite: []gofiles.GoFileSpec{ 140 { 141 RelPath: "foo/foo.go", 142 Src: `package foo 143 func Foo() int { 144 return "foo" 145 }`, 146 }, 147 }, 148 pathToCheck: func(projectDir string) string { 149 return path.Join(projectDir, "foo") 150 }, 151 want: func(files map[string]gofiles.GoFile) []string { 152 return []string{ 153 `foo.go:3:9: cannot convert "foo" (untyped string constant) to int`, 154 } 155 }, 156 }, 157 { 158 check: cmdlib.Instance().MustNewCmd("compiles"), 159 filesToWrite: []gofiles.GoFileSpec{ 160 { 161 RelPath: "foo/foo.go", 162 Src: `package foo 163 import "bar" 164 func Foo() { 165 bar.Bar() 166 }`, 167 }, 168 }, 169 pathToCheck: func(projectDir string) string { 170 return path.Join(projectDir, "foo") 171 }, 172 want: func(files map[string]gofiles.GoFile) []string { 173 return []string{ 174 `foo.go:2:8: could not import bar \(cannot find package "bar" in any of: 175 .+ \(vendor tree\) 176 .+ \(from \$GOROOT\) 177 .+ \(from \$GOPATH\)\)`, 178 `foo.go:4:2: undeclared name: bar`, 179 } 180 }, 181 customMatcher: func(caseNum int, want, got []string) { 182 assert.Equal(t, len(want), len(got), "Case %d: number of output lines do not match") 183 184 for i := range want { 185 assert.Regexp(t, want[i], got[i], "Case %d", i) 186 } 187 }, 188 }, 189 { 190 check: cmdlib.Instance().MustNewCmd("extimport"), 191 filesToWrite: []gofiles.GoFileSpec{ 192 { 193 RelPath: "foo/foo.go", 194 Src: `package foo 195 import "{{index . "bar/bar.go"}}" 196 func Foo() { 197 bar.Bar() 198 } 199 `, 200 }, 201 { 202 RelPath: "bar/bar.go", 203 Src: `package bar; func Bar() {}`, 204 }, 205 }, 206 pathToCheck: func(projectDir string) string { 207 return path.Join(projectDir, "foo") 208 }, 209 want: func(files map[string]gofiles.GoFile) []string { 210 return []string{ 211 fmt.Sprintf(`foo.go:2:8: imports external package %s`, files["bar/bar.go"].ImportPath), 212 } 213 }, 214 }, 215 } { 216 currCaseProjectDir, err := ioutil.TempDir(tmpDir, "") 217 require.NoError(t, err, "Case %d", i) 218 219 files, err := gofiles.Write(currCaseProjectDir, currCase.filesToWrite) 220 require.NoError(t, err, "Case %d", i) 221 222 checker, err := checks.GetChecker(currCase.check) 223 require.NoError(t, err, "Case %d", i) 224 225 runner := amalgomated.PathCmder(cli, amalgomated.ProxyCmdPrefix+currCase.check.Name()) 226 lineInfo, err := checker.Check(runner, currCase.pathToCheck(currCaseProjectDir), params.OKGo{}) 227 require.NoError(t, err, "Case %d", i) 228 229 want := currCase.want(files) 230 got := toStringSlice(lineInfo) 231 if currCase.customMatcher == nil { 232 assert.Equal(t, want, got, "Case %d", i) 233 } else { 234 currCase.customMatcher(i, want, got) 235 } 236 } 237 } 238 239 func TestFilters(t *testing.T) { 240 cli, err := products.Bin("okgo") 241 require.NoError(t, err) 242 243 cmd := cmdlib.Instance().MustNewCmd("golint") 244 checker, err := checks.GetChecker(cmd) 245 require.NoError(t, err) 246 runner := amalgomated.PathCmder(cli, amalgomated.ProxyCmdPrefix+cmd.Name()) 247 248 for i, currCase := range []struct { 249 filters []checkoutput.Filterer 250 want []string 251 }{ 252 { 253 filters: nil, 254 want: []string{ 255 "bad.go:3:1: exported function Bad should have comment or be unexported", 256 "mock/mock.go:3:1: exported function Mock should have comment or be unexported", 257 "nested/mock/nestedmock.go:3:1: exported function NestedMock should have comment or be unexported", 258 }, 259 }, 260 { 261 filters: []checkoutput.Filterer{ 262 checkoutput.RelativePathFilter("mock"), 263 }, 264 want: []string{ 265 "bad.go:3:1: exported function Bad should have comment or be unexported", 266 "nested/mock/nestedmock.go:3:1: exported function NestedMock should have comment or be unexported", 267 }, 268 }, 269 { 270 filters: []checkoutput.Filterer{ 271 checkoutput.NamePathFilter("mock"), 272 }, 273 want: []string{ 274 "bad.go:3:1: exported function Bad should have comment or be unexported", 275 }, 276 }, 277 { 278 filters: []checkoutput.Filterer{ 279 checkoutput.MessageRegexpFilter("should have comment or be unexported"), 280 }, 281 want: []string{}, 282 }, 283 } { 284 lineInfo, err := checker.Check(runner, "./testdata/filter", params.OKGo{}) 285 require.NoError(t, err, "Case %d", i) 286 287 filteredLines, err := checkoutput.ApplyFilters(lineInfo, currCase.filters) 288 require.NoError(t, err, "Case %d", i) 289 290 assert.Equal(t, currCase.want, toStringSlice(filteredLines), "Case %d", i) 291 } 292 } 293 294 func TestCheckerUsesConfig(t *testing.T) { 295 cli, err := products.Bin("okgo") 296 require.NoError(t, err) 297 298 tmpDir, cleanup, err := dirs.TempDir("", "") 299 defer cleanup() 300 require.NoError(t, err) 301 302 for i, currCase := range []struct { 303 config string 304 want []string 305 }{ 306 { 307 config: "", 308 want: []string{ 309 "bad.go:3:1: exported function Bad should have comment or be unexported", 310 "mock/mock.go:3:1: exported function Mock should have comment or be unexported", 311 "nested/mock/nestedmock.go:3:1: exported function NestedMock should have comment or be unexported", 312 }, 313 }, 314 { 315 config: ` 316 exclude: 317 paths: 318 - "mock" 319 `, 320 want: []string{ 321 "bad.go:3:1: exported function Bad should have comment or be unexported", 322 "nested/mock/nestedmock.go:3:1: exported function NestedMock should have comment or be unexported", 323 }, 324 }, 325 { 326 config: ` 327 exclude: 328 names: 329 - "m.ck" 330 `, 331 want: []string{ 332 "bad.go:3:1: exported function Bad should have comment or be unexported", 333 }, 334 }, 335 { 336 config: ` 337 checks: 338 golint: 339 filters: 340 - type: "message" 341 value: "should have comment or be unexported" 342 `, 343 want: []string{}, 344 }, 345 } { 346 tmpFile, err := ioutil.TempFile(tmpDir, "") 347 require.NoError(t, err, "Case %d", i) 348 tmpFilePath := tmpFile.Name() 349 err = tmpFile.Close() 350 require.NoError(t, err, "Case %d", i) 351 err = ioutil.WriteFile(tmpFilePath, []byte(unindent(currCase.config)), 0644) 352 require.NoError(t, err, "Case %d", i) 353 354 cfg, err := config.Load(tmpFilePath, "") 355 require.NoError(t, err, "Case %d", i) 356 357 cmd := cmdlib.Instance().MustNewCmd("golint") 358 checker, err := checks.GetChecker(cmd) 359 require.NoError(t, err, "Case %d", i) 360 361 runner := amalgomated.PathCmder(cli, amalgomated.ProxyCmdPrefix+cmd.Name()) 362 lineInfo, err := checker.Check(runner, "./testdata/filter", cfg) 363 require.NoError(t, err, "Case %d", i) 364 365 assert.Equal(t, currCase.want, toStringSlice(lineInfo), "Case %d", i) 366 } 367 } 368 369 func toStringSlice(input []checkoutput.Issue) []string { 370 output := make([]string, len(input)) 371 for i, curr := range input { 372 output[i] = curr.String() 373 } 374 return output 375 } 376 377 func unindent(input string) string { 378 return strings.Replace(input, "\n\t\t\t", "\n", -1) 379 }