github.com/anchorlabsinc/go-swagger@v0.19.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  	"strings"
    12  	"testing"
    13  
    14  	"github.com/go-openapi/analysis"
    15  	"github.com/go-openapi/loads"
    16  	"github.com/stretchr/testify/assert"
    17  )
    18  
    19  const testPath = "a/b/c"
    20  
    21  // TODO: there is a catch, since these methods are sensitive
    22  // to the CWD of the current swagger command (or go
    23  // generate when working on resulting template)
    24  // NOTE:
    25  // Errors in CheckOpts are hard to simulate since
    26  // they occur only on os.Getwd() errors
    27  // Windows style path is difficult to test on unix
    28  // since the filepath pkg is platform dependent
    29  func TestShared_CheckOpts(t *testing.T) {
    30  	log.SetOutput(ioutil.Discard)
    31  	defer log.SetOutput(os.Stdout)
    32  
    33  	var opts = new(GenOpts)
    34  	_ = opts.EnsureDefaults()
    35  	cwd, _ := os.Getwd()
    36  
    37  	opts.Target = filepath.Join(".", "a", "b", "c")
    38  	opts.ServerPackage = filepath.Join(cwd, "a", "b", "c")
    39  	err := opts.CheckOpts()
    40  	assert.Error(t, err)
    41  
    42  	opts.Target = filepath.Join(cwd, "a", "b", "c")
    43  	opts.ServerPackage = testPath
    44  	err = opts.CheckOpts()
    45  	assert.NoError(t, err)
    46  
    47  	opts.Target = filepath.Join(cwd, "a", "b", "c")
    48  	opts.ServerPackage = testPath
    49  	opts.Spec = "https:/ab/c"
    50  	err = opts.CheckOpts()
    51  	assert.NoError(t, err)
    52  
    53  	opts.Target = filepath.Join(cwd, "a", "b", "c")
    54  	opts.ServerPackage = testPath
    55  	opts.Spec = "http:/ab/c"
    56  	err = opts.CheckOpts()
    57  	assert.NoError(t, err)
    58  
    59  	opts.Target = filepath.Join("a", "b", "c")
    60  	opts.ServerPackage = testPath
    61  	opts.Spec = filepath.Join(cwd, "x")
    62  	err = opts.CheckOpts()
    63  	assert.NoError(t, err)
    64  }
    65  
    66  // TargetPath and SpecPath are used in server.gotmpl
    67  // as template variables: {{ .TestTargetPath }} and
    68  // {{ .SpecPath }}, to construct the go generate
    69  // directive.
    70  func TestShared_TargetPath(t *testing.T) {
    71  	log.SetOutput(ioutil.Discard)
    72  	defer log.SetOutput(os.Stdout)
    73  
    74  	cwd, _ := os.Getwd()
    75  
    76  	// relative target
    77  	var opts = new(GenOpts)
    78  	_ = opts.EnsureDefaults()
    79  	opts.Target = filepath.Join(".", "a", "b", "c")
    80  	opts.ServerPackage = "y"
    81  	expected := filepath.Join("..", "..", "c")
    82  	result := opts.TargetPath()
    83  	assert.Equal(t, expected, result)
    84  
    85  	// relative target, server path
    86  	opts = new(GenOpts)
    87  	_ = opts.EnsureDefaults()
    88  	opts.Target = filepath.Join(".", "a", "b", "c")
    89  	opts.ServerPackage = "y/z"
    90  	expected = filepath.Join("..", "..", "..", "c")
    91  	result = opts.TargetPath()
    92  	assert.Equal(t, expected, result)
    93  
    94  	// absolute target
    95  	opts = new(GenOpts)
    96  	_ = opts.EnsureDefaults()
    97  	opts.Target = filepath.Join(cwd, "a", "b", "c")
    98  	opts.ServerPackage = "y"
    99  	expected = filepath.Join("..", "..", "c")
   100  	result = opts.TargetPath()
   101  	assert.Equal(t, expected, result)
   102  
   103  	// absolute target, server path
   104  	opts = new(GenOpts)
   105  	_ = opts.EnsureDefaults()
   106  	opts.Target = filepath.Join(cwd, "a", "b", "c")
   107  	opts.ServerPackage = path.Join("y", "z")
   108  	expected = filepath.Join("..", "..", "..", "c")
   109  	result = opts.TargetPath()
   110  	assert.Equal(t, expected, result)
   111  }
   112  
   113  // NOTE: file://url is not supported
   114  func TestShared_SpecPath(t *testing.T) {
   115  	log.SetOutput(ioutil.Discard)
   116  	defer log.SetOutput(os.Stdout)
   117  
   118  	cwd, _ := os.Getwd()
   119  
   120  	// http URL spec
   121  	var opts = new(GenOpts)
   122  	_ = opts.EnsureDefaults()
   123  	opts.Spec = "http://a/b/c"
   124  	opts.ServerPackage = "y"
   125  	expected := opts.Spec
   126  	result := opts.SpecPath()
   127  	assert.Equal(t, expected, result)
   128  
   129  	// https URL spec
   130  	opts = new(GenOpts)
   131  	_ = opts.EnsureDefaults()
   132  	opts.Spec = "https://a/b/c"
   133  	opts.ServerPackage = "y"
   134  	expected = opts.Spec
   135  	result = opts.SpecPath()
   136  	assert.Equal(t, expected, result)
   137  
   138  	// relative spec
   139  	opts = new(GenOpts)
   140  	_ = opts.EnsureDefaults()
   141  	opts.Spec = filepath.Join(".", "a", "b", "c")
   142  	opts.Target = filepath.Join("d")
   143  	opts.ServerPackage = "y"
   144  	expected = filepath.Join("..", "..", "a", "b", "c")
   145  	result = opts.SpecPath()
   146  	assert.Equal(t, expected, result)
   147  
   148  	// relative spec, server path
   149  	opts = new(GenOpts)
   150  	_ = opts.EnsureDefaults()
   151  	opts.Spec = filepath.Join(".", "a", "b", "c")
   152  	opts.Target = filepath.Join("d", "e")
   153  	opts.ServerPackage = "y/z"
   154  	expected = filepath.Join("..", "..", "..", "..", "a", "b", "c")
   155  	result = opts.SpecPath()
   156  	assert.Equal(t, expected, result)
   157  
   158  	// relative spec, server path
   159  	opts = new(GenOpts)
   160  	_ = opts.EnsureDefaults()
   161  	opts.Spec = filepath.Join(".", "a", "b", "c")
   162  	opts.Target = filepath.Join(".", "a", "b")
   163  	opts.ServerPackage = "y/z"
   164  	expected = filepath.Join("..", "..", "c")
   165  	result = opts.SpecPath()
   166  	assert.Equal(t, expected, result)
   167  
   168  	// absolute spec
   169  	opts = new(GenOpts)
   170  	_ = opts.EnsureDefaults()
   171  	opts.Spec = filepath.Join(cwd, "a", "b", "c")
   172  	opts.ServerPackage = "y"
   173  	expected = filepath.Join("..", "a", "b", "c")
   174  	result = opts.SpecPath()
   175  	assert.Equal(t, expected, result)
   176  
   177  	// absolute spec, server path
   178  	opts = new(GenOpts)
   179  	_ = opts.EnsureDefaults()
   180  	opts.Spec = filepath.Join("..", "a", "b", "c")
   181  	opts.Target = ""
   182  	opts.ServerPackage = path.Join("y", "z")
   183  	expected = filepath.Join("..", "..", "..", "a", "b", "c")
   184  	result = opts.SpecPath()
   185  	assert.Equal(t, expected, result)
   186  
   187  	if runtime.GOOS == "windows" {
   188  		opts = new(GenOpts)
   189  		_ = opts.EnsureDefaults()
   190  		opts.Spec = filepath.Join("a", "b", "c")
   191  		opts.Target = filepath.Join("Z:", "e", "f", "f")
   192  		opts.ServerPackage = "y/z"
   193  		expected, _ = filepath.Abs(opts.Spec)
   194  		result = opts.SpecPath()
   195  		assert.Equal(t, expected, result)
   196  	}
   197  }
   198  
   199  // Low level testing: templates not found (higher level calls raise panic(), see above)
   200  func TestShared_NotFoundTemplate(t *testing.T) {
   201  	log.SetOutput(ioutil.Discard)
   202  	defer log.SetOutput(os.Stdout)
   203  
   204  	opts := GenOpts{}
   205  	tplOpts := TemplateOpts{
   206  		Name:       "NotFound",
   207  		Source:     "asset:notfound",
   208  		Target:     ".",
   209  		FileName:   "test_notfound.go",
   210  		SkipExists: false,
   211  		SkipFormat: false,
   212  	}
   213  
   214  	buf, err := opts.render(&tplOpts, nil)
   215  	assert.Error(t, err, "Error should be handled here")
   216  	assert.Nil(t, buf, "Upon error, GenOpts.render() should return nil buffer")
   217  }
   218  
   219  // Low level testing: invalid template => Get() returns not found (higher level calls raise panic(), see above)
   220  // TODO: better error discrimination between absent definition and non-parsing template
   221  func TestShared_GarbledTemplate(t *testing.T) {
   222  	log.SetOutput(ioutil.Discard)
   223  	defer log.SetOutput(os.Stdout)
   224  
   225  	garbled := "func x {{;;; garbled"
   226  
   227  	_ = templates.AddFile("garbled", garbled)
   228  	opts := GenOpts{}
   229  	tplOpts := TemplateOpts{
   230  		Name:       "Garbled",
   231  		Source:     "asset:garbled",
   232  		Target:     ".",
   233  		FileName:   "test_garbled.go",
   234  		SkipExists: false,
   235  		SkipFormat: false,
   236  	}
   237  
   238  	buf, err := opts.render(&tplOpts, nil)
   239  	assert.Error(t, err, "Error should be handled here")
   240  	assert.Nil(t, buf, "Upon error, GenOpts.render() should return nil buffer")
   241  }
   242  
   243  // Template execution failure
   244  type myTemplateData struct {
   245  }
   246  
   247  func (*myTemplateData) MyFaultyMethod() (string, error) {
   248  	return "", fmt.Errorf("myFaultyError")
   249  }
   250  
   251  func TestShared_ExecTemplate(t *testing.T) {
   252  	log.SetOutput(ioutil.Discard)
   253  	defer log.SetOutput(os.Stdout)
   254  
   255  	// Not a failure: no value data
   256  	execfailure1 := "func x {{ .NotInData }}"
   257  
   258  	_ = templates.AddFile("execfailure1", execfailure1)
   259  	opts := new(GenOpts)
   260  	tplOpts := TemplateOpts{
   261  		Name:       "execFailure1",
   262  		Source:     "asset:execfailure1",
   263  		Target:     ".",
   264  		FileName:   "test_execfailure1.go",
   265  		SkipExists: false,
   266  		SkipFormat: false,
   267  	}
   268  
   269  	buf1, err := opts.render(&tplOpts, nil)
   270  	assert.NoError(t, err, "Template rendering should put <no value> instead of missing data, and report no error")
   271  	assert.Equal(t, string(buf1), "func x <no value>")
   272  
   273  	execfailure2 := "func {{ .MyFaultyMethod }}"
   274  
   275  	_ = templates.AddFile("execfailure2", execfailure2)
   276  	opts = new(GenOpts)
   277  	tplOpts2 := TemplateOpts{
   278  		Name:       "execFailure2",
   279  		Source:     "asset:execfailure2",
   280  		Target:     ".",
   281  		FileName:   "test_execfailure2.go",
   282  		SkipExists: false,
   283  		SkipFormat: false,
   284  	}
   285  
   286  	data := new(myTemplateData)
   287  	buf2, err := opts.render(&tplOpts2, data)
   288  	assert.Error(t, err, "Error should be handled here: missing func in template yields an error")
   289  	assert.Contains(t, err.Error(), "template execution failed")
   290  	assert.Nil(t, buf2, "Upon error, GenOpts.render() should return nil buffer")
   291  }
   292  
   293  // Test correctly parsed templates, with bad formatting
   294  func TestShared_BadFormatTemplate(t *testing.T) {
   295  	log.SetOutput(ioutil.Discard)
   296  
   297  	defer func() {
   298  		_ = os.Remove("test_badformat.gol")
   299  		_ = os.Remove("test_badformat2.gol")
   300  		log.SetOutput(os.Stdout)
   301  		Debug = false
   302  	}()
   303  
   304  	// Not skipping format
   305  	badFormat := "func x {;;; garbled"
   306  
   307  	Debug = true
   308  	_ = templates.AddFile("badformat", badFormat)
   309  
   310  	opts := GenOpts{}
   311  	opts.LanguageOpts = GoLangOpts()
   312  	tplOpts := TemplateOpts{
   313  		Name:   "badformat",
   314  		Source: "asset:badformat",
   315  		Target: ".",
   316  		// Extension ".gol" won't mess with go if cleanup is not performed
   317  		FileName:   "test_badformat.gol",
   318  		SkipExists: false,
   319  		SkipFormat: false,
   320  	}
   321  
   322  	data := appGenerator{
   323  		Name:    "badtest",
   324  		Package: "wrongpkg",
   325  	}
   326  
   327  	err := opts.write(&tplOpts, data)
   328  
   329  	// The badly formatted file has been dumped for debugging purposes
   330  	_, exists := os.Stat(tplOpts.FileName)
   331  	assert.True(t, !os.IsNotExist(exists), "The template file has not been generated as expected")
   332  	_ = os.Remove(tplOpts.FileName)
   333  
   334  	assert.NotNil(t, err)
   335  	assert.Contains(t, err.Error(), "source formatting on generated source")
   336  
   337  	// Skipping format
   338  	opts = GenOpts{}
   339  	opts.LanguageOpts = GoLangOpts()
   340  	tplOpts2 := TemplateOpts{
   341  		Name:       "badformat2",
   342  		Source:     "asset:badformat",
   343  		Target:     ".",
   344  		FileName:   "test_badformat2.gol",
   345  		SkipExists: false,
   346  		SkipFormat: true,
   347  	}
   348  
   349  	err2 := opts.write(&tplOpts2, data)
   350  
   351  	// The unformatted file has been dumped without format checks
   352  	_, exists2 := os.Stat(tplOpts2.FileName)
   353  	assert.True(t, !os.IsNotExist(exists2), "The template file has not been generated as expected")
   354  	_ = os.Remove(tplOpts2.FileName)
   355  
   356  	assert.Nil(t, err2)
   357  
   358  	// os.RemoveAll(filepath.Join(filepath.FromSlash(dr),"restapi"))
   359  }
   360  
   361  // Test dir creation
   362  func TestShared_DirectoryTemplate(t *testing.T) {
   363  	log.SetOutput(ioutil.Discard)
   364  
   365  	defer func() {
   366  		_ = os.RemoveAll("TestGenDir")
   367  		log.SetOutput(os.Stdout)
   368  	}()
   369  
   370  	// Not skipping format
   371  	content := "func x {}"
   372  
   373  	_ = templates.AddFile("gendir", content)
   374  
   375  	opts := GenOpts{}
   376  	opts.LanguageOpts = GoLangOpts()
   377  	tplOpts := TemplateOpts{
   378  		Name:   "gendir",
   379  		Source: "asset:gendir",
   380  		Target: "TestGenDir",
   381  		// Extension ".gol" won't mess with go if cleanup is not performed
   382  		FileName:   "test_gendir.gol",
   383  		SkipExists: false,
   384  		SkipFormat: true,
   385  	}
   386  
   387  	data := appGenerator{
   388  		Name:    "gentest",
   389  		Package: "stubpkg",
   390  	}
   391  
   392  	err := opts.write(&tplOpts, data)
   393  
   394  	// The badly formatted file has been dumped for debugging purposes
   395  	_, exists := os.Stat(filepath.Join(tplOpts.Target, tplOpts.FileName))
   396  	assert.True(t, !os.IsNotExist(exists), "The template file has not been generated as expected")
   397  	_ = os.RemoveAll(tplOpts.Target)
   398  
   399  	assert.Nil(t, err)
   400  }
   401  
   402  // Test templates which are not assets (open in file)
   403  // Low level testing: templates loaded from file
   404  func TestShared_LoadTemplate(t *testing.T) {
   405  	log.SetOutput(ioutil.Discard)
   406  	defer log.SetOutput(os.Stdout)
   407  
   408  	opts := GenOpts{}
   409  	tplOpts := TemplateOpts{
   410  		Name:       "File",
   411  		Source:     "File",
   412  		Target:     ".",
   413  		FileName:   "file.go",
   414  		SkipExists: false,
   415  		SkipFormat: false,
   416  	}
   417  
   418  	buf, err := opts.render(&tplOpts, nil)
   419  	//spew.Dump(err)
   420  	assert.Error(t, err, "Error should be handled here")
   421  	assert.Contains(t, err.Error(), "open File")
   422  	assert.Contains(t, err.Error(), "error while opening")
   423  	assert.Nil(t, buf, "Upon error, GenOpts.render() should return nil buffer")
   424  
   425  	opts.TemplateDir = filepath.Join(".", "myTemplateDir")
   426  	buf, err = opts.render(&tplOpts, nil)
   427  	//spew.Dump(err)
   428  	assert.Error(t, err, "Error should be handled here")
   429  	assert.Contains(t, err.Error(), "open "+filepath.Join("myTemplateDir", "File"))
   430  	assert.Contains(t, err.Error(), "error while opening")
   431  	assert.Nil(t, buf, "Upon error, GenOpts.render() should return nil buffer")
   432  
   433  }
   434  
   435  func TestShared_Issue1429(t *testing.T) {
   436  	log.SetOutput(ioutil.Discard)
   437  	defer log.SetOutput(os.Stdout)
   438  
   439  	// acknowledge fix in go-openapi/spec
   440  	specPath := filepath.Join("..", "fixtures", "bugs", "1429", "swagger-1429.yaml")
   441  	specDoc, err := loads.Spec(specPath)
   442  	assert.NoError(t, err)
   443  
   444  	opts := testGenOpts()
   445  	opts.Spec = specPath
   446  	_, err = validateAndFlattenSpec(&opts, specDoc)
   447  	assert.NoError(t, err)
   448  
   449  	// more aggressive fixture on $refs, with validation errors, but flatten ok
   450  	specPath = filepath.Join("..", "fixtures", "bugs", "1429", "swagger.yaml")
   451  	specDoc, err = loads.Spec(specPath)
   452  	assert.NoError(t, err)
   453  
   454  	opts.Spec = specPath
   455  	opts.FlattenOpts.BasePath = specDoc.SpecFilePath()
   456  	opts.FlattenOpts.Spec = analysis.New(specDoc.Spec())
   457  	opts.FlattenOpts.Minimal = true
   458  	err = analysis.Flatten(*opts.FlattenOpts)
   459  	assert.NoError(t, err)
   460  
   461  	specDoc, _ = loads.Spec(specPath) // needs reload
   462  	opts.FlattenOpts.Spec = analysis.New(specDoc.Spec())
   463  	opts.FlattenOpts.Minimal = false
   464  	err = analysis.Flatten(*opts.FlattenOpts)
   465  	assert.NoError(t, err)
   466  }
   467  
   468  func TestShared_MangleFileName(t *testing.T) {
   469  	// standard : swag.ToFileName()
   470  	o := LanguageOpts{}
   471  	o.Init()
   472  	res := o.MangleFileName("aFileEndingInOsNameWindows")
   473  	assert.True(t, strings.HasSuffix(res, "_windows"))
   474  
   475  	// golang specific
   476  	res = golang.MangleFileName("aFileEndingInOsNameWindows")
   477  	assert.True(t, strings.HasSuffix(res, "_windows_swagger"))
   478  	res = golang.MangleFileName("aFileEndingInOsNameWindowsAmd64")
   479  	assert.True(t, strings.HasSuffix(res, "_windows_amd64_swagger"))
   480  	res = golang.MangleFileName("aFileEndingInTest")
   481  	assert.True(t, strings.HasSuffix(res, "_test_swagger"))
   482  }
   483  
   484  func TestShared_ManglePackage(t *testing.T) {
   485  	o := GoLangOpts()
   486  	o.Init()
   487  
   488  	for _, v := range []struct {
   489  		tested       string
   490  		expectedPath string
   491  		expectedName string
   492  	}{
   493  		{tested: "", expectedPath: "default", expectedName: "default"},
   494  		{tested: "select", expectedPath: "select_default", expectedName: "select_default"},
   495  		{tested: "x", expectedPath: "x", expectedName: "x"},
   496  		{tested: "a/b/c-d/e_f/g", expectedPath: "a/b/c-d/e_f/g", expectedName: "g"},
   497  		{tested: "a/b/c-d/e_f/g-h", expectedPath: "a/b/c-d/e_f/g_h", expectedName: "g_h"},
   498  	} {
   499  		res := o.ManglePackagePath(v.tested, "default")
   500  		assert.Equal(t, v.expectedPath, res)
   501  		res = o.ManglePackageName(v.tested, "default")
   502  		assert.Equal(t, v.expectedName, res)
   503  	}
   504  }
   505  
   506  func TestShared_Issue1621(t *testing.T) {
   507  	log.SetOutput(ioutil.Discard)
   508  	defer log.SetOutput(os.Stdout)
   509  
   510  	// acknowledge fix in go-openapi/spec
   511  	specPath := filepath.Join("..", "fixtures", "bugs", "1621", "fixture-1621.yaml")
   512  	specDoc, err := loads.Spec(specPath)
   513  	assert.NoError(t, err)
   514  
   515  	opts := testGenOpts()
   516  	opts.Spec = specPath
   517  	opts.ValidateSpec = true
   518  	//t.Logf("path: %s", specDoc.SpecFilePath())
   519  	_, err = validateAndFlattenSpec(&opts, specDoc)
   520  	assert.NoError(t, err)
   521  }
   522  
   523  func TestShared_Issue1614(t *testing.T) {
   524  	log.SetOutput(ioutil.Discard)
   525  	defer log.SetOutput(os.Stdout)
   526  
   527  	// acknowledge fix in go-openapi/spec
   528  	specPath := filepath.Join("..", "fixtures", "bugs", "1614", "gitea.json")
   529  	specDoc, err := loads.Spec(specPath)
   530  	assert.NoError(t, err)
   531  
   532  	opts := testGenOpts()
   533  	opts.Spec = specPath
   534  	opts.ValidateSpec = true
   535  	t.Logf("path: %s", specDoc.SpecFilePath())
   536  	_, err = validateAndFlattenSpec(&opts, specDoc)
   537  	assert.NoError(t, err)
   538  }