github.com/rancher/moq@v0.0.0-20200712062324-13d1f37d2d77/pkg/moq/moq_test.go (about) 1 package moq 2 3 import ( 4 "bytes" 5 "flag" 6 "fmt" 7 "io/ioutil" 8 "os" 9 "os/exec" 10 "path/filepath" 11 "strings" 12 "testing" 13 14 "github.com/pmezard/go-difflib/difflib" 15 ) 16 17 var update = flag.Bool("update", false, "Update golden files.") 18 19 func TestMoq(t *testing.T) { 20 m, err := New(Config{SrcDir: "testpackages/example"}) 21 if err != nil { 22 t.Fatalf("moq.New: %s", err) 23 } 24 var buf bytes.Buffer 25 err = m.Mock(&buf, "PersonStore") 26 if err != nil { 27 t.Errorf("m.Mock: %s", err) 28 } 29 s := buf.String() 30 // assertions of things that should be mentioned 31 var strs = []string{ 32 "package example", 33 "type PersonStoreMock struct", 34 "CreateFunc func(ctx context.Context, person *Person, confirm bool) error", 35 "GetFunc func(ctx context.Context, id string) (*Person, error)", 36 "func (mock *PersonStoreMock) Create(ctx context.Context, person *Person, confirm bool) error", 37 "func (mock *PersonStoreMock) Get(ctx context.Context, id string) (*Person, error)", 38 "panic(\"PersonStoreMock.CreateFunc: method is nil but PersonStore.Create was just called\")", 39 "panic(\"PersonStoreMock.GetFunc: method is nil but PersonStore.Get was just called\")", 40 "lockPersonStoreMockGet.Lock()", 41 "mock.calls.Get = append(mock.calls.Get, callInfo)", 42 "lockPersonStoreMockGet.Unlock()", 43 "// ID is the id argument value", 44 } 45 for _, str := range strs { 46 if !strings.Contains(s, str) { 47 t.Errorf("expected but missing: \"%s\"", str) 48 } 49 } 50 } 51 52 func TestMoqWithStaticCheck(t *testing.T) { 53 m, err := New(Config{SrcDir: "testpackages/example"}) 54 if err != nil { 55 t.Fatalf("moq.New: %s", err) 56 } 57 var buf bytes.Buffer 58 err = m.Mock(&buf, "PersonStore") 59 if err != nil { 60 t.Errorf("m.Mock: %s", err) 61 } 62 s := buf.String() 63 // assertions of things that should be mentioned 64 var strs = []string{ 65 "package example", 66 "var _ PersonStore = &PersonStoreMock{}", 67 "type PersonStoreMock struct", 68 "CreateFunc func(ctx context.Context, person *Person, confirm bool) error", 69 "GetFunc func(ctx context.Context, id string) (*Person, error)", 70 "func (mock *PersonStoreMock) Create(ctx context.Context, person *Person, confirm bool) error", 71 "func (mock *PersonStoreMock) Get(ctx context.Context, id string) (*Person, error)", 72 "panic(\"PersonStoreMock.CreateFunc: method is nil but PersonStore.Create was just called\")", 73 "panic(\"PersonStoreMock.GetFunc: method is nil but PersonStore.Get was just called\")", 74 "lockPersonStoreMockGet.Lock()", 75 "mock.calls.Get = append(mock.calls.Get, callInfo)", 76 "lockPersonStoreMockGet.Unlock()", 77 "// ID is the id argument value", 78 } 79 for _, str := range strs { 80 if !strings.Contains(s, str) { 81 t.Errorf("expected but missing: \"%s\"", str) 82 } 83 } 84 } 85 86 func TestMoqWithAlias(t *testing.T) { 87 m, err := New(Config{SrcDir: "testpackages/example"}) 88 if err != nil { 89 t.Fatalf("moq.New: %s", err) 90 } 91 var buf bytes.Buffer 92 err = m.Mock(&buf, "PersonStore:AnotherPersonStoreMock") 93 if err != nil { 94 t.Errorf("m.Mock: %s", err) 95 } 96 s := buf.String() 97 // assertions of things that should be mentioned 98 var strs = []string{ 99 "package example", 100 "type AnotherPersonStoreMock struct", 101 "CreateFunc func(ctx context.Context, person *Person, confirm bool) error", 102 "GetFunc func(ctx context.Context, id string) (*Person, error)", 103 "func (mock *AnotherPersonStoreMock) Create(ctx context.Context, person *Person, confirm bool) error", 104 "func (mock *AnotherPersonStoreMock) Get(ctx context.Context, id string) (*Person, error)", 105 "panic(\"AnotherPersonStoreMock.CreateFunc: method is nil but PersonStore.Create was just called\")", 106 "panic(\"AnotherPersonStoreMock.GetFunc: method is nil but PersonStore.Get was just called\")", 107 "lockAnotherPersonStoreMockGet.Lock()", 108 "mock.calls.Get = append(mock.calls.Get, callInfo)", 109 "lockAnotherPersonStoreMockGet.Unlock()", 110 "// ID is the id argument value", 111 } 112 for _, str := range strs { 113 if !strings.Contains(s, str) { 114 t.Errorf("expected but missing: \"%s\"", str) 115 } 116 } 117 } 118 119 func TestMoqExplicitPackage(t *testing.T) { 120 m, err := New(Config{SrcDir: "testpackages/example", PkgName: "different"}) 121 if err != nil { 122 t.Fatalf("moq.New: %s", err) 123 } 124 var buf bytes.Buffer 125 err = m.Mock(&buf, "PersonStore") 126 if err != nil { 127 t.Errorf("m.Mock: %s", err) 128 } 129 s := buf.String() 130 // assertions of things that should be mentioned 131 var strs = []string{ 132 "package different", 133 "type PersonStoreMock struct", 134 "CreateFunc func(ctx context.Context, person *example.Person, confirm bool) error", 135 "GetFunc func(ctx context.Context, id string) (*example.Person, error)", 136 "func (mock *PersonStoreMock) Create(ctx context.Context, person *example.Person, confirm bool) error", 137 "func (mock *PersonStoreMock) Get(ctx context.Context, id string) (*example.Person, error)", 138 } 139 for _, str := range strs { 140 if !strings.Contains(s, str) { 141 t.Errorf("expected but missing: \"%s\"", str) 142 } 143 } 144 } 145 146 func TestMoqExplicitPackageWithStaticCheck(t *testing.T) { 147 m, err := New(Config{SrcDir: "testpackages/example", PkgName: "different"}) 148 if err != nil { 149 t.Fatalf("moq.New: %s", err) 150 } 151 var buf bytes.Buffer 152 err = m.Mock(&buf, "PersonStore") 153 if err != nil { 154 t.Errorf("m.Mock: %s", err) 155 } 156 s := buf.String() 157 // assertions of things that should be mentioned 158 var strs = []string{ 159 "package different", 160 "var _ example.PersonStore = &PersonStoreMock{}", 161 "type PersonStoreMock struct", 162 "CreateFunc func(ctx context.Context, person *example.Person, confirm bool) error", 163 "GetFunc func(ctx context.Context, id string) (*example.Person, error)", 164 "func (mock *PersonStoreMock) Create(ctx context.Context, person *example.Person, confirm bool) error", 165 "func (mock *PersonStoreMock) Get(ctx context.Context, id string) (*example.Person, error)", 166 } 167 for _, str := range strs { 168 if !strings.Contains(s, str) { 169 t.Errorf("expected but missing: \"%s\"", str) 170 } 171 } 172 } 173 174 func TestNotCreatingEmptyDirWhenPkgIsGiven(t *testing.T) { 175 m, err := New(Config{SrcDir: "testpackages/example", PkgName: "different"}) 176 if err != nil { 177 t.Fatalf("moq.New: %s", err) 178 } 179 var buf bytes.Buffer 180 err = m.Mock(&buf, "PersonStore") 181 if err != nil { 182 t.Errorf("m.Mock: %s", err) 183 } 184 s := buf.String() 185 if len(s) == 0 { 186 t.Fatalf("mock should be generated") 187 } 188 if _, err := os.Stat("testpackages/example/different"); !os.IsNotExist(err) { 189 t.Fatalf("no empty dir should be created by moq") 190 } 191 } 192 193 // TestVariadicArguments tests to ensure variadic work as 194 // expected. 195 // see https://github.com/matryer/moq/issues/5 196 func TestVariadicArguments(t *testing.T) { 197 m, err := New(Config{SrcDir: "testpackages/variadic"}) 198 if err != nil { 199 t.Fatalf("moq.New: %s", err) 200 } 201 var buf bytes.Buffer 202 err = m.Mock(&buf, "Greeter") 203 if err != nil { 204 t.Errorf("m.Mock: %s", err) 205 } 206 s := buf.String() 207 // assertions of things that should be mentioned 208 var strs = []string{ 209 "package variadic", 210 "type GreeterMock struct", 211 "GreetFunc func(ctx context.Context, names ...string) string", 212 "return mock.GreetFunc(ctx, names...)", 213 } 214 for _, str := range strs { 215 if !strings.Contains(s, str) { 216 t.Errorf("expected but missing: \"%s\"", str) 217 } 218 } 219 } 220 221 // TestSliceResult tests to ensure slice return data type works as 222 // expected. 223 // see https://github.com/matryer/moq/issues/124 224 func TestSliceResult(t *testing.T) { 225 m, err := New(Config{SrcDir: "testpackages/variadic"}) 226 if err != nil { 227 t.Fatalf("moq.New: %s", err) 228 } 229 230 var buf bytes.Buffer 231 if err = m.Mock(&buf, "Echoer"); err != nil { 232 t.Errorf("m.Mock: %s", err) 233 } 234 235 golden := filepath.Join("testpackages/variadic/testdata", "echoer.golden.go") 236 if err := matchGoldenFile(golden, buf.Bytes()); err != nil { 237 t.Errorf("check golden file: %s", err) 238 } 239 } 240 241 func TestNothingToReturn(t *testing.T) { 242 m, err := New(Config{SrcDir: "testpackages/example"}) 243 if err != nil { 244 t.Fatalf("moq.New: %s", err) 245 } 246 var buf bytes.Buffer 247 err = m.Mock(&buf, "PersonStore") 248 if err != nil { 249 t.Errorf("m.Mock: %s", err) 250 } 251 s := buf.String() 252 if strings.Contains(s, `return mock.ClearCacheFunc(id)`) { 253 t.Errorf("should not have return for items that have no return arguments") 254 } 255 // assertions of things that should be mentioned 256 var strs = []string{ 257 "mock.ClearCacheFunc(id)", 258 } 259 for _, str := range strs { 260 if !strings.Contains(s, str) { 261 t.Errorf("expected but missing: \"%s\"", str) 262 } 263 } 264 } 265 266 func TestChannelNames(t *testing.T) { 267 m, err := New(Config{SrcDir: "testpackages/channels"}) 268 if err != nil { 269 t.Fatalf("moq.New: %s", err) 270 } 271 var buf bytes.Buffer 272 err = m.Mock(&buf, "Queuer") 273 if err != nil { 274 t.Errorf("m.Mock: %s", err) 275 } 276 s := buf.String() 277 var strs = []string{ 278 "func (mock *QueuerMock) Sub(topic string) (<-chan Queue, error)", 279 } 280 for _, str := range strs { 281 if !strings.Contains(s, str) { 282 t.Errorf("expected but missing: \"%s\"", str) 283 } 284 } 285 } 286 287 func TestImports(t *testing.T) { 288 m, err := New(Config{SrcDir: "testpackages/imports/two"}) 289 if err != nil { 290 t.Fatalf("moq.New: %s", err) 291 } 292 var buf bytes.Buffer 293 err = m.Mock(&buf, "DoSomething") 294 if err != nil { 295 t.Errorf("m.Mock: %s", err) 296 } 297 s := buf.String() 298 var strs = []string{ 299 ` "sync"`, 300 ` "github.com/matryer/moq/pkg/moq/testpackages/imports/one"`, 301 } 302 for _, str := range strs { 303 if !strings.Contains(s, str) { 304 t.Errorf("expected but missing: \"%s\"", str) 305 } 306 if len(strings.Split(s, str)) > 2 { 307 t.Errorf("more than one: \"%s\"", str) 308 } 309 } 310 } 311 312 func TestFormatter(t *testing.T) { 313 cases := []struct { 314 name string 315 conf Config 316 }{ 317 {name: "gofmt", conf: Config{SrcDir: "testpackages/imports/two"}}, 318 {name: "goimports", conf: Config{SrcDir: "testpackages/imports/two", Formatter: "goimports"}}, 319 } 320 for _, tc := range cases { 321 t.Run(tc.name, func(t *testing.T) { 322 m, err := New(tc.conf) 323 if err != nil { 324 t.Fatalf("moq.New: %s", err) 325 } 326 var buf bytes.Buffer 327 err = m.Mock(&buf, "DoSomething") 328 if err != nil { 329 t.Errorf("m.Mock: %s", err) 330 } 331 332 golden := filepath.Join("testpackages/imports/testdata", tc.name+".golden.go") 333 if err := matchGoldenFile(golden, buf.Bytes()); err != nil { 334 t.Errorf("check golden file: %s", err) 335 } 336 }) 337 } 338 } 339 340 func matchGoldenFile(goldenFile string, actual []byte) error { 341 // To update golden files, run the following: 342 // go test -v -run '^<Test-Name>$' github.com/matryer/moq/pkg/moq -update 343 if *update { 344 if err := ioutil.WriteFile(goldenFile, actual, 0644); err != nil { 345 return fmt.Errorf("write: %s: %s", goldenFile, err) 346 } 347 348 return nil 349 } 350 351 expected, err := ioutil.ReadFile(goldenFile) 352 if err != nil { 353 return fmt.Errorf("read: %s: %s", goldenFile, err) 354 } 355 356 // Normalise newlines 357 actual, expected = normalize(actual), normalize(expected) 358 if !bytes.Equal(expected, actual) { 359 diff, err := difflib.GetUnifiedDiffString(difflib.UnifiedDiff{ 360 A: difflib.SplitLines(string(expected)), 361 B: difflib.SplitLines(string(actual)), 362 FromFile: "Expected", 363 ToFile: "Actual", 364 Context: 1, 365 }) 366 if err != nil { 367 return fmt.Errorf("diff: %s", err) 368 } 369 return fmt.Errorf("match: %s:\n%s", goldenFile, diff) 370 } 371 372 return nil 373 } 374 375 func TestTemplateFuncs(t *testing.T) { 376 fn := templateFuncs["Exported"].(func(string) string) 377 if fn("var") != "Var" { 378 t.Errorf("exported didn't work: %s", fn("var")) 379 } 380 } 381 382 func TestVendoredPackages(t *testing.T) { 383 m, err := New(Config{SrcDir: "testpackages/vendoring/user"}) 384 if err != nil { 385 t.Fatalf("moq.New: %s", err) 386 } 387 var buf bytes.Buffer 388 err = m.Mock(&buf, "Service") 389 if err != nil { 390 t.Errorf("mock error: %s", err) 391 } 392 s := buf.String() 393 // assertions of things that should be mentioned 394 var strs = []string{ 395 `"github.com/matryer/somerepo"`, 396 } 397 for _, str := range strs { 398 if !strings.Contains(s, str) { 399 t.Errorf("expected but missing: \"%s\"", str) 400 } 401 } 402 } 403 404 func TestVendoredInterface(t *testing.T) { 405 m, err := New(Config{ 406 SrcDir: "testpackages/vendoring/vendor/github.com/matryer/somerepo", 407 PkgName: "someother", 408 }) 409 if err != nil { 410 t.Fatalf("moq.New: %s", err) 411 } 412 var buf bytes.Buffer 413 err = m.Mock(&buf, "SomeService") 414 if err != nil { 415 t.Errorf("mock error: %s", err) 416 } 417 s := buf.String() 418 // assertions of things that should be mentioned 419 var strs = []string{ 420 `"github.com/matryer/somerepo"`, 421 } 422 for _, str := range strs { 423 if !strings.Contains(s, str) { 424 t.Errorf("expected but missing: \"%s\"", str) 425 } 426 } 427 incorrectImport := `"github.com/matryer/moq/pkg/moq/testpackages/vendoring/vendor/github.com/matryer/somerepo"` 428 if strings.Contains(s, incorrectImport) { 429 t.Errorf("unexpected import: %s", incorrectImport) 430 } 431 } 432 433 func TestVendoredBuildConstraints(t *testing.T) { 434 m, err := New(Config{SrcDir: "testpackages/buildconstraints/user"}) 435 if err != nil { 436 t.Fatalf("moq.New: %s", err) 437 } 438 var buf bytes.Buffer 439 err = m.Mock(&buf, "Service") 440 if err != nil { 441 t.Errorf("mock error: %s", err) 442 } 443 s := buf.String() 444 // assertions of things that should be mentioned 445 var strs = []string{ 446 `"github.com/matryer/buildconstraints"`, 447 } 448 for _, str := range strs { 449 if !strings.Contains(s, str) { 450 t.Errorf("expected but missing: \"%s\"", str) 451 } 452 } 453 } 454 455 // TestDotImports tests for https://github.com/matryer/moq/issues/21. 456 func TestDotImports(t *testing.T) { 457 preDir, err := os.Getwd() 458 if err != nil { 459 t.Errorf("Getwd: %s", err) 460 } 461 err = os.Chdir("testpackages/dotimport") 462 if err != nil { 463 t.Errorf("Chdir: %s", err) 464 } 465 defer func() { 466 err := os.Chdir(preDir) 467 if err != nil { 468 t.Errorf("Chdir back: %s", err) 469 } 470 }() 471 m, err := New(Config{SrcDir: ".", PkgName: "moqtest_test"}) 472 if err != nil { 473 t.Fatalf("moq.New: %s", err) 474 } 475 var buf bytes.Buffer 476 err = m.Mock(&buf, "Service") 477 if err != nil { 478 t.Errorf("mock error: %s", err) 479 } 480 s := buf.String() 481 if strings.Contains(s, `"."`) { 482 t.Error("contains invalid dot import") 483 } 484 } 485 486 func TestEmptyInterface(t *testing.T) { 487 m, err := New(Config{SrcDir: "testpackages/emptyinterface"}) 488 if err != nil { 489 t.Fatalf("moq.New: %s", err) 490 } 491 var buf bytes.Buffer 492 err = m.Mock(&buf, "Empty") 493 if err != nil { 494 t.Errorf("mock error: %s", err) 495 } 496 s := buf.String() 497 if strings.Contains(s, `"sync"`) { 498 t.Error("contains sync import, although this package isn't used") 499 } 500 } 501 502 func helperExec(t *testing.T, args []string, dir string) []byte { 503 cmd := exec.Command(args[0], args[1:]...) 504 cmd.Dir = dir 505 output, err := cmd.CombinedOutput() 506 if err != nil { 507 t.Fatalf("Exec: %s; Output:\n%s\n", err, output) 508 } 509 return output 510 } 511 512 func TestGoGenerateVendoredPackages(t *testing.T) { 513 output := helperExec(t, []string{"go", "generate", "./..."}, "testpackages/gogenvendoring") 514 if bytes.Contains(output, []byte(`vendor/`)) { 515 t.Error("contains vendor directory in import path") 516 } 517 } 518 519 func TestOverrlappingImports(t *testing.T) { 520 m, err := New(Config{ 521 SrcDir: "testpackages/overlappingimports", 522 PkgName: "template", 523 }) 524 if err != nil { 525 t.Fatalf("moq.New: %s", err) 526 } 527 var buf bytes.Buffer 528 err = m.Mock(&buf, "Example", "Example2") 529 if err != nil { 530 t.Errorf("mock error: %s", err) 531 } 532 s := buf.String() 533 // assertions of things that should be mentioned 534 var strs = []string{ 535 `template1 "github.com/matryer/moq/pkg/moq/testpackages/overlappingimports"`, 536 `"github.com/matryer/moq/pkg/moq/testpackages/overlappingimports/one"`, 537 `one1 "github.com/matryer/moq/pkg/moq/testpackages/overlappingimports/one/one"`, 538 `"html/template"`, 539 `custom "text/template"`, 540 `HTML() template.HTML`, 541 `Text() custom.Template`, 542 `Self() template1.Example`, 543 `MultiFile() one.Example`, 544 `Example2MultiFile() one1.Example`, 545 } 546 for _, str := range strs { 547 if !strings.Contains(s, str) { 548 t.Errorf("expected but missing: \"%s\"", str) 549 } 550 } 551 } 552 553 func TestImportedPackageWithSameName(t *testing.T) { 554 m, err := New(Config{SrcDir: "testpackages/samenameimport"}) 555 if err != nil { 556 t.Fatalf("moq.New: %s", err) 557 } 558 var buf bytes.Buffer 559 err = m.Mock(&buf, "Example") 560 if err != nil { 561 t.Errorf("mock error: %s", err) 562 } 563 s := buf.String() 564 if !strings.Contains(s, `a samename.A`) { 565 t.Error("missing samename.A to address the struct A from the external package samename") 566 } 567 } 568 569 // normalize normalizes \r\n (windows) and \r (mac) 570 // into \n (unix) 571 func normalize(d []byte) []byte { 572 // Source: https://www.programming-books.io/essential/go/normalize-newlines-1d3abcf6f17c4186bb9617fa14074e48 573 // replace CR LF \r\n (windows) with LF \n (unix) 574 d = bytes.Replace(d, []byte{13, 10}, []byte{10}, -1) 575 // replace CF \r (mac) with LF \n (unix) 576 d = bytes.Replace(d, []byte{13}, []byte{10}, -1) 577 return d 578 } 579 580 func TestParamShadowsImport(t *testing.T) { 581 m, err := New(Config{SrcDir: "testpackages/shadow", PkgName: "gen"}) 582 if err != nil { 583 t.Fatalf("moq.New: %s", err) 584 } 585 586 genDir := "./testpackages/shadow/gen" 587 err = os.MkdirAll(genDir, 0777) 588 if err != nil { 589 t.Fatalf("mkdir: %s", err) 590 } 591 defer os.Remove(genDir) 592 593 f, err := os.Create(filepath.Join(genDir, "shadowmock.go")) 594 if err != nil { 595 t.Fatalf("failed to create shadowmock: %s", err) 596 } 597 defer f.Close() 598 defer os.Remove(f.Name()) 599 600 err = m.Mock(f, "Shadower") 601 if err != nil { 602 t.Fatalf("mock error: %s", err) 603 } 604 605 helperExec(t, []string{"go", "vet", genDir}, "") 606 }