github.com/go-swagger/go-swagger@v0.31.0/generator/shared_test.go (about)

     1  package generator
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"os"
     7  	"path"
     8  	"path/filepath"
     9  	"runtime"
    10  	"testing"
    11  
    12  	"github.com/go-openapi/analysis"
    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  	defer discardOutput()()
    82  	testPath := filepath.Join("a", "b", "b")
    83  
    84  	opts := new(GenOpts)
    85  	_ = opts.EnsureDefaults()
    86  	cwd, _ := os.Getwd()
    87  	opts.Spec = "../fixtures/codegen/simplesearch.yml"
    88  
    89  	opts.Target = filepath.Join(".", "a", "b", "c")
    90  	opts.ServerPackage = filepath.Join(cwd, "a", "b", "c")
    91  	err := opts.CheckOpts()
    92  	require.Error(t, err)
    93  
    94  	opts.Target = filepath.Join(cwd, "a", "b", "c")
    95  	opts.ServerPackage = testPath
    96  	opts.Spec = filepath.Join(cwd, "nowhere", "swagger.yaml")
    97  	err = opts.CheckOpts()
    98  	require.Error(t, err)
    99  
   100  	opts.Target = filepath.Join(cwd, "a", "b", "c")
   101  	opts.ServerPackage = testPath
   102  	opts.Spec = "https://ab/c"
   103  	err = opts.CheckOpts()
   104  	require.NoError(t, err)
   105  
   106  	opts.Target = filepath.Join(cwd, "a", "b", "c")
   107  	opts.ServerPackage = testPath
   108  	opts.Spec = "http://ab/c"
   109  	err = opts.CheckOpts()
   110  	require.NoError(t, err)
   111  
   112  	opts.Target = filepath.Join("a", "b", "c")
   113  	opts.ServerPackage = testPath
   114  	opts.Spec = filepath.Join(cwd, "..", "fixtures", "codegen", "swagger-codegen-tests.json")
   115  	err = opts.CheckOpts()
   116  	require.NoError(t, err)
   117  
   118  	opts.Target = filepath.Join("a", "b", "c")
   119  	opts.ServerPackage = testPath
   120  	opts.Spec = filepath.Join("..", "fixtures", "codegen", "swagger-codegen-tests.json")
   121  	err = opts.CheckOpts()
   122  	require.NoError(t, err)
   123  
   124  	opts = nil
   125  	err = opts.CheckOpts()
   126  	require.Error(t, err)
   127  }
   128  
   129  func TestShared_EnsureDefaults(t *testing.T) {
   130  	opts := &GenOpts{}
   131  	require.NoError(t, opts.EnsureDefaults())
   132  	assert.True(t, opts.defaultsEnsured)
   133  	opts.DefaultConsumes = "https"
   134  	_ = opts.EnsureDefaults()
   135  	assert.Equal(t, "https", opts.DefaultConsumes)
   136  }
   137  
   138  // TargetPath and SpecPath are used in server.gotmpl
   139  // as template variables: {{ .TestTargetPath }} and
   140  // {{ .SpecPath }}, to construct the go generate
   141  // directive.
   142  func TestShared_TargetPath(t *testing.T) {
   143  	defer discardOutput()()
   144  
   145  	cwd, _ := os.Getwd()
   146  
   147  	// relative target
   148  	opts := new(GenOpts)
   149  	_ = opts.EnsureDefaults()
   150  	opts.Target = filepath.Join(".", "a", "b", "c")
   151  	opts.ServerPackage = "y"
   152  	expected := filepath.Join("..", "..", "c")
   153  	result := opts.TargetPath()
   154  	assert.Equal(t, expected, result)
   155  
   156  	// relative target, server path
   157  	opts = new(GenOpts)
   158  	_ = opts.EnsureDefaults()
   159  	opts.Target = filepath.Join(".", "a", "b", "c")
   160  	opts.ServerPackage = "y/z"
   161  	expected = filepath.Join("..", "..", "..", "c")
   162  	result = opts.TargetPath()
   163  	assert.Equal(t, expected, result)
   164  
   165  	// absolute target
   166  	opts = new(GenOpts)
   167  	_ = opts.EnsureDefaults()
   168  	opts.Target = filepath.Join(cwd, "a", "b", "c")
   169  	opts.ServerPackage = "y"
   170  	expected = filepath.Join("..", "..", "c")
   171  	result = opts.TargetPath()
   172  	assert.Equal(t, expected, result)
   173  
   174  	// absolute target, server path
   175  	opts = new(GenOpts)
   176  	_ = opts.EnsureDefaults()
   177  	opts.Target = filepath.Join(cwd, "a", "b", "c")
   178  	opts.ServerPackage = path.Join("y", "z")
   179  	expected = filepath.Join("..", "..", "..", "c")
   180  	result = opts.TargetPath()
   181  	assert.Equal(t, expected, result)
   182  }
   183  
   184  // NOTE: file://url is not supported
   185  func TestShared_SpecPath(t *testing.T) {
   186  	defer discardOutput()()
   187  
   188  	cwd, _ := os.Getwd()
   189  
   190  	// http URL spec
   191  	opts := new(GenOpts)
   192  	_ = opts.EnsureDefaults()
   193  	opts.Spec = "http://a/b/c"
   194  	opts.ServerPackage = "y"
   195  	expected := opts.Spec
   196  	result := opts.SpecPath()
   197  	assert.Equal(t, expected, result)
   198  
   199  	// https URL spec
   200  	opts = new(GenOpts)
   201  	_ = opts.EnsureDefaults()
   202  	opts.Spec = "https://a/b/c"
   203  	opts.ServerPackage = "y"
   204  	expected = opts.Spec
   205  	result = opts.SpecPath()
   206  	assert.Equal(t, expected, result)
   207  
   208  	// relative spec
   209  	opts = new(GenOpts)
   210  	_ = opts.EnsureDefaults()
   211  	opts.Spec = filepath.Join(".", "a", "b", "c")
   212  	opts.Target = "d"
   213  	opts.ServerPackage = "y"
   214  	expected = filepath.Join("..", "..", "a", "b", "c")
   215  	result = opts.SpecPath()
   216  	assert.Equal(t, expected, result)
   217  
   218  	// relative spec, server path
   219  	opts = new(GenOpts)
   220  	_ = opts.EnsureDefaults()
   221  	opts.Spec = filepath.Join(".", "a", "b", "c")
   222  	opts.Target = filepath.Join("d", "e")
   223  	opts.ServerPackage = "y/z"
   224  	expected = filepath.Join("..", "..", "..", "..", "a", "b", "c")
   225  	result = opts.SpecPath()
   226  	assert.Equal(t, expected, result)
   227  
   228  	// relative spec, server path
   229  	opts = new(GenOpts)
   230  	_ = opts.EnsureDefaults()
   231  	opts.Spec = filepath.Join(".", "a", "b", "c")
   232  	opts.Target = filepath.Join(".", "a", "b")
   233  	opts.ServerPackage = "y/z"
   234  	expected = filepath.Join("..", "..", "c")
   235  	result = opts.SpecPath()
   236  	assert.Equal(t, expected, result)
   237  
   238  	// absolute spec
   239  	opts = new(GenOpts)
   240  	_ = opts.EnsureDefaults()
   241  	opts.Spec = filepath.Join(cwd, "a", "b", "c")
   242  	opts.ServerPackage = "y"
   243  	expected = filepath.Join("..", "a", "b", "c")
   244  	result = opts.SpecPath()
   245  	assert.Equal(t, expected, result)
   246  
   247  	// absolute spec, server path
   248  	opts = new(GenOpts)
   249  	_ = opts.EnsureDefaults()
   250  	opts.Spec = filepath.Join("..", "a", "b", "c")
   251  	opts.Target = ""
   252  	opts.ServerPackage = path.Join("y", "z")
   253  	expected = filepath.Join("..", "..", "..", "a", "b", "c")
   254  	result = opts.SpecPath()
   255  	assert.Equal(t, expected, result)
   256  
   257  	if runtime.GOOS == "windows" {
   258  		opts = new(GenOpts)
   259  		_ = opts.EnsureDefaults()
   260  		opts.Spec = filepath.Join("a", "b", "c")
   261  		opts.Target = filepath.Join("Z:", "e", "f", "f")
   262  		opts.ServerPackage = "y/z"
   263  		expected, _ = filepath.Abs(opts.Spec)
   264  		result = opts.SpecPath()
   265  		assert.Equal(t, expected, result)
   266  	}
   267  }
   268  
   269  // Low level testing: templates not found (higher level calls raise panic(), see above)
   270  func TestShared_NotFoundTemplate(t *testing.T) {
   271  	defer discardOutput()()
   272  
   273  	opts := testGenOpts()
   274  	tplOpts := TemplateOpts{
   275  		Name:       "NotFound",
   276  		Source:     "asset:notfound",
   277  		Target:     ".",
   278  		FileName:   "test_notfound.go",
   279  		SkipExists: false,
   280  		SkipFormat: false,
   281  	}
   282  
   283  	buf, err := opts.render(&tplOpts, nil)
   284  	require.Errorf(t, err, "Error should be handled here")
   285  	assert.Nilf(t, buf, "Upon error, GenOpts.render() should return nil buffer")
   286  }
   287  
   288  // Low level testing: invalid template => Get() returns not found (higher level calls raise panic(), see above)
   289  // TODO: better error discrimination between absent definition and non-parsing template
   290  func TestShared_GarbledTemplate(t *testing.T) {
   291  	defer discardOutput()()
   292  
   293  	garbled := "func x {{;;; garbled"
   294  
   295  	_ = templates.AddFile("garbled", garbled)
   296  	opts := testGenOpts()
   297  
   298  	tplOpts := TemplateOpts{
   299  		Name:       "Garbled",
   300  		Source:     "asset:garbled",
   301  		Target:     ".",
   302  		FileName:   "test_garbled.go",
   303  		SkipExists: false,
   304  		SkipFormat: false,
   305  	}
   306  
   307  	buf, err := opts.render(&tplOpts, nil)
   308  	require.Errorf(t, err, "Error should be handled here")
   309  	assert.Nilf(t, buf, "Upon error, GenOpts.render() should return nil buffer")
   310  }
   311  
   312  // Template execution failure
   313  type myTemplateData struct{}
   314  
   315  func (*myTemplateData) MyFaultyMethod() (string, error) {
   316  	return "", fmt.Errorf("myFaultyError")
   317  }
   318  
   319  func TestShared_ExecTemplate(t *testing.T) {
   320  	defer discardOutput()()
   321  
   322  	// Not a failure: no value data
   323  	execfailure1 := "func x {{ .NotInData }}"
   324  
   325  	_ = templates.AddFile("execfailure1", execfailure1)
   326  	opts := testGenOpts()
   327  
   328  	tplOpts := TemplateOpts{
   329  		Name:       "execFailure1",
   330  		Source:     "asset:execfailure1",
   331  		Target:     ".",
   332  		FileName:   "test_execfailure1.go",
   333  		SkipExists: false,
   334  		SkipFormat: false,
   335  	}
   336  
   337  	buf1, err := opts.render(&tplOpts, nil)
   338  	require.NoError(t, err, "Template rendering should put <no value> instead of missing data, and report no error")
   339  	assert.Equal(t, "func x <no value>", string(buf1))
   340  
   341  	execfailure2 := "func {{ .MyFaultyMethod }}"
   342  
   343  	_ = templates.AddFile("execfailure2", execfailure2)
   344  	opts = testGenOpts()
   345  	tplOpts2 := TemplateOpts{
   346  		Name:       "execFailure2",
   347  		Source:     "asset:execfailure2",
   348  		Target:     ".",
   349  		FileName:   "test_execfailure2.go",
   350  		SkipExists: false,
   351  		SkipFormat: false,
   352  	}
   353  
   354  	data := new(myTemplateData)
   355  	buf2, err := opts.render(&tplOpts2, data)
   356  	require.Error(t, err, "Error should be handled here: missing func in template yields an error")
   357  	assert.Contains(t, err.Error(), "template execution failed")
   358  	assert.Nil(t, buf2, "Upon error, GenOpts.render() should return nil buffer")
   359  }
   360  
   361  // Test correctly parsed templates, with bad formatting
   362  func TestShared_BadFormatTemplate(t *testing.T) {
   363  	// TODO: fred refact
   364  	defer discardOutput()()
   365  
   366  	t.Cleanup(func() {
   367  		_ = os.Remove("test_badformat.gol")
   368  		_ = os.Remove("test_badformat2.gol")
   369  		Debug = false
   370  	})
   371  
   372  	// Not skipping format
   373  	badFormat := "func x {;;; garbled"
   374  
   375  	Debug = true
   376  	_ = templates.AddFile("badformat", badFormat)
   377  
   378  	opts := testGenOpts()
   379  	opts.LanguageOpts = GoLangOpts()
   380  	tplOpts := TemplateOpts{
   381  		Name:   "badformat",
   382  		Source: "asset:badformat",
   383  		Target: ".",
   384  		// Extension ".gol" won't mess with go if cleanup is not performed
   385  		FileName:   "test_badformat.gol",
   386  		SkipExists: false,
   387  		SkipFormat: false,
   388  	}
   389  
   390  	data := appGenerator{
   391  		Name:    "badtest",
   392  		Package: "wrongpkg",
   393  	}
   394  
   395  	err := opts.write(&tplOpts, data)
   396  	defer func() {
   397  		_ = os.Remove(tplOpts.FileName)
   398  	}()
   399  
   400  	// The badly formatted file has been dumped for debugging purposes
   401  	_, exists := os.Stat(tplOpts.FileName)
   402  	assert.False(t, os.IsNotExist(exists), "The template file has not been generated as expected")
   403  
   404  	require.Error(t, err)
   405  	assert.Contains(t, err.Error(), "source formatting on generated source")
   406  
   407  	// Skipping format
   408  	opts = testGenOpts()
   409  	opts.LanguageOpts = GoLangOpts()
   410  	tplOpts2 := TemplateOpts{
   411  		Name:       "badformat2",
   412  		Source:     "asset:badformat",
   413  		Target:     ".",
   414  		FileName:   "test_badformat2.gol",
   415  		SkipExists: false,
   416  		SkipFormat: true,
   417  	}
   418  
   419  	err2 := opts.write(&tplOpts2, data)
   420  
   421  	// The unformatted file has been dumped without format checks
   422  	_, exists2 := os.Stat(tplOpts2.FileName)
   423  	assert.False(t, os.IsNotExist(exists2), "The template file has not been generated as expected")
   424  	_ = os.Remove(tplOpts2.FileName)
   425  
   426  	require.NoError(t, err2)
   427  
   428  	// os.RemoveAll(filepath.Join(filepath.FromSlash(dr),"restapi"))
   429  }
   430  
   431  // Test dir creation
   432  func TestShared_DirectoryTemplate(t *testing.T) {
   433  	defer discardOutput()()
   434  
   435  	t.Cleanup(func() {
   436  		_ = os.RemoveAll("TestGenDir")
   437  	})
   438  
   439  	// Not skipping format
   440  	content := "func x {}"
   441  
   442  	_ = templates.AddFile("gendir", content)
   443  
   444  	opts := testGenOpts()
   445  	opts.LanguageOpts = GoLangOpts()
   446  	tplOpts := TemplateOpts{
   447  		Name:   "gendir",
   448  		Source: "asset:gendir",
   449  		Target: "TestGenDir",
   450  		// Extension ".gol" won't mess with go if cleanup is not performed
   451  		FileName:   "test_gendir.gol",
   452  		SkipExists: false,
   453  		SkipFormat: true,
   454  	}
   455  
   456  	data := appGenerator{
   457  		Name:    "gentest",
   458  		Package: "stubpkg",
   459  	}
   460  
   461  	err := opts.write(&tplOpts, data)
   462  
   463  	// The badly formatted file has been dumped for debugging purposes
   464  	_, exists := os.Stat(filepath.Join(tplOpts.Target, tplOpts.FileName))
   465  	assert.False(t, os.IsNotExist(exists), "The template file has not been generated as expected")
   466  	_ = os.RemoveAll(tplOpts.Target)
   467  
   468  	require.NoError(t, err)
   469  }
   470  
   471  // Test templates which are not assets (open in file)
   472  // Low level testing: templates loaded from file
   473  func TestShared_LoadTemplate(t *testing.T) {
   474  	defer discardOutput()()
   475  
   476  	opts := testGenOpts()
   477  	tplOpts := TemplateOpts{
   478  		Name:       "File",
   479  		Source:     "File",
   480  		Target:     ".",
   481  		FileName:   "file.go",
   482  		SkipExists: false,
   483  		SkipFormat: false,
   484  	}
   485  
   486  	buf, err := opts.render(&tplOpts, nil)
   487  	require.Error(t, err, "Error should be handled here")
   488  	assert.Contains(t, err.Error(), "open File")
   489  	assert.Contains(t, err.Error(), "error while opening")
   490  	assert.Nil(t, buf, "Upon error, GenOpts.render() should return nil buffer")
   491  
   492  	opts.TemplateDir = filepath.Join(".", "myTemplateDir")
   493  	buf, err = opts.render(&tplOpts, nil)
   494  	require.Error(t, err, "Error should be handled here")
   495  	assert.Contains(t, err.Error(), "open "+filepath.Join("myTemplateDir", "File"))
   496  	assert.Contains(t, err.Error(), "error while opening")
   497  	assert.Nil(t, buf, "Upon error, GenOpts.render() should return nil buffer")
   498  }
   499  
   500  func TestShared_AppNameOrDefault(t *testing.T) {
   501  	specPath := filepath.Join("..", "fixtures", "codegen", "shipyard.yml")
   502  	specDoc, err := loads.Spec(specPath)
   503  	require.NoError(t, err)
   504  
   505  	require.NotNil(t, specDoc.Spec().Info)
   506  	specDoc.Spec().Info.Title = "    "
   507  	assert.Equal(t, "Xyz", appNameOrDefault(specDoc, "  ", "xyz"))
   508  	specDoc.Spec().Info.Title = "test"
   509  	assert.Equal(t, "Xyz", appNameOrDefault(specDoc, "  ", "xyz"))
   510  
   511  	opts := testGenOpts()
   512  	opts.Spec = specPath
   513  	_, err = opts.validateAndFlattenSpec()
   514  	require.NoError(t, err)
   515  
   516  	// more aggressive fixture on $refs, with validation errors, but flatten ok
   517  	specPath = filepath.Join("..", "fixtures", "bugs", "1429", "swagger.yaml")
   518  	specDoc, err = loads.Spec(specPath)
   519  	require.NoError(t, err)
   520  
   521  	opts.Spec = specPath
   522  	opts.FlattenOpts.BasePath = specDoc.SpecFilePath()
   523  	opts.FlattenOpts.Spec = analysis.New(specDoc.Spec())
   524  	opts.FlattenOpts.Minimal = true
   525  	err = analysis.Flatten(*opts.FlattenOpts)
   526  	require.NoError(t, err)
   527  
   528  	specDoc, _ = loads.Spec(specPath) // needs reload
   529  	opts.FlattenOpts.Spec = analysis.New(specDoc.Spec())
   530  	opts.FlattenOpts.Minimal = false
   531  	err = analysis.Flatten(*opts.FlattenOpts)
   532  	require.NoError(t, err)
   533  }
   534  
   535  func TestShared_GatherModel(t *testing.T) {
   536  	specPath := filepath.Join("..", "fixtures", "codegen", "shipyard.yml")
   537  
   538  	specDoc, err := loads.Spec(specPath)
   539  	require.NoError(t, err)
   540  
   541  	_, err = gatherModels(specDoc, []string{"unknown"})
   542  	require.Error(t, err)
   543  
   544  	res, err := gatherModels(specDoc, []string{"Image", "Application"})
   545  	require.NoError(t, err)
   546  	assert.Len(t, res, 2)
   547  
   548  	res, err = gatherModels(specDoc, []string{"Image", "Application"})
   549  	require.NoError(t, err)
   550  	assert.Len(t, res, 2)
   551  
   552  	res, err = gatherModels(specDoc, []string{})
   553  	require.NoError(t, err)
   554  	assert.Len(t, res, 4)
   555  }
   556  
   557  func TestShared_DumpWrongData(t *testing.T) {
   558  	defer discardOutput()()
   559  
   560  	t.Run("should not be able to dump things that don't marshal as JSON", func(t *testing.T) {
   561  		require.Error(t, dumpData(struct {
   562  			A func() string
   563  			B string
   564  		}{
   565  			A: func() string { return "" },
   566  			B: "xyz",
   567  		}))
   568  	})
   569  
   570  	t.Run("should dump any data, with unmarshallable fields exlicitly excluded", func(t *testing.T) {
   571  		require.NoError(t, dumpData(struct {
   572  			A func() string `json:"-"`
   573  			B string
   574  		}{
   575  			A: func() string { return "" },
   576  			B: "xyz",
   577  		}))
   578  
   579  		require.NoError(t, dumpData(struct {
   580  			a func() string
   581  			B string
   582  		}{
   583  			a: func() string { return "" },
   584  			B: "xyz",
   585  		}))
   586  	})
   587  }
   588  
   589  func TestResolvePrincipal(t *testing.T) {
   590  	for _, toPin := range []struct {
   591  		Title     string
   592  		Principal string
   593  		Expected  []string
   594  	}{
   595  		{
   596  			Title: "defaults", Principal: "",
   597  			Expected: []string{"", "interface{}", ""},
   598  		},
   599  		{
   600  			Title: "with base import", Principal: "auth.Principal",
   601  			Expected: []string{"auth", "auth.Principal", "auth"},
   602  		},
   603  		{
   604  			Title: "with full import", Principal: "github.com/myproject/auth.Principal",
   605  			Expected: []string{"auth", "auth.Principal", "github.com/myproject/auth"},
   606  		},
   607  		{
   608  			Title: "with name conflict", Principal: "github.com/myproject/middleware.Principal",
   609  			Expected: []string{"auth", "auth.Principal", "github.com/myproject/middleware"},
   610  		},
   611  		{
   612  			Title: "with name conflict (2)", Principal: "github.com/myproject/principal.Principal",
   613  			Expected: []string{"auth", "auth.Principal", "github.com/myproject/principal"},
   614  		},
   615  	} {
   616  		fixture := toPin
   617  		t.Run(fixture.Title, func(t *testing.T) {
   618  			t.Parallel()
   619  			opts := &GenOpts{GenOptsCommon: GenOptsCommon{Principal: fixture.Principal}}
   620  			err := opts.EnsureDefaults()
   621  			require.NoError(t, err)
   622  			alias, principal, target := opts.resolvePrincipal()
   623  			require.Equal(t, fixture.Expected[0], alias)
   624  			require.Equal(t, fixture.Expected[1], principal)
   625  			require.Equal(t, fixture.Expected[2], target)
   626  		})
   627  	}
   628  }
   629  
   630  func TestDefaultImports(t *testing.T) {
   631  	for i, toPin := range []struct {
   632  		Title    string
   633  		Opts     *GenOpts
   634  		Expected map[string]string
   635  	}{
   636  		{
   637  			Title: "defaults",
   638  			Opts:  &GenOpts{},
   639  			Expected: map[string]string{
   640  				"models": "github.com/go-swagger/go-swagger/generator/models",
   641  			},
   642  		},
   643  		{
   644  			Title: "with base import",
   645  			Opts: &GenOpts{
   646  				GenOptsCommon: GenOptsCommon{
   647  					Principal: "ext.Principal",
   648  				},
   649  			},
   650  			Expected: map[string]string{
   651  				"ext":    "github.com/go-swagger/go-swagger/generator/ext",
   652  				"models": "github.com/go-swagger/go-swagger/generator/models",
   653  			},
   654  		},
   655  		{
   656  			Title: "with full import",
   657  			Opts: &GenOpts{
   658  				GenOptsCommon: GenOptsCommon{
   659  					Principal: "github.com/myproject/identity.Principal",
   660  				},
   661  			},
   662  			Expected: map[string]string{
   663  				"identity": "github.com/myproject/identity",
   664  				"models":   "github.com/go-swagger/go-swagger/generator/models",
   665  			},
   666  		},
   667  		{
   668  			Title: "with name conflict",
   669  			Opts: &GenOpts{
   670  				GenOptsCommon: GenOptsCommon{
   671  					Principal: "github.com/myproject/middleware.Principal",
   672  				},
   673  			},
   674  			Expected: map[string]string{
   675  				"auth":   "github.com/myproject/middleware",
   676  				"models": "github.com/go-swagger/go-swagger/generator/models",
   677  			},
   678  		},
   679  		{
   680  			Title: "with name conflict (2)",
   681  			Opts: &GenOpts{
   682  				GenOptsCommon: GenOptsCommon{
   683  					Principal: "github.com/myproject/principal.Principal",
   684  				},
   685  			},
   686  			Expected: map[string]string{
   687  				"auth":   "github.com/myproject/principal",
   688  				"models": "github.com/go-swagger/go-swagger/generator/models",
   689  			},
   690  		},
   691  		{
   692  			Title: "alternate target for models",
   693  			Opts: &GenOpts{
   694  				GenOptsCommon: GenOptsCommon{
   695  					ModelPackage: "target/bespoke",
   696  				},
   697  			},
   698  			Expected: map[string]string{
   699  				"bespoke": "github.com/go-swagger/go-swagger/generator/target/bespoke",
   700  			},
   701  		},
   702  		{
   703  			Title: "with existing models",
   704  			Opts: &GenOpts{
   705  				GenOptsCommon: GenOptsCommon{
   706  					ExistingModels: "github.com/myproject/target/bespoke",
   707  				},
   708  			},
   709  			Expected: map[string]string{
   710  				"models": "github.com/myproject/target/bespoke",
   711  			},
   712  		},
   713  		// issue #2362
   714  		{
   715  			Title: "relative principal, in dedicated package under generated target",
   716  			Opts: &GenOpts{
   717  				GenOptsCommon: GenOptsCommon{
   718  					Principal:    "auth.Principal",
   719  					ModelPackage: "target/bespoke",
   720  				},
   721  			},
   722  			Expected: map[string]string{
   723  				"bespoke": "github.com/go-swagger/go-swagger/generator/target/bespoke",
   724  				"auth":    "github.com/go-swagger/go-swagger/generator/auth",
   725  			},
   726  		},
   727  		{
   728  			Title: "relative principal in models (1)",
   729  			Opts: &GenOpts{
   730  				GenOptsCommon: GenOptsCommon{
   731  					Principal:    "bespoke.Principal",
   732  					ModelPackage: "target/bespoke",
   733  				},
   734  			},
   735  			Expected: map[string]string{
   736  				"bespoke": "github.com/go-swagger/go-swagger/generator/target/bespoke",
   737  			},
   738  		},
   739  		{
   740  			Title: "relative principal in models (2)",
   741  			Opts: &GenOpts{
   742  				GenOptsCommon: GenOptsCommon{
   743  					Principal:    "target/bespoke.Principal",
   744  					ModelPackage: "target/bespoke",
   745  				},
   746  			},
   747  			Expected: map[string]string{
   748  				"bespoke": "github.com/go-swagger/go-swagger/generator/target/bespoke",
   749  			},
   750  		},
   751  		{
   752  			Title: "relative principal: not detected",
   753  			// NOTE: this case will probably not build: no way to determine the user intent
   754  			Opts: &GenOpts{
   755  				GenOptsCommon: GenOptsCommon{
   756  					Principal:    "target/auth.Principal",
   757  					ModelPackage: "target/models",
   758  				},
   759  			},
   760  			Expected: map[string]string{
   761  				"models": "github.com/go-swagger/go-swagger/generator/target/models",
   762  				"auth":   "target/auth",
   763  			},
   764  		},
   765  	} {
   766  		fixture := toPin
   767  		i := i
   768  		t.Run(fixture.Title, func(t *testing.T) {
   769  			t.Parallel()
   770  			err := fixture.Opts.EnsureDefaults()
   771  			require.NoError(t, err)
   772  			imports := fixture.Opts.defaultImports()
   773  			require.EqualValuesf(t, fixture.Expected, imports, "unexpected imports generated with fixture %q[%d]", fixture.Title, i)
   774  		})
   775  	}
   776  }
   777  
   778  func TestShared_Issue2113(t *testing.T) {
   779  	defer discardOutput()()
   780  
   781  	// acknowledge fix in go-openapi/spec
   782  	specPath := filepath.Join("..", "fixtures", "bugs", "2113", "base.yaml")
   783  	_, err := loads.Spec(specPath)
   784  	require.NoError(t, err)
   785  
   786  	opts := testGenOpts()
   787  	opts.Spec = specPath
   788  	opts.ValidateSpec = true
   789  	_, err = opts.validateAndFlattenSpec()
   790  	require.NoError(t, err)
   791  }
   792  
   793  func TestShared_Issue2743(t *testing.T) {
   794  	defer discardOutput()()
   795  
   796  	// acknowledge fix in go-openapi/spec
   797  	t.Run("should NOT flatten invalid spec that used to work", func(t *testing.T) {
   798  		specPath := filepath.Join("..", "fixtures", "bugs", "2743", "working", "spec.yaml")
   799  		_, err := loads.Spec(specPath)
   800  		require.NoError(t, err)
   801  
   802  		opts := testGenOpts()
   803  		opts.Spec = specPath
   804  		opts.ValidateSpec = true
   805  		_, err = opts.validateAndFlattenSpec()
   806  		require.Error(t, err)
   807  	})
   808  
   809  	t.Run("should flatten valid spec that used NOT to work", func(t *testing.T) {
   810  		specPath := filepath.Join("..", "fixtures", "bugs", "2743", "not-working", "spec.yaml")
   811  		_, err := loads.Spec(specPath)
   812  		require.NoError(t, err)
   813  
   814  		opts := testGenOpts()
   815  		opts.Spec = specPath
   816  		opts.ValidateSpec = true
   817  		_, err = opts.validateAndFlattenSpec()
   818  		require.NoError(t, err)
   819  	})
   820  }