github.com/djui/moq@v0.3.3/pkg/moq/moq_test.go (about)

     1  package moq
     2  
     3  import (
     4  	"bytes"
     5  	"flag"
     6  	"fmt"
     7  	"io"
     8  	"io/ioutil"
     9  	"os"
    10  	"os/exec"
    11  	"path/filepath"
    12  	"strings"
    13  	"testing"
    14  
    15  	"github.com/pmezard/go-difflib/difflib"
    16  )
    17  
    18  var update = flag.Bool("update", false, "Update golden files.")
    19  
    20  func TestMoq(t *testing.T) {
    21  	m, err := New(Config{SrcDir: "testpackages/example"})
    22  	if err != nil {
    23  		t.Fatalf("moq.New: %s", err)
    24  	}
    25  	var buf bytes.Buffer
    26  	err = m.Mock(&buf, "PersonStore")
    27  	if err != nil {
    28  		t.Errorf("m.Mock: %s", err)
    29  	}
    30  	s := buf.String()
    31  	// assertions of things that should be mentioned
    32  	var strs = []string{
    33  		"package example",
    34  		"type PersonStoreMock struct",
    35  		"CreateFunc func(ctx context.Context, person *Person, confirm bool) error",
    36  		"GetFunc func(ctx context.Context, id string) (*Person, error)",
    37  		"func (mock *PersonStoreMock) Create(ctx context.Context, person *Person, confirm bool) error",
    38  		"func (mock *PersonStoreMock) Get(ctx context.Context, id string) (*Person, error)",
    39  		"panic(\"PersonStoreMock.CreateFunc: method is nil but PersonStore.Create was just called\")",
    40  		"panic(\"PersonStoreMock.GetFunc: method is nil but PersonStore.Get was just called\")",
    41  		"mock.lockGet.Lock()",
    42  		"mock.calls.Get = append(mock.calls.Get, callInfo)",
    43  		"mock.lockGet.Unlock()",
    44  		"// ID is the id argument value",
    45  	}
    46  	for _, str := range strs {
    47  		if !strings.Contains(s, str) {
    48  			t.Errorf("expected but missing: \"%s\"", str)
    49  		}
    50  	}
    51  }
    52  
    53  func TestMoqWithStaticCheck(t *testing.T) {
    54  	m, err := New(Config{SrcDir: "testpackages/example"})
    55  	if err != nil {
    56  		t.Fatalf("moq.New: %s", err)
    57  	}
    58  	var buf bytes.Buffer
    59  	err = m.Mock(&buf, "PersonStore")
    60  	if err != nil {
    61  		t.Errorf("m.Mock: %s", err)
    62  	}
    63  	s := buf.String()
    64  	// assertions of things that should be mentioned
    65  	var strs = []string{
    66  		"package example",
    67  		"var _ PersonStore = &PersonStoreMock{}",
    68  		"type PersonStoreMock struct",
    69  		"CreateFunc func(ctx context.Context, person *Person, confirm bool) error",
    70  		"GetFunc func(ctx context.Context, id string) (*Person, error)",
    71  		"func (mock *PersonStoreMock) Create(ctx context.Context, person *Person, confirm bool) error",
    72  		"func (mock *PersonStoreMock) Get(ctx context.Context, id string) (*Person, error)",
    73  		"panic(\"PersonStoreMock.CreateFunc: method is nil but PersonStore.Create was just called\")",
    74  		"panic(\"PersonStoreMock.GetFunc: method is nil but PersonStore.Get was just called\")",
    75  		"mock.lockGet.Lock()",
    76  		"mock.calls.Get = append(mock.calls.Get, callInfo)",
    77  		"mock.lockGet.Unlock()",
    78  		"// ID is the id argument value",
    79  	}
    80  	for _, str := range strs {
    81  		if !strings.Contains(s, str) {
    82  			t.Errorf("expected but missing: \"%s\"", str)
    83  		}
    84  	}
    85  }
    86  
    87  func TestMoqWithAlias(t *testing.T) {
    88  	m, err := New(Config{SrcDir: "testpackages/example"})
    89  	if err != nil {
    90  		t.Fatalf("moq.New: %s", err)
    91  	}
    92  	var buf bytes.Buffer
    93  	err = m.Mock(&buf, "PersonStore:AnotherPersonStoreMock")
    94  	if err != nil {
    95  		t.Errorf("m.Mock: %s", err)
    96  	}
    97  	s := buf.String()
    98  	// assertions of things that should be mentioned
    99  	var strs = []string{
   100  		"package example",
   101  		"type AnotherPersonStoreMock struct",
   102  		"CreateFunc func(ctx context.Context, person *Person, confirm bool) error",
   103  		"GetFunc func(ctx context.Context, id string) (*Person, error)",
   104  		"func (mock *AnotherPersonStoreMock) Create(ctx context.Context, person *Person, confirm bool) error",
   105  		"func (mock *AnotherPersonStoreMock) Get(ctx context.Context, id string) (*Person, error)",
   106  		"panic(\"AnotherPersonStoreMock.CreateFunc: method is nil but PersonStore.Create was just called\")",
   107  		"panic(\"AnotherPersonStoreMock.GetFunc: method is nil but PersonStore.Get was just called\")",
   108  		"mock.lockGet.Lock()",
   109  		"mock.calls.Get = append(mock.calls.Get, callInfo)",
   110  		"mock.lockGet.Unlock()",
   111  		"// ID is the id argument value",
   112  	}
   113  	for _, str := range strs {
   114  		if !strings.Contains(s, str) {
   115  			t.Errorf("expected but missing: \"%s\"", str)
   116  		}
   117  	}
   118  }
   119  
   120  func TestMoqExplicitPackage(t *testing.T) {
   121  	m, err := New(Config{SrcDir: "testpackages/example", PkgName: "different"})
   122  	if err != nil {
   123  		t.Fatalf("moq.New: %s", err)
   124  	}
   125  	var buf bytes.Buffer
   126  	err = m.Mock(&buf, "PersonStore")
   127  	if err != nil {
   128  		t.Errorf("m.Mock: %s", err)
   129  	}
   130  	s := buf.String()
   131  	// assertions of things that should be mentioned
   132  	var strs = []string{
   133  		"package different",
   134  		"type PersonStoreMock struct",
   135  		"CreateFunc func(ctx context.Context, person *example.Person, confirm bool) error",
   136  		"GetFunc func(ctx context.Context, id string) (*example.Person, error)",
   137  		"func (mock *PersonStoreMock) Create(ctx context.Context, person *example.Person, confirm bool) error",
   138  		"func (mock *PersonStoreMock) Get(ctx context.Context, id string) (*example.Person, error)",
   139  	}
   140  	for _, str := range strs {
   141  		if !strings.Contains(s, str) {
   142  			t.Errorf("expected but missing: \"%s\"", str)
   143  		}
   144  	}
   145  }
   146  
   147  func TestMoqExplicitPackageWithStaticCheck(t *testing.T) {
   148  	m, err := New(Config{SrcDir: "testpackages/example", PkgName: "different"})
   149  	if err != nil {
   150  		t.Fatalf("moq.New: %s", err)
   151  	}
   152  	var buf bytes.Buffer
   153  	err = m.Mock(&buf, "PersonStore")
   154  	if err != nil {
   155  		t.Errorf("m.Mock: %s", err)
   156  	}
   157  	s := buf.String()
   158  	// assertions of things that should be mentioned
   159  	var strs = []string{
   160  		"package different",
   161  		"var _ example.PersonStore = &PersonStoreMock{}",
   162  		"type PersonStoreMock struct",
   163  		"CreateFunc func(ctx context.Context, person *example.Person, confirm bool) error",
   164  		"GetFunc func(ctx context.Context, id string) (*example.Person, error)",
   165  		"func (mock *PersonStoreMock) Create(ctx context.Context, person *example.Person, confirm bool) error",
   166  		"func (mock *PersonStoreMock) Get(ctx context.Context, id string) (*example.Person, error)",
   167  	}
   168  	for _, str := range strs {
   169  		if !strings.Contains(s, str) {
   170  			t.Errorf("expected but missing: \"%s\"", str)
   171  		}
   172  	}
   173  }
   174  
   175  func TestMoqSkipEnsure(t *testing.T) {
   176  	m, err := New(Config{SrcDir: "testpackages/example", PkgName: "different", SkipEnsure: true})
   177  	if err != nil {
   178  		t.Fatalf("moq.New: %s", err)
   179  	}
   180  	var buf bytes.Buffer
   181  	err = m.Mock(&buf, "PersonStore")
   182  	if err != nil {
   183  		t.Errorf("m.Mock: %s", err)
   184  	}
   185  	s := buf.String()
   186  	// assertions of things that should be mentioned
   187  	var strs = []string{
   188  		"package different",
   189  		"type PersonStoreMock struct",
   190  		"CreateFunc func(ctx context.Context, person *example.Person, confirm bool) error",
   191  		"GetFunc func(ctx context.Context, id string) (*example.Person, error)",
   192  		"func (mock *PersonStoreMock) Create(ctx context.Context, person *example.Person, confirm bool) error",
   193  		"func (mock *PersonStoreMock) Get(ctx context.Context, id string) (*example.Person, error)",
   194  	}
   195  	for _, str := range strs {
   196  		if !strings.Contains(s, str) {
   197  			t.Errorf("expected but missing: \"%s\"", str)
   198  		}
   199  	}
   200  }
   201  
   202  func TestNotCreatingEmptyDirWhenPkgIsGiven(t *testing.T) {
   203  	m, err := New(Config{SrcDir: "testpackages/example", PkgName: "different"})
   204  	if err != nil {
   205  		t.Fatalf("moq.New: %s", err)
   206  	}
   207  	var buf bytes.Buffer
   208  	err = m.Mock(&buf, "PersonStore")
   209  	if err != nil {
   210  		t.Errorf("m.Mock: %s", err)
   211  	}
   212  	s := buf.String()
   213  	if len(s) == 0 {
   214  		t.Fatalf("mock should be generated")
   215  	}
   216  	if _, err := os.Stat("testpackages/example/different"); !os.IsNotExist(err) {
   217  		t.Fatalf("no empty dir should be created by moq")
   218  	}
   219  }
   220  
   221  // TestVariadicArguments tests to ensure variadic work as
   222  // expected.
   223  // see https://github.com/matryer/moq/issues/5
   224  func TestVariadicArguments(t *testing.T) {
   225  	m, err := New(Config{SrcDir: "testpackages/variadic"})
   226  	if err != nil {
   227  		t.Fatalf("moq.New: %s", err)
   228  	}
   229  	var buf bytes.Buffer
   230  	err = m.Mock(&buf, "Greeter")
   231  	if err != nil {
   232  		t.Errorf("m.Mock: %s", err)
   233  	}
   234  	s := buf.String()
   235  	// assertions of things that should be mentioned
   236  	var strs = []string{
   237  		"package variadic",
   238  		"type GreeterMock struct",
   239  		"GreetFunc func(ctx context.Context, names ...string) string",
   240  		"return mock.GreetFunc(ctx, names...)",
   241  	}
   242  	for _, str := range strs {
   243  		if !strings.Contains(s, str) {
   244  			t.Errorf("expected but missing: \"%s\"", str)
   245  		}
   246  	}
   247  }
   248  
   249  func TestNothingToReturn(t *testing.T) {
   250  	m, err := New(Config{SrcDir: "testpackages/example"})
   251  	if err != nil {
   252  		t.Fatalf("moq.New: %s", err)
   253  	}
   254  	var buf bytes.Buffer
   255  	err = m.Mock(&buf, "PersonStore")
   256  	if err != nil {
   257  		t.Errorf("m.Mock: %s", err)
   258  	}
   259  	s := buf.String()
   260  	if strings.Contains(s, `return mock.ClearCacheFunc(id)`) {
   261  		t.Errorf("should not have return for items that have no return arguments")
   262  	}
   263  	// assertions of things that should be mentioned
   264  	var strs = []string{
   265  		"mock.ClearCacheFunc(id)",
   266  	}
   267  	for _, str := range strs {
   268  		if !strings.Contains(s, str) {
   269  			t.Errorf("expected but missing: \"%s\"", str)
   270  		}
   271  	}
   272  }
   273  
   274  func TestImports(t *testing.T) {
   275  	m, err := New(Config{SrcDir: "testpackages/imports/two"})
   276  	if err != nil {
   277  		t.Fatalf("moq.New: %s", err)
   278  	}
   279  	var buf bytes.Buffer
   280  	err = m.Mock(&buf, "DoSomething")
   281  	if err != nil {
   282  		t.Errorf("m.Mock: %s", err)
   283  	}
   284  	s := buf.String()
   285  	var strs = []string{
   286  		`	"sync"`,
   287  		`	"github.com/matryer/moq/pkg/moq/testpackages/imports/one"`,
   288  	}
   289  	for _, str := range strs {
   290  		if !strings.Contains(s, str) {
   291  			t.Errorf("expected but missing: \"%s\"", str)
   292  		}
   293  		if len(strings.Split(s, str)) > 2 {
   294  			t.Errorf("more than one: \"%s\"", str)
   295  		}
   296  	}
   297  }
   298  
   299  func TestMockGolden(t *testing.T) {
   300  	cases := []struct {
   301  		name       string
   302  		cfg        Config
   303  		interfaces []string
   304  		goldenFile string
   305  	}{
   306  		{
   307  			// Tests to ensure slice return data type works as expected.
   308  			// See https://github.com/matryer/moq/issues/124
   309  			name:       "SliceResult",
   310  			cfg:        Config{SrcDir: "testpackages/variadic"},
   311  			interfaces: []string{"Echoer"},
   312  			goldenFile: filepath.Join("testpackages/variadic", "echoer.golden.go"),
   313  		},
   314  		{
   315  			// Tests generation of mock where a method on the interface uses a
   316  			// blank identifier.
   317  			// See https://github.com/matryer/moq/issues/70
   318  			name:       "BlankID",
   319  			cfg:        Config{SrcDir: "testpackages/blankid"},
   320  			interfaces: []string{"Swallower"},
   321  			goldenFile: filepath.Join("testpackages/blankid", "swallower.golden.go"),
   322  		},
   323  		{
   324  			name:       "ChannelNames",
   325  			cfg:        Config{SrcDir: "testpackages/channels", StubImpl: true},
   326  			interfaces: []string{"Queuer"},
   327  			goldenFile: filepath.Join("testpackages/channels", "queuer_moq.golden.go"),
   328  		},
   329  		{
   330  			// Tests generation of mock when the interface imports a different
   331  			// package by the same name as it's own.
   332  			// See https://github.com/matryer/moq/issues/94
   333  			name:       "PkgShadow",
   334  			cfg:        Config{SrcDir: "testpackages/shadow/http", PkgName: "mock"},
   335  			interfaces: []string{"Thing"},
   336  			goldenFile: filepath.Join("testpackages/shadow/mock", "thing_moq.golden.go"),
   337  		},
   338  		{
   339  			// Tests generation of mock when a method parameter shadows an
   340  			// imported package name.
   341  			name:       "ParamShadow",
   342  			cfg:        Config{SrcDir: "testpackages/shadow"},
   343  			interfaces: []string{"Shadower"},
   344  			goldenFile: filepath.Join("testpackages/shadow", "shadower_moq.golden.go"),
   345  		},
   346  		{
   347  			name:       "ImportAlias",
   348  			cfg:        Config{SrcDir: "testpackages/importalias"},
   349  			interfaces: []string{"MiddleMan"},
   350  			goldenFile: filepath.Join("testpackages/importalias", "middleman_moq.golden.go"),
   351  		},
   352  		{
   353  			// Tests conflict resolution for generated names of method
   354  			// parameters.
   355  			name:       "ParamNameConflict",
   356  			cfg:        Config{SrcDir: "testpackages/paramconflict"},
   357  			interfaces: []string{"Interface"},
   358  			goldenFile: filepath.Join("testpackages/paramconflict", "iface_moq.golden.go"),
   359  		},
   360  		{
   361  			// Tests generation of names for unnamed method parameters.
   362  			name:       "GenerateParamNames",
   363  			cfg:        Config{SrcDir: "testpackages/genparamname"},
   364  			interfaces: []string{"Interface"},
   365  			goldenFile: filepath.Join("testpackages/genparamname", "iface_moq.golden.go"),
   366  		},
   367  		{
   368  			name:       "SyncImport",
   369  			cfg:        Config{SrcDir: "testpackages/syncimport"},
   370  			interfaces: []string{"Syncer"},
   371  			goldenFile: filepath.Join("testpackages/syncimport", "syncer_moq.golden.go"),
   372  		},
   373  		{
   374  			// Tests anonymous imports are not included in the generated mock.
   375  			name:       "AnonymousImport",
   376  			cfg:        Config{SrcDir: "testpackages/anonimport"},
   377  			interfaces: []string{"Example"},
   378  			goldenFile: filepath.Join("testpackages/anonimport", "iface_moq.golden.go"),
   379  		},
   380  		{
   381  			name:       "ShadowTypes",
   382  			cfg:        Config{SrcDir: "testpackages/shadowtypes"},
   383  			interfaces: []string{"ShadowTypes"},
   384  			goldenFile: filepath.Join("testpackages/shadowtypes", "shadowtypes_moq.golden.go"),
   385  		},
   386  		{
   387  			name:       "Generics",
   388  			cfg:        Config{SrcDir: "testpackages/generics"},
   389  			interfaces: []string{"GenericStore1", "GenericStore2", "AliasStore"},
   390  			goldenFile: filepath.Join("testpackages/generics", "generics_moq.golden.go"),
   391  		},
   392  	}
   393  	for _, tc := range cases {
   394  		t.Run(tc.name, func(t *testing.T) {
   395  			m, err := New(tc.cfg)
   396  			if err != nil {
   397  				t.Fatalf("moq.New: %s", err)
   398  			}
   399  
   400  			var buf bytes.Buffer
   401  			if err = m.Mock(&buf, tc.interfaces...); err != nil {
   402  				t.Errorf("m.Mock: %s", err)
   403  				return
   404  			}
   405  
   406  			if err := matchGoldenFile(tc.goldenFile, buf.Bytes()); err != nil {
   407  				t.Errorf("check golden file: %s", err)
   408  			}
   409  		})
   410  	}
   411  }
   412  
   413  func TestFormatter(t *testing.T) {
   414  	cases := []struct {
   415  		name string
   416  		conf Config
   417  	}{
   418  		{name: "gofmt", conf: Config{SrcDir: "testpackages/imports/two"}},
   419  		{name: "goimports", conf: Config{SrcDir: "testpackages/imports/two", Formatter: "goimports"}},
   420  		{name: "noop", conf: Config{SrcDir: "testpackages/imports/two", Formatter: "noop"}},
   421  	}
   422  	for _, tc := range cases {
   423  		t.Run(tc.name, func(t *testing.T) {
   424  			m, err := New(tc.conf)
   425  			if err != nil {
   426  				t.Fatalf("moq.New: %s", err)
   427  			}
   428  			var buf bytes.Buffer
   429  			err = m.Mock(&buf, "DoSomething:"+tc.name+"Mock")
   430  			if err != nil {
   431  				t.Errorf("m.Mock: %s", err)
   432  			}
   433  
   434  			golden := filepath.Join("testpackages/imports/two", tc.name+".golden.go")
   435  			if err := matchGoldenFile(golden, buf.Bytes()); err != nil {
   436  				t.Errorf("check golden file: %s", err)
   437  			}
   438  		})
   439  	}
   440  }
   441  
   442  func matchGoldenFile(goldenFile string, actual []byte) error {
   443  	// To update golden files, run the following:
   444  	// go test -v -run '^<Test-Name>$' github.com/matryer/moq/pkg/moq -update
   445  	if *update {
   446  		if err := os.MkdirAll(filepath.Dir(goldenFile), 0750); err != nil {
   447  			return fmt.Errorf("create dir: %s", err)
   448  		}
   449  		if err := ioutil.WriteFile(goldenFile, actual, 0600); err != nil {
   450  			return fmt.Errorf("write: %s", err)
   451  		}
   452  
   453  		return nil
   454  	}
   455  
   456  	expected, err := ioutil.ReadFile(goldenFile)
   457  	if err != nil {
   458  		return fmt.Errorf("read: %s: %s", goldenFile, err)
   459  	}
   460  
   461  	// Normalise newlines
   462  	actual, expected = normalize(actual), normalize(expected)
   463  	if !bytes.Equal(expected, actual) {
   464  		diff, err := difflib.GetUnifiedDiffString(difflib.UnifiedDiff{
   465  			A:        difflib.SplitLines(string(expected)),
   466  			B:        difflib.SplitLines(string(actual)),
   467  			FromFile: "Expected",
   468  			ToFile:   "Actual",
   469  			Context:  1,
   470  		})
   471  		if err != nil {
   472  			return fmt.Errorf("diff: %s", err)
   473  		}
   474  		return fmt.Errorf("match: %s:\n%s", goldenFile, diff)
   475  	}
   476  
   477  	return nil
   478  }
   479  
   480  func TestVendoredPackages(t *testing.T) {
   481  	m, err := New(Config{SrcDir: "testpackages/vendoring/user"})
   482  	if err != nil {
   483  		t.Fatalf("moq.New: %s", err)
   484  	}
   485  	var buf bytes.Buffer
   486  	err = m.Mock(&buf, "Service")
   487  	if err != nil {
   488  		t.Errorf("mock error: %s", err)
   489  	}
   490  	s := buf.String()
   491  	// assertions of things that should be mentioned
   492  	var strs = []string{
   493  		`"github.com/sudo-suhas/moq-test-pkgs/somerepo"`,
   494  	}
   495  	for _, str := range strs {
   496  		if !strings.Contains(s, str) {
   497  			t.Errorf("expected but missing: \"%s\"", str)
   498  		}
   499  	}
   500  }
   501  
   502  func TestVendoredInterface(t *testing.T) {
   503  	m, err := New(Config{
   504  		SrcDir:  "testpackages/vendoring/vendor/github.com/sudo-suhas/moq-test-pkgs/somerepo",
   505  		PkgName: "someother",
   506  	})
   507  	if err != nil {
   508  		t.Fatalf("moq.New: %s", err)
   509  	}
   510  	var buf bytes.Buffer
   511  	err = m.Mock(&buf, "SomeService")
   512  	if err != nil {
   513  		t.Errorf("mock error: %s", err)
   514  	}
   515  	s := buf.String()
   516  	// assertions of things that should be mentioned
   517  	var strs = []string{
   518  		`"github.com/sudo-suhas/moq-test-pkgs/somerepo"`,
   519  	}
   520  	for _, str := range strs {
   521  		if !strings.Contains(s, str) {
   522  			t.Errorf("expected but missing: \"%s\"", str)
   523  		}
   524  	}
   525  	incorrectImport := `"github.com/matryer/moq/pkg/moq/testpackages/vendoring/vendor/github.com/sudo-suhas/moq-test-pkgs/somerepo"`
   526  	if strings.Contains(s, incorrectImport) {
   527  		t.Errorf("unexpected import: %s", incorrectImport)
   528  	}
   529  }
   530  
   531  func TestVendoredBuildConstraints(t *testing.T) {
   532  	m, err := New(Config{SrcDir: "testpackages/buildconstraints/user"})
   533  	if err != nil {
   534  		t.Fatalf("moq.New: %s", err)
   535  	}
   536  	var buf bytes.Buffer
   537  	err = m.Mock(&buf, "Service")
   538  	if err != nil {
   539  		t.Errorf("mock error: %s", err)
   540  	}
   541  	s := buf.String()
   542  	// assertions of things that should be mentioned
   543  	var strs = []string{
   544  		`"github.com/sudo-suhas/moq-test-pkgs/buildconstraints"`,
   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  // TestDotImports tests for https://github.com/matryer/moq/issues/21.
   554  func TestDotImports(t *testing.T) {
   555  	preDir, err := os.Getwd()
   556  	if err != nil {
   557  		t.Errorf("Getwd: %s", err)
   558  	}
   559  	err = os.Chdir("testpackages/dotimport")
   560  	if err != nil {
   561  		t.Errorf("Chdir: %s", err)
   562  	}
   563  	defer func() {
   564  		err := os.Chdir(preDir)
   565  		if err != nil {
   566  			t.Errorf("Chdir back: %s", err)
   567  		}
   568  	}()
   569  	m, err := New(Config{SrcDir: ".", PkgName: "moqtest_test"})
   570  	if err != nil {
   571  		t.Fatalf("moq.New: %s", err)
   572  	}
   573  	var buf bytes.Buffer
   574  	err = m.Mock(&buf, "Service")
   575  	if err != nil {
   576  		t.Errorf("mock error: %s", err)
   577  	}
   578  	s := buf.String()
   579  	if strings.Contains(s, `"."`) {
   580  		t.Error("contains invalid dot import")
   581  	}
   582  }
   583  
   584  func TestEmptyInterface(t *testing.T) {
   585  	m, err := New(Config{SrcDir: "testpackages/emptyinterface"})
   586  	if err != nil {
   587  		t.Fatalf("moq.New: %s", err)
   588  	}
   589  	var buf bytes.Buffer
   590  	err = m.Mock(&buf, "Empty")
   591  	if err != nil {
   592  		t.Errorf("mock error: %s", err)
   593  	}
   594  	s := buf.String()
   595  	if strings.Contains(s, `"sync"`) {
   596  		t.Error("contains sync import, although this package isn't used")
   597  	}
   598  }
   599  
   600  func TestGoGenerateVendoredPackages(t *testing.T) {
   601  	cmd := exec.Command("go", "generate", "./...")
   602  	cmd.Dir = "testpackages/gogenvendoring"
   603  	stdout, err := cmd.StdoutPipe()
   604  	if err != nil {
   605  		t.Errorf("StdoutPipe: %s", err)
   606  	}
   607  	defer stdout.Close()
   608  	err = cmd.Start()
   609  	if err != nil {
   610  		t.Errorf("Start: %s", err)
   611  	}
   612  	buf := bytes.NewBuffer(nil)
   613  	io.Copy(buf, stdout)
   614  	err = cmd.Wait()
   615  	if err != nil {
   616  		if exitErr, ok := err.(*exec.ExitError); ok {
   617  			t.Errorf("Wait: %s %s", exitErr, string(exitErr.Stderr))
   618  		} else {
   619  			t.Errorf("Wait: %s", err)
   620  		}
   621  	}
   622  	s := buf.String()
   623  	if strings.Contains(s, `vendor/`) {
   624  		t.Error("contains vendor directory in import path")
   625  	}
   626  }
   627  
   628  func TestImportedPackageWithSameName(t *testing.T) {
   629  	m, err := New(Config{SrcDir: "testpackages/samenameimport"})
   630  	if err != nil {
   631  		t.Fatalf("moq.New: %s", err)
   632  	}
   633  	var buf bytes.Buffer
   634  	err = m.Mock(&buf, "Example")
   635  	if err != nil {
   636  		t.Errorf("mock error: %s", err)
   637  	}
   638  	s := buf.String()
   639  	if !strings.Contains(s, `a samename.A`) {
   640  		t.Error("missing samename.A to address the struct A from the external package samename")
   641  	}
   642  }
   643  
   644  func TestParseError(t *testing.T) {
   645  	_, err := New(Config{SrcDir: "testpackages/_parseerror/service"})
   646  	if err == nil {
   647  		t.Errorf("expected error but got nil")
   648  		return
   649  	}
   650  	if !strings.Contains(err.Error(), `could not import github.com/matryer/notexist (invalid package name: "")`) {
   651  		t.Errorf("unexpected error: %s", err.Error())
   652  	}
   653  }
   654  
   655  func TestMockError(t *testing.T) {
   656  	m, err := New(Config{SrcDir: "testpackages/example"})
   657  	if err != nil {
   658  		t.Fatalf("moq.New: %s", err)
   659  	}
   660  	cases := []struct {
   661  		name     string
   662  		namePair string
   663  		wantErr  string
   664  	}{
   665  		{
   666  			name:     "TypeNotFound",
   667  			namePair: "DoesNotExist",
   668  			wantErr:  "interface not found: DoesNotExist",
   669  		},
   670  		{
   671  			name:     "UnexpectedType",
   672  			namePair: "Person",
   673  			wantErr:  "Person (github.com/matryer/moq/pkg/moq/testpackages/example.Person) is not an interface",
   674  		},
   675  	}
   676  	for _, tc := range cases {
   677  		t.Run(tc.name, func(t *testing.T) {
   678  			err := m.Mock(ioutil.Discard, tc.namePair)
   679  			if err == nil {
   680  				t.Errorf("expected error but got nil")
   681  				return
   682  			}
   683  			if !strings.Contains(err.Error(), tc.wantErr) {
   684  				t.Errorf("unexpected error: %s", err.Error())
   685  			}
   686  		})
   687  	}
   688  }
   689  
   690  // normalize normalizes \r\n (windows) and \r (mac)
   691  // into \n (unix)
   692  func normalize(d []byte) []byte {
   693  	// Source: https://www.programming-books.io/essential/go/normalize-newlines-1d3abcf6f17c4186bb9617fa14074e48
   694  	// replace CR LF \r\n (windows) with LF \n (unix)
   695  	d = bytes.Replace(d, []byte{13, 10}, []byte{10}, -1)
   696  	// replace CF \r (mac) with LF \n (unix)
   697  	d = bytes.Replace(d, []byte{13}, []byte{10}, -1)
   698  	return d
   699  }