github.com/6543-forks/go-swagger@v0.26.0/generator/shared_test.go (about)

     1  package generator
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"log"
     7  	"os"
     8  	"path"
     9  	"path/filepath"
    10  	"runtime"
    11  	"testing"
    12  
    13  	"github.com/go-openapi/loads"
    14  	"github.com/stretchr/testify/assert"
    15  	"github.com/stretchr/testify/require"
    16  )
    17  
    18  const (
    19  	defaultAPIPackage    = "operations"
    20  	defaultClientPackage = "client"
    21  	defaultModelPackage  = "models"
    22  	defaultServerPackage = "restapi"
    23  )
    24  
    25  // Perform common initialization of template repository before running tests.
    26  // This allows to run tests unitarily (e.g. go test -run xxx ).
    27  func TestMain(m *testing.M) {
    28  	// initializations to run tests in this package
    29  	log.SetFlags(log.LstdFlags | log.Lshortfile)
    30  	templates.LoadDefaults()
    31  	initSchemaValidationTest()
    32  	os.Exit(m.Run())
    33  }
    34  
    35  func opts() *GenOpts {
    36  	var opts GenOpts
    37  	opts.IncludeValidator = true
    38  	opts.IncludeModel = true
    39  	if err := opts.EnsureDefaults(); err != nil {
    40  		panic(err)
    41  	}
    42  	return &opts
    43  }
    44  
    45  func testGenOpts() *GenOpts {
    46  	g := &GenOpts{}
    47  	g.Target = "."
    48  	g.APIPackage = defaultAPIPackage
    49  	g.ModelPackage = defaultModelPackage
    50  	g.ServerPackage = defaultServerPackage
    51  	g.ClientPackage = defaultClientPackage
    52  	g.Principal = ""
    53  	g.DefaultScheme = "http"
    54  	g.IncludeModel = true
    55  	g.IncludeValidator = true
    56  	g.IncludeModel = true
    57  	g.IncludeHandler = true
    58  	g.IncludeParameters = true
    59  	g.IncludeResponses = true
    60  	g.IncludeMain = false
    61  	g.IncludeSupport = true
    62  	g.ExcludeSpec = true
    63  	g.TemplateDir = ""
    64  	g.DumpData = false
    65  
    66  	if err := g.EnsureDefaults(); err != nil {
    67  		panic(err)
    68  	}
    69  	return g
    70  }
    71  
    72  // TODO: there is a catch, since these methods are sensitive
    73  // to the CWD of the current swagger command (or go
    74  // generate when working on resulting template)
    75  // NOTE:
    76  // Errors in CheckOpts are hard to simulate since
    77  // they occur only on os.Getwd() errors
    78  // Windows style path is difficult to test on unix
    79  // since the filepath pkg is platform dependent
    80  func TestShared_CheckOpts(t *testing.T) {
    81  	testPath := filepath.Join("a", "b", "b")
    82  
    83  	log.SetOutput(ioutil.Discard)
    84  	defer log.SetOutput(os.Stdout)
    85  
    86  	var opts = new(GenOpts)
    87  	_ = opts.EnsureDefaults()
    88  	cwd, _ := os.Getwd()
    89  	opts.Spec = "../fixtures/codegen/simplesearch.yml"
    90  
    91  	opts.Target = filepath.Join(".", "a", "b", "c")
    92  	opts.ServerPackage = filepath.Join(cwd, "a", "b", "c")
    93  	err := opts.CheckOpts()
    94  	assert.Error(t, err)
    95  
    96  	opts.Target = filepath.Join(cwd, "a", "b", "c")
    97  	opts.ServerPackage = testPath
    98  	opts.Spec = filepath.Join(cwd, "nowhere", "swagger.yaml")
    99  	err = opts.CheckOpts()
   100  	assert.Error(t, err)
   101  
   102  	opts.Target = filepath.Join(cwd, "a", "b", "c")
   103  	opts.ServerPackage = testPath
   104  	opts.Spec = "https://ab/c"
   105  	err = opts.CheckOpts()
   106  	assert.NoError(t, err)
   107  
   108  	opts.Target = filepath.Join(cwd, "a", "b", "c")
   109  	opts.ServerPackage = testPath
   110  	opts.Spec = "http://ab/c"
   111  	err = opts.CheckOpts()
   112  	assert.NoError(t, err)
   113  
   114  	opts.Target = filepath.Join("a", "b", "c")
   115  	opts.ServerPackage = testPath
   116  	opts.Spec = filepath.Join(cwd, "..", "fixtures", "codegen", "swagger-codegen-tests.json")
   117  	err = opts.CheckOpts()
   118  	assert.NoError(t, err)
   119  
   120  	opts.Target = filepath.Join("a", "b", "c")
   121  	opts.ServerPackage = testPath
   122  	opts.Spec = filepath.Join("..", "fixtures", "codegen", "swagger-codegen-tests.json")
   123  	err = opts.CheckOpts()
   124  	assert.NoError(t, err)
   125  
   126  	opts = nil
   127  	err = opts.CheckOpts()
   128  	assert.Error(t, err)
   129  }
   130  
   131  func TestShared_EnsureDefaults(t *testing.T) {
   132  	opts := &GenOpts{}
   133  	_ = opts.EnsureDefaults()
   134  	assert.True(t, opts.defaultsEnsured)
   135  	opts.DefaultConsumes = "https"
   136  	_ = opts.EnsureDefaults()
   137  	assert.Equal(t, "https", opts.DefaultConsumes)
   138  }
   139  
   140  // TargetPath and SpecPath are used in server.gotmpl
   141  // as template variables: {{ .TestTargetPath }} and
   142  // {{ .SpecPath }}, to construct the go generate
   143  // directive.
   144  func TestShared_TargetPath(t *testing.T) {
   145  	log.SetOutput(ioutil.Discard)
   146  	defer log.SetOutput(os.Stdout)
   147  
   148  	cwd, _ := os.Getwd()
   149  
   150  	// relative target
   151  	var opts = new(GenOpts)
   152  	_ = opts.EnsureDefaults()
   153  	opts.Target = filepath.Join(".", "a", "b", "c")
   154  	opts.ServerPackage = "y"
   155  	expected := filepath.Join("..", "..", "c")
   156  	result := opts.TargetPath()
   157  	assert.Equal(t, expected, result)
   158  
   159  	// relative target, server path
   160  	opts = new(GenOpts)
   161  	_ = opts.EnsureDefaults()
   162  	opts.Target = filepath.Join(".", "a", "b", "c")
   163  	opts.ServerPackage = "y/z"
   164  	expected = filepath.Join("..", "..", "..", "c")
   165  	result = opts.TargetPath()
   166  	assert.Equal(t, expected, result)
   167  
   168  	// absolute target
   169  	opts = new(GenOpts)
   170  	_ = opts.EnsureDefaults()
   171  	opts.Target = filepath.Join(cwd, "a", "b", "c")
   172  	opts.ServerPackage = "y"
   173  	expected = filepath.Join("..", "..", "c")
   174  	result = opts.TargetPath()
   175  	assert.Equal(t, expected, result)
   176  
   177  	// absolute target, server path
   178  	opts = new(GenOpts)
   179  	_ = opts.EnsureDefaults()
   180  	opts.Target = filepath.Join(cwd, "a", "b", "c")
   181  	opts.ServerPackage = path.Join("y", "z")
   182  	expected = filepath.Join("..", "..", "..", "c")
   183  	result = opts.TargetPath()
   184  	assert.Equal(t, expected, result)
   185  }
   186  
   187  // NOTE: file://url is not supported
   188  func TestShared_SpecPath(t *testing.T) {
   189  	log.SetOutput(ioutil.Discard)
   190  	defer log.SetOutput(os.Stdout)
   191  
   192  	cwd, _ := os.Getwd()
   193  
   194  	// http URL spec
   195  	var opts = new(GenOpts)
   196  	_ = opts.EnsureDefaults()
   197  	opts.Spec = "http://a/b/c"
   198  	opts.ServerPackage = "y"
   199  	expected := opts.Spec
   200  	result := opts.SpecPath()
   201  	assert.Equal(t, expected, result)
   202  
   203  	// https URL spec
   204  	opts = new(GenOpts)
   205  	_ = opts.EnsureDefaults()
   206  	opts.Spec = "https://a/b/c"
   207  	opts.ServerPackage = "y"
   208  	expected = opts.Spec
   209  	result = opts.SpecPath()
   210  	assert.Equal(t, expected, result)
   211  
   212  	// relative spec
   213  	opts = new(GenOpts)
   214  	_ = opts.EnsureDefaults()
   215  	opts.Spec = filepath.Join(".", "a", "b", "c")
   216  	opts.Target = filepath.Join("d")
   217  	opts.ServerPackage = "y"
   218  	expected = filepath.Join("..", "..", "a", "b", "c")
   219  	result = opts.SpecPath()
   220  	assert.Equal(t, expected, result)
   221  
   222  	// relative spec, server path
   223  	opts = new(GenOpts)
   224  	_ = opts.EnsureDefaults()
   225  	opts.Spec = filepath.Join(".", "a", "b", "c")
   226  	opts.Target = filepath.Join("d", "e")
   227  	opts.ServerPackage = "y/z"
   228  	expected = filepath.Join("..", "..", "..", "..", "a", "b", "c")
   229  	result = opts.SpecPath()
   230  	assert.Equal(t, expected, result)
   231  
   232  	// relative spec, server path
   233  	opts = new(GenOpts)
   234  	_ = opts.EnsureDefaults()
   235  	opts.Spec = filepath.Join(".", "a", "b", "c")
   236  	opts.Target = filepath.Join(".", "a", "b")
   237  	opts.ServerPackage = "y/z"
   238  	expected = filepath.Join("..", "..", "c")
   239  	result = opts.SpecPath()
   240  	assert.Equal(t, expected, result)
   241  
   242  	// absolute spec
   243  	opts = new(GenOpts)
   244  	_ = opts.EnsureDefaults()
   245  	opts.Spec = filepath.Join(cwd, "a", "b", "c")
   246  	opts.ServerPackage = "y"
   247  	expected = filepath.Join("..", "a", "b", "c")
   248  	result = opts.SpecPath()
   249  	assert.Equal(t, expected, result)
   250  
   251  	// absolute spec, server path
   252  	opts = new(GenOpts)
   253  	_ = opts.EnsureDefaults()
   254  	opts.Spec = filepath.Join("..", "a", "b", "c")
   255  	opts.Target = ""
   256  	opts.ServerPackage = path.Join("y", "z")
   257  	expected = filepath.Join("..", "..", "..", "a", "b", "c")
   258  	result = opts.SpecPath()
   259  	assert.Equal(t, expected, result)
   260  
   261  	if runtime.GOOS == "windows" {
   262  		opts = new(GenOpts)
   263  		_ = opts.EnsureDefaults()
   264  		opts.Spec = filepath.Join("a", "b", "c")
   265  		opts.Target = filepath.Join("Z:", "e", "f", "f")
   266  		opts.ServerPackage = "y/z"
   267  		expected, _ = filepath.Abs(opts.Spec)
   268  		result = opts.SpecPath()
   269  		assert.Equal(t, expected, result)
   270  	}
   271  }
   272  
   273  // Low level testing: templates not found (higher level calls raise panic(), see above)
   274  func TestShared_NotFoundTemplate(t *testing.T) {
   275  	log.SetOutput(ioutil.Discard)
   276  	defer log.SetOutput(os.Stdout)
   277  
   278  	opts := GenOpts{}
   279  	tplOpts := TemplateOpts{
   280  		Name:       "NotFound",
   281  		Source:     "asset:notfound",
   282  		Target:     ".",
   283  		FileName:   "test_notfound.go",
   284  		SkipExists: false,
   285  		SkipFormat: false,
   286  	}
   287  
   288  	buf, err := opts.render(&tplOpts, nil)
   289  	assert.Error(t, err, "Error should be handled here")
   290  	assert.Nil(t, buf, "Upon error, GenOpts.render() should return nil buffer")
   291  }
   292  
   293  // Low level testing: invalid template => Get() returns not found (higher level calls raise panic(), see above)
   294  // TODO: better error discrimination between absent definition and non-parsing template
   295  func TestShared_GarbledTemplate(t *testing.T) {
   296  	log.SetOutput(ioutil.Discard)
   297  	defer log.SetOutput(os.Stdout)
   298  
   299  	garbled := "func x {{;;; garbled"
   300  
   301  	_ = templates.AddFile("garbled", garbled)
   302  	opts := GenOpts{}
   303  	tplOpts := TemplateOpts{
   304  		Name:       "Garbled",
   305  		Source:     "asset:garbled",
   306  		Target:     ".",
   307  		FileName:   "test_garbled.go",
   308  		SkipExists: false,
   309  		SkipFormat: false,
   310  	}
   311  
   312  	buf, err := opts.render(&tplOpts, nil)
   313  	assert.Error(t, err, "Error should be handled here")
   314  	assert.Nil(t, buf, "Upon error, GenOpts.render() should return nil buffer")
   315  }
   316  
   317  // Template execution failure
   318  type myTemplateData struct {
   319  }
   320  
   321  func (*myTemplateData) MyFaultyMethod() (string, error) {
   322  	return "", fmt.Errorf("myFaultyError")
   323  }
   324  
   325  func TestShared_ExecTemplate(t *testing.T) {
   326  	log.SetOutput(ioutil.Discard)
   327  	defer log.SetOutput(os.Stdout)
   328  
   329  	// Not a failure: no value data
   330  	execfailure1 := "func x {{ .NotInData }}"
   331  
   332  	_ = templates.AddFile("execfailure1", execfailure1)
   333  	opts := new(GenOpts)
   334  	tplOpts := TemplateOpts{
   335  		Name:       "execFailure1",
   336  		Source:     "asset:execfailure1",
   337  		Target:     ".",
   338  		FileName:   "test_execfailure1.go",
   339  		SkipExists: false,
   340  		SkipFormat: false,
   341  	}
   342  
   343  	buf1, err := opts.render(&tplOpts, nil)
   344  	assert.NoError(t, err, "Template rendering should put <no value> instead of missing data, and report no error")
   345  	assert.Equal(t, string(buf1), "func x <no value>")
   346  
   347  	execfailure2 := "func {{ .MyFaultyMethod }}"
   348  
   349  	_ = templates.AddFile("execfailure2", execfailure2)
   350  	opts = new(GenOpts)
   351  	tplOpts2 := TemplateOpts{
   352  		Name:       "execFailure2",
   353  		Source:     "asset:execfailure2",
   354  		Target:     ".",
   355  		FileName:   "test_execfailure2.go",
   356  		SkipExists: false,
   357  		SkipFormat: false,
   358  	}
   359  
   360  	data := new(myTemplateData)
   361  	buf2, err := opts.render(&tplOpts2, data)
   362  	assert.Error(t, err, "Error should be handled here: missing func in template yields an error")
   363  	assert.Contains(t, err.Error(), "template execution failed")
   364  	assert.Nil(t, buf2, "Upon error, GenOpts.render() should return nil buffer")
   365  }
   366  
   367  // Test correctly parsed templates, with bad formatting
   368  func TestShared_BadFormatTemplate(t *testing.T) {
   369  	log.SetOutput(ioutil.Discard)
   370  
   371  	defer func() {
   372  		_ = os.Remove("test_badformat.gol")
   373  		_ = os.Remove("test_badformat2.gol")
   374  		log.SetOutput(os.Stdout)
   375  		Debug = false
   376  	}()
   377  
   378  	// Not skipping format
   379  	badFormat := "func x {;;; garbled"
   380  
   381  	Debug = true
   382  	_ = templates.AddFile("badformat", badFormat)
   383  
   384  	opts := GenOpts{}
   385  	opts.LanguageOpts = GoLangOpts()
   386  	tplOpts := TemplateOpts{
   387  		Name:   "badformat",
   388  		Source: "asset:badformat",
   389  		Target: ".",
   390  		// Extension ".gol" won't mess with go if cleanup is not performed
   391  		FileName:   "test_badformat.gol",
   392  		SkipExists: false,
   393  		SkipFormat: false,
   394  	}
   395  
   396  	data := appGenerator{
   397  		Name:    "badtest",
   398  		Package: "wrongpkg",
   399  	}
   400  
   401  	err := opts.write(&tplOpts, data)
   402  
   403  	// The badly formatted file has been dumped for debugging purposes
   404  	_, exists := os.Stat(tplOpts.FileName)
   405  	assert.True(t, !os.IsNotExist(exists), "The template file has not been generated as expected")
   406  	_ = os.Remove(tplOpts.FileName)
   407  
   408  	assert.NotNil(t, err)
   409  	assert.Contains(t, err.Error(), "source formatting on generated source")
   410  
   411  	// Skipping format
   412  	opts = GenOpts{}
   413  	opts.LanguageOpts = GoLangOpts()
   414  	tplOpts2 := TemplateOpts{
   415  		Name:       "badformat2",
   416  		Source:     "asset:badformat",
   417  		Target:     ".",
   418  		FileName:   "test_badformat2.gol",
   419  		SkipExists: false,
   420  		SkipFormat: true,
   421  	}
   422  
   423  	err2 := opts.write(&tplOpts2, data)
   424  
   425  	// The unformatted file has been dumped without format checks
   426  	_, exists2 := os.Stat(tplOpts2.FileName)
   427  	assert.True(t, !os.IsNotExist(exists2), "The template file has not been generated as expected")
   428  	_ = os.Remove(tplOpts2.FileName)
   429  
   430  	assert.Nil(t, err2)
   431  
   432  	// os.RemoveAll(filepath.Join(filepath.FromSlash(dr),"restapi"))
   433  }
   434  
   435  // Test dir creation
   436  func TestShared_DirectoryTemplate(t *testing.T) {
   437  	log.SetOutput(ioutil.Discard)
   438  
   439  	defer func() {
   440  		_ = os.RemoveAll("TestGenDir")
   441  		log.SetOutput(os.Stdout)
   442  	}()
   443  
   444  	// Not skipping format
   445  	content := "func x {}"
   446  
   447  	_ = templates.AddFile("gendir", content)
   448  
   449  	opts := GenOpts{}
   450  	opts.LanguageOpts = GoLangOpts()
   451  	tplOpts := TemplateOpts{
   452  		Name:   "gendir",
   453  		Source: "asset:gendir",
   454  		Target: "TestGenDir",
   455  		// Extension ".gol" won't mess with go if cleanup is not performed
   456  		FileName:   "test_gendir.gol",
   457  		SkipExists: false,
   458  		SkipFormat: true,
   459  	}
   460  
   461  	data := appGenerator{
   462  		Name:    "gentest",
   463  		Package: "stubpkg",
   464  	}
   465  
   466  	err := opts.write(&tplOpts, data)
   467  
   468  	// The badly formatted file has been dumped for debugging purposes
   469  	_, exists := os.Stat(filepath.Join(tplOpts.Target, tplOpts.FileName))
   470  	assert.True(t, !os.IsNotExist(exists), "The template file has not been generated as expected")
   471  	_ = os.RemoveAll(tplOpts.Target)
   472  
   473  	assert.Nil(t, err)
   474  }
   475  
   476  // Test templates which are not assets (open in file)
   477  // Low level testing: templates loaded from file
   478  func TestShared_LoadTemplate(t *testing.T) {
   479  	log.SetOutput(ioutil.Discard)
   480  	defer log.SetOutput(os.Stdout)
   481  
   482  	opts := GenOpts{}
   483  	tplOpts := TemplateOpts{
   484  		Name:       "File",
   485  		Source:     "File",
   486  		Target:     ".",
   487  		FileName:   "file.go",
   488  		SkipExists: false,
   489  		SkipFormat: false,
   490  	}
   491  
   492  	buf, err := opts.render(&tplOpts, nil)
   493  	assert.Error(t, err, "Error should be handled here")
   494  	assert.Contains(t, err.Error(), "open File")
   495  	assert.Contains(t, err.Error(), "error while opening")
   496  	assert.Nil(t, buf, "Upon error, GenOpts.render() should return nil buffer")
   497  
   498  	opts.TemplateDir = filepath.Join(".", "myTemplateDir")
   499  	buf, err = opts.render(&tplOpts, nil)
   500  	assert.Error(t, err, "Error should be handled here")
   501  	assert.Contains(t, err.Error(), "open "+filepath.Join("myTemplateDir", "File"))
   502  	assert.Contains(t, err.Error(), "error while opening")
   503  	assert.Nil(t, buf, "Upon error, GenOpts.render() should return nil buffer")
   504  
   505  }
   506  
   507  func TestShared_AppNameOrDefault(t *testing.T) {
   508  	specPath := filepath.Join("..", "fixtures", "codegen", "shipyard.yml")
   509  	specDoc, err := loads.Spec(specPath)
   510  	require.NoError(t, err)
   511  	require.NotNil(t, specDoc.Spec().Info)
   512  	specDoc.Spec().Info.Title = "    "
   513  	assert.Equal(t, "Xyz", appNameOrDefault(specDoc, "  ", "xyz"))
   514  	specDoc.Spec().Info.Title = "test"
   515  	assert.Equal(t, "Xyz", appNameOrDefault(specDoc, "  ", "xyz"))
   516  }
   517  
   518  func TestShared_GatherModel(t *testing.T) {
   519  	specPath := filepath.Join("..", "fixtures", "codegen", "shipyard.yml")
   520  
   521  	specDoc, err := loads.Spec(specPath)
   522  	require.NoError(t, err)
   523  
   524  	_, err = gatherModels(specDoc, []string{"unknown"})
   525  	assert.Error(t, err)
   526  
   527  	res, err := gatherModels(specDoc, []string{"Image", "Application"})
   528  	require.NoError(t, err)
   529  	assert.Len(t, res, 2)
   530  
   531  	res, err = gatherModels(specDoc, []string{"Image", "Application"})
   532  	require.NoError(t, err)
   533  	assert.Len(t, res, 2)
   534  
   535  	res, err = gatherModels(specDoc, []string{})
   536  	require.NoError(t, err)
   537  	assert.Len(t, res, 4)
   538  }
   539  
   540  func TestShared_DumpWrongData(t *testing.T) {
   541  	assert.Error(t, dumpData(struct {
   542  		A func() string
   543  		B string
   544  	}{
   545  		A: func() string { return "" },
   546  		B: "xyz",
   547  	}))
   548  
   549  	assert.NoError(t, dumpData(struct {
   550  		A func() string `json:"-"`
   551  		B string
   552  	}{
   553  		A: func() string { return "" },
   554  		B: "xyz",
   555  	}))
   556  
   557  	assert.NoError(t, dumpData(struct {
   558  		a func() string
   559  		B string
   560  	}{
   561  		a: func() string { return "" },
   562  		B: "xyz",
   563  	}))
   564  }
   565  
   566  func TestResolvePrincipal(t *testing.T) {
   567  	for _, toPin := range []struct {
   568  		Title     string
   569  		Principal string
   570  		Expected  []string
   571  	}{
   572  		{
   573  			Title: "defaults", Principal: "",
   574  			Expected: []string{"", "interface{}", ""},
   575  		},
   576  		{
   577  			Title: "with base import", Principal: "auth.Principal",
   578  			Expected: []string{"auth", "auth.Principal", "auth"},
   579  		},
   580  		{
   581  			Title: "with full import", Principal: "github.com/myproject/auth.Principal",
   582  			Expected: []string{"auth", "auth.Principal", "github.com/myproject/auth"},
   583  		},
   584  		{
   585  			Title: "with name conflict", Principal: "github.com/myproject/middleware.Principal",
   586  			Expected: []string{"auth", "auth.Principal", "github.com/myproject/middleware"},
   587  		},
   588  		{
   589  			Title: "with name conflict (2)", Principal: "github.com/myproject/principal.Principal",
   590  			Expected: []string{"auth", "auth.Principal", "github.com/myproject/principal"},
   591  		},
   592  	} {
   593  		fixture := toPin
   594  		t.Run(fixture.Title, func(t *testing.T) {
   595  			t.Parallel()
   596  			opts := &GenOpts{Principal: fixture.Principal}
   597  			err := opts.EnsureDefaults()
   598  			require.NoError(t, err)
   599  			alias, principal, target := opts.resolvePrincipal()
   600  			require.Equal(t, fixture.Expected[0], alias)
   601  			require.Equal(t, fixture.Expected[1], principal)
   602  			require.Equal(t, fixture.Expected[2], target)
   603  		})
   604  	}
   605  }
   606  
   607  func TestDefaultImports(t *testing.T) {
   608  	for i, toPin := range []struct {
   609  		Title    string
   610  		Opts     *GenOpts
   611  		Expected map[string]string
   612  	}{
   613  		{
   614  			Title: "defaults",
   615  			Opts:  &GenOpts{},
   616  			Expected: map[string]string{
   617  				"models": "github.com/go-swagger/go-swagger/generator/models",
   618  			},
   619  		},
   620  		{
   621  			Title: "with base import",
   622  			Opts: &GenOpts{
   623  				Principal: "ext.Principal",
   624  			},
   625  			Expected: map[string]string{
   626  				"ext":    "github.com/go-swagger/go-swagger/generator/ext",
   627  				"models": "github.com/go-swagger/go-swagger/generator/models",
   628  			},
   629  		},
   630  		{
   631  			Title: "with full import",
   632  			Opts: &GenOpts{
   633  				Principal: "github.com/myproject/identity.Principal",
   634  			},
   635  			Expected: map[string]string{
   636  				"identity": "github.com/myproject/identity",
   637  				"models":   "github.com/go-swagger/go-swagger/generator/models",
   638  			},
   639  		},
   640  		{
   641  			Title: "with name conflict",
   642  			Opts: &GenOpts{
   643  				Principal: "github.com/myproject/middleware.Principal",
   644  			},
   645  			Expected: map[string]string{
   646  				"auth":   "github.com/myproject/middleware",
   647  				"models": "github.com/go-swagger/go-swagger/generator/models",
   648  			},
   649  		},
   650  		{
   651  			Title: "with name conflict (2)",
   652  			Opts: &GenOpts{
   653  				Principal: "github.com/myproject/principal.Principal",
   654  			},
   655  			Expected: map[string]string{
   656  				"auth":   "github.com/myproject/principal",
   657  				"models": "github.com/go-swagger/go-swagger/generator/models",
   658  			},
   659  		},
   660  		{
   661  			Title: "alternate target for models",
   662  			Opts: &GenOpts{
   663  				ModelPackage: "target/bespoke",
   664  			},
   665  			Expected: map[string]string{
   666  				"bespoke": "github.com/go-swagger/go-swagger/generator/target/bespoke",
   667  			},
   668  		},
   669  		{
   670  			Title: "with existing models",
   671  			Opts: &GenOpts{
   672  				ExistingModels: "github.com/myproject/target/bespoke",
   673  			},
   674  			Expected: map[string]string{
   675  				"models": "github.com/myproject/target/bespoke",
   676  			},
   677  		},
   678  	} {
   679  		fixture := toPin
   680  		t.Run(fixture.Title, func(t *testing.T) {
   681  			t.Parallel()
   682  			err := fixture.Opts.EnsureDefaults()
   683  			require.NoError(t, err)
   684  			imports := fixture.Opts.defaultImports()
   685  			require.EqualValuesf(t, fixture.Expected, imports, "unexpected imports generated with fixture %q[%d]", fixture.Title, i)
   686  		})
   687  	}
   688  }