github.com/youyuanwu/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 }