feat: adjust fiber route generation
This commit is contained in:
540
pkg/swag/gen/gen.go
Normal file
540
pkg/swag/gen/gen.go
Normal file
@@ -0,0 +1,540 @@
|
||||
package gen
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"go/format"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"text/template"
|
||||
"time"
|
||||
|
||||
"git.ipao.vip/rogeecn/atomctl/pkg/swag"
|
||||
"github.com/go-openapi/spec"
|
||||
"golang.org/x/text/cases"
|
||||
"golang.org/x/text/language"
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
var open = os.Open
|
||||
|
||||
// DefaultOverridesFile is the location swagger will look for type overrides.
|
||||
const DefaultOverridesFile = ".swaggo"
|
||||
|
||||
type genTypeWriter func(*Config, *spec.Swagger) error
|
||||
|
||||
// Gen presents a generate tool for swag.
|
||||
type Gen struct {
|
||||
json func(data interface{}) ([]byte, error)
|
||||
jsonIndent func(data interface{}) ([]byte, error)
|
||||
jsonToYAML func(data []byte) ([]byte, error)
|
||||
outputTypeMap map[string]genTypeWriter
|
||||
debug Debugger
|
||||
}
|
||||
|
||||
// Debugger is the interface that wraps the basic Printf method.
|
||||
type Debugger interface {
|
||||
Printf(format string, v ...interface{})
|
||||
}
|
||||
|
||||
// New creates a new Gen.
|
||||
func New() *Gen {
|
||||
gen := Gen{
|
||||
json: json.Marshal,
|
||||
jsonIndent: func(data interface{}) ([]byte, error) {
|
||||
return json.MarshalIndent(data, "", " ")
|
||||
},
|
||||
jsonToYAML: yaml.JSONToYAML,
|
||||
debug: log.New(os.Stdout, "", log.LstdFlags),
|
||||
}
|
||||
|
||||
gen.outputTypeMap = map[string]genTypeWriter{
|
||||
"go": gen.writeDocSwagger,
|
||||
"json": gen.writeJSONSwagger,
|
||||
"yaml": gen.writeYAMLSwagger,
|
||||
"yml": gen.writeYAMLSwagger,
|
||||
}
|
||||
|
||||
return &gen
|
||||
}
|
||||
|
||||
// Config presents Gen configurations.
|
||||
type Config struct {
|
||||
Debugger swag.Debugger
|
||||
|
||||
// SearchDir the swag would parse,comma separated if multiple
|
||||
SearchDir string
|
||||
|
||||
// excludes dirs and files in SearchDir,comma separated
|
||||
Excludes string
|
||||
|
||||
// outputs only specific extension
|
||||
ParseExtension string
|
||||
|
||||
// OutputDir represents the output directory for all the generated files
|
||||
OutputDir string
|
||||
|
||||
// OutputTypes define types of files which should be generated
|
||||
OutputTypes []string
|
||||
|
||||
// MainAPIFile the Go file path in which 'swagger general API Info' is written
|
||||
MainAPIFile string
|
||||
|
||||
// PropNamingStrategy represents property naming strategy like snake case,camel case,pascal case
|
||||
PropNamingStrategy string
|
||||
|
||||
// MarkdownFilesDir used to find markdown files, which can be used for tag descriptions
|
||||
MarkdownFilesDir string
|
||||
|
||||
// CodeExampleFilesDir used to find code example files, which can be used for x-codeSamples
|
||||
CodeExampleFilesDir string
|
||||
|
||||
// InstanceName is used to get distinct names for different swagger documents in the
|
||||
// same project. The default value is "swagger".
|
||||
InstanceName string
|
||||
|
||||
// ParseDepth dependency parse depth
|
||||
ParseDepth int
|
||||
|
||||
// ParseVendor whether swag should be parse vendor folder
|
||||
ParseVendor bool
|
||||
|
||||
// ParseDependencies whether swag should be parse outside dependency folder: 0 none, 1 models, 2 operations, 3 all
|
||||
ParseDependency int
|
||||
|
||||
// ParseInternal whether swag should parse internal packages
|
||||
ParseInternal bool
|
||||
|
||||
// Strict whether swag should error or warn when it detects cases which are most likely user errors
|
||||
Strict bool
|
||||
|
||||
// GeneratedTime whether swag should generate the timestamp at the top of docs.go
|
||||
GeneratedTime bool
|
||||
|
||||
// RequiredByDefault set validation required for all fields by default
|
||||
RequiredByDefault bool
|
||||
|
||||
// OverridesFile defines global type overrides.
|
||||
OverridesFile string
|
||||
|
||||
// ParseGoList whether swag use go list to parse dependency
|
||||
ParseGoList bool
|
||||
|
||||
// include only tags mentioned when searching, comma separated
|
||||
Tags string
|
||||
|
||||
// LeftTemplateDelim defines the left delimiter for the template generation
|
||||
LeftTemplateDelim string
|
||||
|
||||
// RightTemplateDelim defines the right delimiter for the template generation
|
||||
RightTemplateDelim string
|
||||
|
||||
// PackageName defines package name of generated `docs.go`
|
||||
PackageName string
|
||||
|
||||
// CollectionFormat set default collection format
|
||||
CollectionFormat string
|
||||
|
||||
// Parse only packages whose import path match the given prefix, comma separated
|
||||
PackagePrefix string
|
||||
|
||||
// State set host state
|
||||
State string
|
||||
|
||||
// ParseFuncBody whether swag should parse api info inside of funcs
|
||||
ParseFuncBody bool
|
||||
}
|
||||
|
||||
// Build builds swagger json file for given searchDir and mainAPIFile. Returns json.
|
||||
func (g *Gen) Build(config *Config) error {
|
||||
if config.Debugger != nil {
|
||||
g.debug = config.Debugger
|
||||
}
|
||||
if config.InstanceName == "" {
|
||||
config.InstanceName = swag.Name
|
||||
}
|
||||
|
||||
searchDirs := strings.Split(config.SearchDir, ",")
|
||||
for _, searchDir := range searchDirs {
|
||||
if _, err := os.Stat(searchDir); os.IsNotExist(err) {
|
||||
return fmt.Errorf("dir: %s does not exist", searchDir)
|
||||
}
|
||||
}
|
||||
|
||||
if config.LeftTemplateDelim == "" {
|
||||
config.LeftTemplateDelim = "{{"
|
||||
}
|
||||
|
||||
if config.RightTemplateDelim == "" {
|
||||
config.RightTemplateDelim = "}}"
|
||||
}
|
||||
|
||||
var overrides map[string]string
|
||||
|
||||
if config.OverridesFile != "" {
|
||||
overridesFile, err := open(config.OverridesFile)
|
||||
if err != nil {
|
||||
// Don't bother reporting if the default file is missing; assume there are no overrides
|
||||
if !(config.OverridesFile == DefaultOverridesFile && os.IsNotExist(err)) {
|
||||
return fmt.Errorf("could not open overrides file: %w", err)
|
||||
}
|
||||
} else {
|
||||
g.debug.Printf("Using overrides from %s", config.OverridesFile)
|
||||
|
||||
overrides, err = parseOverrides(overridesFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g.debug.Printf("Generate swagger docs....")
|
||||
|
||||
p := swag.New(
|
||||
swag.SetParseDependency(config.ParseDependency),
|
||||
swag.SetMarkdownFileDirectory(config.MarkdownFilesDir),
|
||||
swag.SetDebugger(config.Debugger),
|
||||
swag.SetExcludedDirsAndFiles(config.Excludes),
|
||||
swag.SetParseExtension(config.ParseExtension),
|
||||
swag.SetCodeExamplesDirectory(config.CodeExampleFilesDir),
|
||||
swag.SetStrict(config.Strict),
|
||||
swag.SetOverrides(overrides),
|
||||
swag.ParseUsingGoList(config.ParseGoList),
|
||||
swag.SetTags(config.Tags),
|
||||
swag.SetCollectionFormat(config.CollectionFormat),
|
||||
swag.SetPackagePrefix(config.PackagePrefix),
|
||||
)
|
||||
|
||||
p.PropNamingStrategy = config.PropNamingStrategy
|
||||
p.ParseVendor = config.ParseVendor
|
||||
p.ParseInternal = config.ParseInternal
|
||||
p.RequiredByDefault = config.RequiredByDefault
|
||||
p.HostState = config.State
|
||||
p.ParseFuncBody = config.ParseFuncBody
|
||||
|
||||
if err := p.ParseAPIMultiSearchDir(searchDirs, config.MainAPIFile, config.ParseDepth); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
swagger := p.GetSwagger()
|
||||
|
||||
if err := os.MkdirAll(config.OutputDir, os.ModePerm); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, outputType := range config.OutputTypes {
|
||||
outputType = strings.ToLower(strings.TrimSpace(outputType))
|
||||
if typeWriter, ok := g.outputTypeMap[outputType]; ok {
|
||||
if err := typeWriter(config, swagger); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
log.Printf("output type '%s' not supported", outputType)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *Gen) writeDocSwagger(config *Config, swagger *spec.Swagger) error {
|
||||
filename := "docs.go"
|
||||
|
||||
if config.State != "" {
|
||||
filename = config.State + "_" + filename
|
||||
}
|
||||
|
||||
if config.InstanceName != swag.Name {
|
||||
filename = config.InstanceName + "_" + filename
|
||||
}
|
||||
|
||||
docFileName := path.Join(config.OutputDir, filename)
|
||||
|
||||
absOutputDir, err := filepath.Abs(config.OutputDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var packageName string
|
||||
if len(config.PackageName) > 0 {
|
||||
packageName = config.PackageName
|
||||
} else {
|
||||
packageName = filepath.Base(absOutputDir)
|
||||
packageName = strings.ReplaceAll(packageName, "-", "_")
|
||||
}
|
||||
|
||||
docs, err := os.Create(docFileName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer docs.Close()
|
||||
|
||||
// Write doc
|
||||
err = g.writeGoDoc(packageName, docs, swagger, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
g.debug.Printf("create docs.go at %+v", docFileName)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *Gen) writeJSONSwagger(config *Config, swagger *spec.Swagger) error {
|
||||
filename := "swagger.json"
|
||||
|
||||
if config.State != "" {
|
||||
filename = config.State + "_" + filename
|
||||
}
|
||||
|
||||
if config.InstanceName != swag.Name {
|
||||
filename = config.InstanceName + "_" + filename
|
||||
}
|
||||
|
||||
jsonFileName := path.Join(config.OutputDir, filename)
|
||||
|
||||
b, err := g.jsonIndent(swagger)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = g.writeFile(b, jsonFileName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
g.debug.Printf("create swagger.json at %+v", jsonFileName)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *Gen) writeYAMLSwagger(config *Config, swagger *spec.Swagger) error {
|
||||
filename := "swagger.yaml"
|
||||
|
||||
if config.State != "" {
|
||||
filename = config.State + "_" + filename
|
||||
}
|
||||
|
||||
if config.InstanceName != swag.Name {
|
||||
filename = config.InstanceName + "_" + filename
|
||||
}
|
||||
|
||||
yamlFileName := path.Join(config.OutputDir, filename)
|
||||
|
||||
b, err := g.json(swagger)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
y, err := g.jsonToYAML(b)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot covert json to yaml error: %s", err)
|
||||
}
|
||||
|
||||
err = g.writeFile(y, yamlFileName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
g.debug.Printf("create swagger.yaml at %+v", yamlFileName)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *Gen) writeFile(b []byte, file string) error {
|
||||
f, err := os.Create(file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer f.Close()
|
||||
|
||||
_, err = f.Write(b)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (g *Gen) formatSource(src []byte) []byte {
|
||||
code, err := format.Source(src)
|
||||
if err != nil {
|
||||
code = src // Formatter failed, return original code.
|
||||
}
|
||||
|
||||
return code
|
||||
}
|
||||
|
||||
// Read and parse the overrides file.
|
||||
func parseOverrides(r io.Reader) (map[string]string, error) {
|
||||
overrides := make(map[string]string)
|
||||
scanner := bufio.NewScanner(r)
|
||||
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
|
||||
// Skip comments
|
||||
if len(line) > 1 && line[0:2] == "//" {
|
||||
continue
|
||||
}
|
||||
|
||||
parts := strings.Fields(line)
|
||||
|
||||
switch len(parts) {
|
||||
case 0:
|
||||
// only whitespace
|
||||
continue
|
||||
case 2:
|
||||
// either a skip or malformed
|
||||
if parts[0] != "skip" {
|
||||
return nil, fmt.Errorf("could not parse override: '%s'", line)
|
||||
}
|
||||
|
||||
overrides[parts[1]] = ""
|
||||
case 3:
|
||||
// either a replace or malformed
|
||||
if parts[0] != "replace" {
|
||||
return nil, fmt.Errorf("could not parse override: '%s'", line)
|
||||
}
|
||||
|
||||
overrides[parts[1]] = parts[2]
|
||||
default:
|
||||
return nil, fmt.Errorf("could not parse override: '%s'", line)
|
||||
}
|
||||
}
|
||||
|
||||
if err := scanner.Err(); err != nil {
|
||||
return nil, fmt.Errorf("error reading overrides file: %w", err)
|
||||
}
|
||||
|
||||
return overrides, nil
|
||||
}
|
||||
|
||||
func (g *Gen) writeGoDoc(packageName string, output io.Writer, swagger *spec.Swagger, config *Config) error {
|
||||
generator, err := template.New("swagger_info").Funcs(template.FuncMap{
|
||||
"printDoc": func(v string) string {
|
||||
// Add schemes
|
||||
v = "{\n \"schemes\": " + config.LeftTemplateDelim + " marshal .Schemes " + config.RightTemplateDelim + "," + v[1:]
|
||||
// Sanitize backticks
|
||||
return strings.Replace(v, "`", "`+\"`\"+`", -1)
|
||||
},
|
||||
}).Parse(packageTemplate)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
swaggerSpec := &spec.Swagger{
|
||||
VendorExtensible: swagger.VendorExtensible,
|
||||
SwaggerProps: spec.SwaggerProps{
|
||||
ID: swagger.ID,
|
||||
Consumes: swagger.Consumes,
|
||||
Produces: swagger.Produces,
|
||||
Swagger: swagger.Swagger,
|
||||
Info: &spec.Info{
|
||||
VendorExtensible: swagger.Info.VendorExtensible,
|
||||
InfoProps: spec.InfoProps{
|
||||
Description: config.LeftTemplateDelim + "escape .Description" + config.RightTemplateDelim,
|
||||
Title: config.LeftTemplateDelim + ".Title" + config.RightTemplateDelim,
|
||||
TermsOfService: swagger.Info.TermsOfService,
|
||||
Contact: swagger.Info.Contact,
|
||||
License: swagger.Info.License,
|
||||
Version: config.LeftTemplateDelim + ".Version" + config.RightTemplateDelim,
|
||||
},
|
||||
},
|
||||
Host: config.LeftTemplateDelim + ".Host" + config.RightTemplateDelim,
|
||||
BasePath: config.LeftTemplateDelim + ".BasePath" + config.RightTemplateDelim,
|
||||
Paths: swagger.Paths,
|
||||
Definitions: swagger.Definitions,
|
||||
Parameters: swagger.Parameters,
|
||||
Responses: swagger.Responses,
|
||||
SecurityDefinitions: swagger.SecurityDefinitions,
|
||||
Security: swagger.Security,
|
||||
Tags: swagger.Tags,
|
||||
ExternalDocs: swagger.ExternalDocs,
|
||||
},
|
||||
}
|
||||
|
||||
// crafted docs.json
|
||||
buf, err := g.jsonIndent(swaggerSpec)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
state := ""
|
||||
if len(config.State) > 0 {
|
||||
state = cases.Title(language.English).String(strings.ToLower(config.State))
|
||||
}
|
||||
|
||||
buffer := &bytes.Buffer{}
|
||||
|
||||
err = generator.Execute(buffer, struct {
|
||||
Timestamp time.Time
|
||||
Doc string
|
||||
Host string
|
||||
PackageName string
|
||||
BasePath string
|
||||
Title string
|
||||
Description string
|
||||
Version string
|
||||
State string
|
||||
InstanceName string
|
||||
Schemes []string
|
||||
GeneratedTime bool
|
||||
LeftTemplateDelim string
|
||||
RightTemplateDelim string
|
||||
}{
|
||||
Timestamp: time.Now(),
|
||||
GeneratedTime: config.GeneratedTime,
|
||||
Doc: string(buf),
|
||||
Host: swagger.Host,
|
||||
PackageName: packageName,
|
||||
BasePath: swagger.BasePath,
|
||||
Schemes: swagger.Schemes,
|
||||
Title: swagger.Info.Title,
|
||||
Description: swagger.Info.Description,
|
||||
Version: swagger.Info.Version,
|
||||
State: state,
|
||||
InstanceName: config.InstanceName,
|
||||
LeftTemplateDelim: config.LeftTemplateDelim,
|
||||
RightTemplateDelim: config.RightTemplateDelim,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
code := g.formatSource(buffer.Bytes())
|
||||
|
||||
// write
|
||||
_, err = output.Write(code)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
var packageTemplate = `// Package {{.PackageName}} Code generated by swaggo/swag{{ if .GeneratedTime }} at {{ .Timestamp }}{{ end }}. DO NOT EDIT
|
||||
package {{.PackageName}}
|
||||
|
||||
import "github.com/swaggo/swag"
|
||||
|
||||
const docTemplate{{ if ne .InstanceName "swagger" }}{{ .InstanceName }} {{- end }}{{ .State }} = ` + "`{{ printDoc .Doc}}`" + `
|
||||
|
||||
// Swagger{{ .State }}Info{{ if ne .InstanceName "swagger" }}{{ .InstanceName }} {{- end }} holds exported Swagger Info so clients can modify it
|
||||
var Swagger{{ .State }}Info{{ if ne .InstanceName "swagger" }}{{ .InstanceName }} {{- end }} = &swag.Spec{
|
||||
Version: {{ printf "%q" .Version}},
|
||||
Host: {{ printf "%q" .Host}},
|
||||
BasePath: {{ printf "%q" .BasePath}},
|
||||
Schemes: []string{ {{ range $index, $schema := .Schemes}}{{if gt $index 0}},{{end}}{{printf "%q" $schema}}{{end}} },
|
||||
Title: {{ printf "%q" .Title}},
|
||||
Description: {{ printf "%q" .Description}},
|
||||
InfoInstanceName: {{ printf "%q" .InstanceName }},
|
||||
SwaggerTemplate: docTemplate{{ if ne .InstanceName "swagger" }}{{ .InstanceName }} {{- end }}{{ .State }},
|
||||
LeftDelim: {{ printf "%q" .LeftTemplateDelim}},
|
||||
RightDelim: {{ printf "%q" .RightTemplateDelim}},
|
||||
}
|
||||
|
||||
func init() {
|
||||
swag.Register(Swagger{{ .State }}Info{{ if ne .InstanceName "swagger" }}{{ .InstanceName }} {{- end }}.InstanceName(), Swagger{{ .State }}Info{{ if ne .InstanceName "swagger" }}{{ .InstanceName }} {{- end }})
|
||||
}
|
||||
`
|
||||
976
pkg/swag/gen/gen_test.go
Normal file
976
pkg/swag/gen/gen_test.go
Normal file
@@ -0,0 +1,976 @@
|
||||
package gen
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"plugin"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"git.ipao.vip/rogeecn/atomctl/pkg/swag"
|
||||
"github.com/go-openapi/spec"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
const searchDir = "../testdata/simple"
|
||||
|
||||
var outputTypes = []string{"go", "json", "yaml"}
|
||||
|
||||
func TestGen_Build(t *testing.T) {
|
||||
config := &Config{
|
||||
SearchDir: searchDir,
|
||||
MainAPIFile: "./main.go",
|
||||
OutputDir: "../testdata/simple/docs",
|
||||
OutputTypes: outputTypes,
|
||||
PropNamingStrategy: "",
|
||||
}
|
||||
assert.NoError(t, New().Build(config))
|
||||
|
||||
expectedFiles := []string{
|
||||
filepath.Join(config.OutputDir, "docs.go"),
|
||||
filepath.Join(config.OutputDir, "swagger.json"),
|
||||
filepath.Join(config.OutputDir, "swagger.yaml"),
|
||||
}
|
||||
for _, expectedFile := range expectedFiles {
|
||||
if _, err := os.Stat(expectedFile); os.IsNotExist(err) {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
_ = os.Remove(expectedFile)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGen_SpecificOutputTypes(t *testing.T) {
|
||||
config := &Config{
|
||||
SearchDir: searchDir,
|
||||
MainAPIFile: "./main.go",
|
||||
OutputDir: "../testdata/simple/docs",
|
||||
OutputTypes: []string{"go", "unknownType"},
|
||||
PropNamingStrategy: "",
|
||||
}
|
||||
assert.NoError(t, New().Build(config))
|
||||
|
||||
tt := []struct {
|
||||
expectedFile string
|
||||
shouldExist bool
|
||||
}{
|
||||
{filepath.Join(config.OutputDir, "docs.go"), true},
|
||||
{filepath.Join(config.OutputDir, "swagger.json"), false},
|
||||
{filepath.Join(config.OutputDir, "swagger.yaml"), false},
|
||||
}
|
||||
for _, tc := range tt {
|
||||
_, err := os.Stat(tc.expectedFile)
|
||||
if tc.shouldExist {
|
||||
if os.IsNotExist(err) {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
} else {
|
||||
require.Error(t, err)
|
||||
require.True(t, errors.Is(err, os.ErrNotExist))
|
||||
}
|
||||
|
||||
_ = os.Remove(tc.expectedFile)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGen_BuildInstanceName(t *testing.T) {
|
||||
config := &Config{
|
||||
SearchDir: searchDir,
|
||||
MainAPIFile: "./main.go",
|
||||
OutputDir: "../testdata/simple/docs",
|
||||
OutputTypes: outputTypes,
|
||||
PropNamingStrategy: "",
|
||||
}
|
||||
assert.NoError(t, New().Build(config))
|
||||
|
||||
goSourceFile := filepath.Join(config.OutputDir, "docs.go")
|
||||
|
||||
// Validate default registration name
|
||||
expectedCode, err := os.ReadFile(goSourceFile)
|
||||
if err != nil {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
if !strings.Contains(
|
||||
string(expectedCode),
|
||||
"swag.Register(SwaggerInfo.InstanceName(), SwaggerInfo)",
|
||||
) {
|
||||
t.Fatal(errors.New("generated go code does not contain the correct default registration sequence"))
|
||||
}
|
||||
|
||||
if !strings.Contains(
|
||||
string(expectedCode),
|
||||
"var SwaggerInfo =",
|
||||
) {
|
||||
t.Fatal(errors.New("generated go code does not contain the correct default variable declaration"))
|
||||
}
|
||||
|
||||
// Custom name
|
||||
config.InstanceName = "Custom"
|
||||
goSourceFile = filepath.Join(config.OutputDir, config.InstanceName+"_"+"docs.go")
|
||||
assert.NoError(t, New().Build(config))
|
||||
|
||||
expectedCode, err = os.ReadFile(goSourceFile)
|
||||
if err != nil {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
if !strings.Contains(
|
||||
string(expectedCode),
|
||||
"swag.Register(SwaggerInfoCustom.InstanceName(), SwaggerInfoCustom)",
|
||||
) {
|
||||
t.Fatal(errors.New("generated go code does not contain the correct registration sequence"))
|
||||
}
|
||||
|
||||
if !strings.Contains(
|
||||
string(expectedCode),
|
||||
"var SwaggerInfoCustom =",
|
||||
) {
|
||||
t.Fatal(errors.New("generated go code does not contain the correct variable declaration"))
|
||||
}
|
||||
|
||||
// cleanup
|
||||
expectedFiles := []string{
|
||||
filepath.Join(config.OutputDir, config.InstanceName+"_"+"docs.go"),
|
||||
filepath.Join(config.OutputDir, config.InstanceName+"_"+"swagger.json"),
|
||||
filepath.Join(config.OutputDir, config.InstanceName+"_"+"swagger.yaml"),
|
||||
}
|
||||
|
||||
for _, expectedFile := range expectedFiles {
|
||||
if _, err := os.Stat(expectedFile); os.IsNotExist(err) {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
_ = os.Remove(expectedFile)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGen_BuildSnakeCase(t *testing.T) {
|
||||
config := &Config{
|
||||
SearchDir: "../testdata/simple2",
|
||||
MainAPIFile: "./main.go",
|
||||
OutputDir: "../testdata/simple2/docs",
|
||||
OutputTypes: outputTypes,
|
||||
PropNamingStrategy: swag.SnakeCase,
|
||||
}
|
||||
|
||||
assert.NoError(t, New().Build(config))
|
||||
|
||||
expectedFiles := []string{
|
||||
filepath.Join(config.OutputDir, "docs.go"),
|
||||
filepath.Join(config.OutputDir, "swagger.json"),
|
||||
filepath.Join(config.OutputDir, "swagger.yaml"),
|
||||
}
|
||||
for _, expectedFile := range expectedFiles {
|
||||
if _, err := os.Stat(expectedFile); os.IsNotExist(err) {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
_ = os.Remove(expectedFile)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGen_BuildLowerCamelcase(t *testing.T) {
|
||||
config := &Config{
|
||||
SearchDir: "../testdata/simple3",
|
||||
MainAPIFile: "./main.go",
|
||||
OutputDir: "../testdata/simple3/docs",
|
||||
OutputTypes: outputTypes,
|
||||
PropNamingStrategy: "",
|
||||
}
|
||||
|
||||
assert.NoError(t, New().Build(config))
|
||||
|
||||
expectedFiles := []string{
|
||||
filepath.Join(config.OutputDir, "docs.go"),
|
||||
filepath.Join(config.OutputDir, "swagger.json"),
|
||||
filepath.Join(config.OutputDir, "swagger.yaml"),
|
||||
}
|
||||
for _, expectedFile := range expectedFiles {
|
||||
if _, err := os.Stat(expectedFile); os.IsNotExist(err) {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
_ = os.Remove(expectedFile)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGen_BuildDescriptionWithQuotes(t *testing.T) {
|
||||
config := &Config{
|
||||
SearchDir: "../testdata/quotes",
|
||||
MainAPIFile: "./main.go",
|
||||
OutputDir: "../testdata/quotes/docs",
|
||||
OutputTypes: outputTypes,
|
||||
MarkdownFilesDir: "../testdata/quotes",
|
||||
}
|
||||
|
||||
require.NoError(t, New().Build(config))
|
||||
|
||||
expectedFiles := []string{
|
||||
filepath.Join(config.OutputDir, "docs.go"),
|
||||
filepath.Join(config.OutputDir, "swagger.json"),
|
||||
filepath.Join(config.OutputDir, "swagger.yaml"),
|
||||
}
|
||||
for _, expectedFile := range expectedFiles {
|
||||
if _, err := os.Stat(expectedFile); os.IsNotExist(err) {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
}
|
||||
|
||||
cmd := exec.Command("go", "build", "-buildmode=plugin", "git.ipao.vip/rogeecn/atomctl/pkg/swag/testdata/quotes")
|
||||
|
||||
cmd.Dir = config.SearchDir
|
||||
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
require.NoError(t, err, string(output))
|
||||
}
|
||||
|
||||
p, err := plugin.Open(filepath.Join(config.SearchDir, "quotes.so"))
|
||||
if err != nil {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
defer os.Remove("quotes.so")
|
||||
|
||||
readDoc, err := p.Lookup("ReadDoc")
|
||||
if err != nil {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
jsonOutput := readDoc.(func() string)()
|
||||
|
||||
var jsonDoc interface{}
|
||||
if err := json.Unmarshal([]byte(jsonOutput), &jsonDoc); err != nil {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
expectedJSON, err := os.ReadFile(filepath.Join(config.SearchDir, "expected.json"))
|
||||
if err != nil {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
assert.JSONEq(t, string(expectedJSON), jsonOutput)
|
||||
}
|
||||
|
||||
func TestGen_BuildDocCustomDelims(t *testing.T) {
|
||||
config := &Config{
|
||||
SearchDir: "../testdata/delims",
|
||||
MainAPIFile: "./main.go",
|
||||
OutputDir: "../testdata/delims/docs",
|
||||
OutputTypes: outputTypes,
|
||||
MarkdownFilesDir: "../testdata/delims",
|
||||
InstanceName: "CustomDelims",
|
||||
LeftTemplateDelim: "{%",
|
||||
RightTemplateDelim: "%}",
|
||||
}
|
||||
|
||||
require.NoError(t, New().Build(config))
|
||||
|
||||
expectedFiles := []string{
|
||||
filepath.Join(config.OutputDir, "CustomDelims_docs.go"),
|
||||
filepath.Join(config.OutputDir, "CustomDelims_swagger.json"),
|
||||
filepath.Join(config.OutputDir, "CustomDelims_swagger.yaml"),
|
||||
}
|
||||
for _, expectedFile := range expectedFiles {
|
||||
if _, err := os.Stat(expectedFile); os.IsNotExist(err) {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
}
|
||||
|
||||
cmd := exec.Command("go", "build", "-buildmode=plugin", "git.ipao.vip/rogeecn/atomctl/pkg/swag/testdata/delims")
|
||||
|
||||
cmd.Dir = config.SearchDir
|
||||
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
require.NoError(t, err, string(output))
|
||||
}
|
||||
|
||||
p, err := plugin.Open(filepath.Join(config.SearchDir, "delims.so"))
|
||||
if err != nil {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
defer os.Remove("delims.so")
|
||||
|
||||
readDoc, err := p.Lookup("ReadDoc")
|
||||
if err != nil {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
jsonOutput := readDoc.(func() string)()
|
||||
|
||||
var jsonDoc interface{}
|
||||
if err := json.Unmarshal([]byte(jsonOutput), &jsonDoc); err != nil {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
expectedJSON, err := os.ReadFile(filepath.Join(config.SearchDir, "expected.json"))
|
||||
if err != nil {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
assert.JSONEq(t, string(expectedJSON), jsonOutput)
|
||||
}
|
||||
|
||||
func TestGen_jsonIndent(t *testing.T) {
|
||||
config := &Config{
|
||||
SearchDir: searchDir,
|
||||
MainAPIFile: "./main.go",
|
||||
OutputDir: "../testdata/simple/docs",
|
||||
OutputTypes: outputTypes,
|
||||
PropNamingStrategy: "",
|
||||
}
|
||||
|
||||
gen := New()
|
||||
gen.jsonIndent = func(data interface{}) ([]byte, error) {
|
||||
return nil, errors.New("fail")
|
||||
}
|
||||
|
||||
assert.Error(t, gen.Build(config))
|
||||
}
|
||||
|
||||
func TestGen_jsonToYAML(t *testing.T) {
|
||||
config := &Config{
|
||||
SearchDir: searchDir,
|
||||
MainAPIFile: "./main.go",
|
||||
OutputDir: "../testdata/simple/docs",
|
||||
OutputTypes: outputTypes,
|
||||
PropNamingStrategy: "",
|
||||
}
|
||||
|
||||
gen := New()
|
||||
gen.jsonToYAML = func(data []byte) ([]byte, error) {
|
||||
return nil, errors.New("fail")
|
||||
}
|
||||
assert.Error(t, gen.Build(config))
|
||||
|
||||
expectedFiles := []string{
|
||||
filepath.Join(config.OutputDir, "docs.go"),
|
||||
filepath.Join(config.OutputDir, "swagger.json"),
|
||||
}
|
||||
|
||||
for _, expectedFile := range expectedFiles {
|
||||
if _, err := os.Stat(expectedFile); os.IsNotExist(err) {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
_ = os.Remove(expectedFile)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGen_SearchDirIsNotExist(t *testing.T) {
|
||||
var swaggerConfDir, propNamingStrategy string
|
||||
|
||||
config := &Config{
|
||||
SearchDir: "../isNotExistDir",
|
||||
MainAPIFile: "./main.go",
|
||||
OutputDir: swaggerConfDir,
|
||||
OutputTypes: outputTypes,
|
||||
PropNamingStrategy: propNamingStrategy,
|
||||
}
|
||||
|
||||
assert.EqualError(t, New().Build(config), "dir: ../isNotExistDir does not exist")
|
||||
}
|
||||
|
||||
func TestGen_MainAPiNotExist(t *testing.T) {
|
||||
var swaggerConfDir, propNamingStrategy string
|
||||
|
||||
config := &Config{
|
||||
SearchDir: searchDir,
|
||||
MainAPIFile: "./notExists.go",
|
||||
OutputDir: swaggerConfDir,
|
||||
OutputTypes: outputTypes,
|
||||
PropNamingStrategy: propNamingStrategy,
|
||||
}
|
||||
|
||||
assert.Error(t, New().Build(config))
|
||||
}
|
||||
|
||||
func TestGen_OutputIsNotExist(t *testing.T) {
|
||||
var propNamingStrategy string
|
||||
config := &Config{
|
||||
SearchDir: searchDir,
|
||||
MainAPIFile: "./main.go",
|
||||
OutputDir: "/dev/null",
|
||||
OutputTypes: outputTypes,
|
||||
PropNamingStrategy: propNamingStrategy,
|
||||
}
|
||||
assert.Error(t, New().Build(config))
|
||||
}
|
||||
|
||||
func TestGen_FailToWrite(t *testing.T) {
|
||||
outputDir := filepath.Join(os.TempDir(), "swagg", "test")
|
||||
outputTypes := []string{"go", "json", "yaml"}
|
||||
|
||||
var propNamingStrategy string
|
||||
config := &Config{
|
||||
SearchDir: searchDir,
|
||||
MainAPIFile: "./main.go",
|
||||
OutputDir: outputDir,
|
||||
OutputTypes: outputTypes,
|
||||
PropNamingStrategy: propNamingStrategy,
|
||||
}
|
||||
|
||||
err := os.MkdirAll(outputDir, 0o755)
|
||||
if err != nil {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
_ = os.RemoveAll(filepath.Join(outputDir, "swagger.yaml"))
|
||||
|
||||
err = os.Mkdir(filepath.Join(outputDir, "swagger.yaml"), 0o755)
|
||||
if err != nil {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
assert.Error(t, New().Build(config))
|
||||
|
||||
_ = os.RemoveAll(filepath.Join(outputDir, "swagger.json"))
|
||||
|
||||
err = os.Mkdir(filepath.Join(outputDir, "swagger.json"), 0o755)
|
||||
if err != nil {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
assert.Error(t, New().Build(config))
|
||||
|
||||
_ = os.RemoveAll(filepath.Join(outputDir, "docs.go"))
|
||||
|
||||
err = os.Mkdir(filepath.Join(outputDir, "docs.go"), 0o755)
|
||||
if err != nil {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
assert.Error(t, New().Build(config))
|
||||
|
||||
err = os.RemoveAll(outputDir)
|
||||
if err != nil {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGen_configWithOutputDir(t *testing.T) {
|
||||
config := &Config{
|
||||
SearchDir: searchDir,
|
||||
MainAPIFile: "./main.go",
|
||||
OutputDir: "../testdata/simple/docs",
|
||||
OutputTypes: outputTypes,
|
||||
PropNamingStrategy: "",
|
||||
}
|
||||
|
||||
assert.NoError(t, New().Build(config))
|
||||
|
||||
expectedFiles := []string{
|
||||
filepath.Join(config.OutputDir, "docs.go"),
|
||||
filepath.Join(config.OutputDir, "swagger.json"),
|
||||
filepath.Join(config.OutputDir, "swagger.yaml"),
|
||||
}
|
||||
for _, expectedFile := range expectedFiles {
|
||||
if _, err := os.Stat(expectedFile); os.IsNotExist(err) {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
_ = os.Remove(expectedFile)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGen_configWithOutputTypesAll(t *testing.T) {
|
||||
searchDir := "../testdata/simple"
|
||||
outputTypes := []string{"go", "json", "yaml"}
|
||||
|
||||
config := &Config{
|
||||
SearchDir: searchDir,
|
||||
MainAPIFile: "./main.go",
|
||||
OutputDir: "../testdata/simple/docs",
|
||||
OutputTypes: outputTypes,
|
||||
PropNamingStrategy: "",
|
||||
}
|
||||
|
||||
assert.NoError(t, New().Build(config))
|
||||
|
||||
expectedFiles := []string{
|
||||
path.Join(config.OutputDir, "docs.go"),
|
||||
path.Join(config.OutputDir, "swagger.json"),
|
||||
path.Join(config.OutputDir, "swagger.yaml"),
|
||||
}
|
||||
for _, expectedFile := range expectedFiles {
|
||||
if _, err := os.Stat(expectedFile); os.IsNotExist(err) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_ = os.Remove(expectedFile)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGen_configWithOutputTypesSingle(t *testing.T) {
|
||||
searchDir := "../testdata/simple"
|
||||
outputTypes := []string{"go", "json", "yaml"}
|
||||
|
||||
for _, outputType := range outputTypes {
|
||||
config := &Config{
|
||||
SearchDir: searchDir,
|
||||
MainAPIFile: "./main.go",
|
||||
OutputDir: "../testdata/simple/docs",
|
||||
OutputTypes: []string{outputType},
|
||||
PropNamingStrategy: "",
|
||||
}
|
||||
|
||||
assert.NoError(t, New().Build(config))
|
||||
|
||||
outFileName := "swagger"
|
||||
if outputType == "go" {
|
||||
outFileName = "docs"
|
||||
}
|
||||
|
||||
expectedFiles := []string{
|
||||
path.Join(config.OutputDir, outFileName+"."+outputType),
|
||||
}
|
||||
for _, expectedFile := range expectedFiles {
|
||||
if _, err := os.Stat(expectedFile); os.IsNotExist(err) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_ = os.Remove(expectedFile)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGen_formatSource(t *testing.T) {
|
||||
src := `package main
|
||||
|
||||
import "net
|
||||
|
||||
func main() {}
|
||||
`
|
||||
g := New()
|
||||
|
||||
res := g.formatSource([]byte(src))
|
||||
assert.Equal(t, []byte(src), res, "Should return same content due to fmt fail")
|
||||
|
||||
src2 := `package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
fmt.Print("Hello world")
|
||||
}
|
||||
`
|
||||
res = g.formatSource([]byte(src2))
|
||||
assert.NotEqual(t, []byte(src2), res, "Should return fmt code")
|
||||
}
|
||||
|
||||
type mockWriter struct {
|
||||
hook func([]byte)
|
||||
}
|
||||
|
||||
func (w *mockWriter) Write(data []byte) (int, error) {
|
||||
if w.hook != nil {
|
||||
w.hook(data)
|
||||
}
|
||||
|
||||
return len(data), nil
|
||||
}
|
||||
|
||||
func TestGen_writeGoDoc(t *testing.T) {
|
||||
gen := New()
|
||||
|
||||
swapTemplate := packageTemplate
|
||||
|
||||
packageTemplate = `{{{`
|
||||
err := gen.writeGoDoc("docs", nil, nil, &Config{})
|
||||
assert.Error(t, err)
|
||||
|
||||
packageTemplate = `{{.Data}}`
|
||||
swagger := &spec.Swagger{
|
||||
VendorExtensible: spec.VendorExtensible{},
|
||||
SwaggerProps: spec.SwaggerProps{
|
||||
Info: &spec.Info{},
|
||||
},
|
||||
}
|
||||
|
||||
err = gen.writeGoDoc("docs", &mockWriter{}, swagger, &Config{})
|
||||
assert.Error(t, err)
|
||||
|
||||
packageTemplate = `{{ if .GeneratedTime }}Fake Time{{ end }}`
|
||||
err = gen.writeGoDoc("docs",
|
||||
&mockWriter{
|
||||
hook: func(data []byte) {
|
||||
assert.Equal(t, "Fake Time", string(data))
|
||||
},
|
||||
}, swagger, &Config{GeneratedTime: true})
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = gen.writeGoDoc("docs",
|
||||
&mockWriter{
|
||||
hook: func(data []byte) {
|
||||
assert.Equal(t, "", string(data))
|
||||
},
|
||||
}, swagger, &Config{GeneratedTime: false})
|
||||
assert.NoError(t, err)
|
||||
|
||||
packageTemplate = swapTemplate
|
||||
}
|
||||
|
||||
func TestGen_GeneratedDoc(t *testing.T) {
|
||||
config := &Config{
|
||||
SearchDir: searchDir,
|
||||
MainAPIFile: "./main.go",
|
||||
OutputDir: "../testdata/simple/docs",
|
||||
OutputTypes: outputTypes,
|
||||
PropNamingStrategy: "",
|
||||
}
|
||||
|
||||
assert.NoError(t, New().Build(config))
|
||||
|
||||
goCMD, err := exec.LookPath("go")
|
||||
assert.NoError(t, err)
|
||||
|
||||
cmd := exec.Command(goCMD, "build", filepath.Join(config.OutputDir, "docs.go"))
|
||||
|
||||
cmd.Stdout = os.Stdout
|
||||
|
||||
cmd.Stderr = os.Stderr
|
||||
|
||||
assert.NoError(t, cmd.Run())
|
||||
|
||||
expectedFiles := []string{
|
||||
filepath.Join(config.OutputDir, "docs.go"),
|
||||
filepath.Join(config.OutputDir, "swagger.json"),
|
||||
filepath.Join(config.OutputDir, "swagger.yaml"),
|
||||
}
|
||||
for _, expectedFile := range expectedFiles {
|
||||
if _, err := os.Stat(expectedFile); os.IsNotExist(err) {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
_ = os.Remove(expectedFile)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGen_cgoImports(t *testing.T) {
|
||||
config := &Config{
|
||||
SearchDir: "../testdata/simple_cgo",
|
||||
MainAPIFile: "./main.go",
|
||||
OutputDir: "../testdata/simple_cgo/docs",
|
||||
OutputTypes: outputTypes,
|
||||
PropNamingStrategy: "",
|
||||
ParseDependency: 1,
|
||||
}
|
||||
|
||||
assert.NoError(t, New().Build(config))
|
||||
|
||||
expectedFiles := []string{
|
||||
filepath.Join(config.OutputDir, "docs.go"),
|
||||
filepath.Join(config.OutputDir, "swagger.json"),
|
||||
filepath.Join(config.OutputDir, "swagger.yaml"),
|
||||
}
|
||||
for _, expectedFile := range expectedFiles {
|
||||
if _, err := os.Stat(expectedFile); os.IsNotExist(err) {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
_ = os.Remove(expectedFile)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGen_parseOverrides(t *testing.T) {
|
||||
testCases := []struct {
|
||||
Name string
|
||||
Data string
|
||||
Expected map[string]string
|
||||
ExpectedError error
|
||||
}{
|
||||
{
|
||||
Name: "replace",
|
||||
Data: `replace github.com/foo/bar baz`,
|
||||
Expected: map[string]string{
|
||||
"github.com/foo/bar": "baz",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "skip",
|
||||
Data: `skip github.com/foo/bar`,
|
||||
Expected: map[string]string{
|
||||
"github.com/foo/bar": "",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "generic-simple",
|
||||
Data: `replace types.Field[string] string`,
|
||||
Expected: map[string]string{
|
||||
"types.Field[string]": "string",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "generic-double",
|
||||
Data: `replace types.Field[string,string] string`,
|
||||
Expected: map[string]string{
|
||||
"types.Field[string,string]": "string",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "comment",
|
||||
Data: `// this is a comment
|
||||
replace foo bar`,
|
||||
Expected: map[string]string{
|
||||
"foo": "bar",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "ignore whitespace",
|
||||
Data: `
|
||||
|
||||
replace foo bar`,
|
||||
Expected: map[string]string{
|
||||
"foo": "bar",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "unknown directive",
|
||||
Data: `foo`,
|
||||
ExpectedError: fmt.Errorf("could not parse override: 'foo'"),
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
tc := tc
|
||||
t.Run(tc.Name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
overrides, err := parseOverrides(strings.NewReader(tc.Data))
|
||||
assert.Equal(t, tc.Expected, overrides)
|
||||
assert.Equal(t, tc.ExpectedError, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGen_TypeOverridesFile(t *testing.T) {
|
||||
customPath := "/foo/bar/baz"
|
||||
|
||||
tmp, err := os.CreateTemp("", "")
|
||||
require.NoError(t, err)
|
||||
|
||||
defer os.Remove(tmp.Name())
|
||||
|
||||
config := &Config{
|
||||
SearchDir: searchDir,
|
||||
MainAPIFile: "./main.go",
|
||||
OutputDir: "../testdata/simple/docs",
|
||||
PropNamingStrategy: "",
|
||||
}
|
||||
|
||||
t.Run("Default file is missing", func(t *testing.T) {
|
||||
open = func(path string) (*os.File, error) {
|
||||
assert.Equal(t, DefaultOverridesFile, path)
|
||||
|
||||
return nil, os.ErrNotExist
|
||||
}
|
||||
defer func() {
|
||||
open = os.Open
|
||||
}()
|
||||
|
||||
config.OverridesFile = DefaultOverridesFile
|
||||
err := New().Build(config)
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("Default file is present", func(t *testing.T) {
|
||||
open = func(path string) (*os.File, error) {
|
||||
assert.Equal(t, DefaultOverridesFile, path)
|
||||
|
||||
return tmp, nil
|
||||
}
|
||||
defer func() {
|
||||
open = os.Open
|
||||
}()
|
||||
|
||||
config.OverridesFile = DefaultOverridesFile
|
||||
err := New().Build(config)
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("Different file is missing", func(t *testing.T) {
|
||||
open = func(path string) (*os.File, error) {
|
||||
assert.Equal(t, customPath, path)
|
||||
|
||||
return nil, os.ErrNotExist
|
||||
}
|
||||
defer func() {
|
||||
open = os.Open
|
||||
}()
|
||||
|
||||
config.OverridesFile = customPath
|
||||
err := New().Build(config)
|
||||
assert.EqualError(t, err, "could not open overrides file: file does not exist")
|
||||
})
|
||||
|
||||
t.Run("Different file is present", func(t *testing.T) {
|
||||
open = func(path string) (*os.File, error) {
|
||||
assert.Equal(t, customPath, path)
|
||||
|
||||
return tmp, nil
|
||||
}
|
||||
defer func() {
|
||||
open = os.Open
|
||||
}()
|
||||
|
||||
config.OverridesFile = customPath
|
||||
err := New().Build(config)
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestGen_Debugger(t *testing.T) {
|
||||
var buf bytes.Buffer
|
||||
config := &Config{
|
||||
SearchDir: searchDir,
|
||||
MainAPIFile: "./main.go",
|
||||
OutputDir: "../testdata/simple/docs",
|
||||
OutputTypes: outputTypes,
|
||||
PropNamingStrategy: "",
|
||||
Debugger: log.New(&buf, "", log.LstdFlags),
|
||||
}
|
||||
assert.True(t, buf.Len() == 0)
|
||||
assert.NoError(t, New().Build(config))
|
||||
assert.True(t, buf.Len() > 0)
|
||||
|
||||
expectedFiles := []string{
|
||||
filepath.Join(config.OutputDir, "docs.go"),
|
||||
filepath.Join(config.OutputDir, "swagger.json"),
|
||||
filepath.Join(config.OutputDir, "swagger.yaml"),
|
||||
}
|
||||
for _, expectedFile := range expectedFiles {
|
||||
if _, err := os.Stat(expectedFile); os.IsNotExist(err) {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
_ = os.Remove(expectedFile)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGen_ErrorAndInterface(t *testing.T) {
|
||||
config := &Config{
|
||||
SearchDir: "../testdata/error",
|
||||
MainAPIFile: "./main.go",
|
||||
OutputDir: "../testdata/error/docs",
|
||||
OutputTypes: outputTypes,
|
||||
PropNamingStrategy: "",
|
||||
}
|
||||
|
||||
assert.NoError(t, New().Build(config))
|
||||
|
||||
expectedFiles := []string{
|
||||
filepath.Join(config.OutputDir, "docs.go"),
|
||||
filepath.Join(config.OutputDir, "swagger.json"),
|
||||
filepath.Join(config.OutputDir, "swagger.yaml"),
|
||||
}
|
||||
t.Cleanup(func() {
|
||||
for _, expectedFile := range expectedFiles {
|
||||
_ = os.Remove(expectedFile)
|
||||
}
|
||||
})
|
||||
|
||||
// check files
|
||||
for _, expectedFile := range expectedFiles {
|
||||
if _, err := os.Stat(expectedFile); os.IsNotExist(err) {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
}
|
||||
|
||||
// check content
|
||||
jsonOutput, err := os.ReadFile(filepath.Join(config.OutputDir, "swagger.json"))
|
||||
if err != nil {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
expectedJSON, err := os.ReadFile(filepath.Join(config.SearchDir, "expected.json"))
|
||||
if err != nil {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
assert.JSONEq(t, string(expectedJSON), string(jsonOutput))
|
||||
}
|
||||
|
||||
func TestGen_StateAdmin(t *testing.T) {
|
||||
config := &Config{
|
||||
SearchDir: "../testdata/state",
|
||||
MainAPIFile: "./main.go",
|
||||
OutputDir: "../testdata/state/docs",
|
||||
OutputTypes: outputTypes,
|
||||
PropNamingStrategy: "",
|
||||
State: "admin",
|
||||
}
|
||||
|
||||
assert.NoError(t, New().Build(config))
|
||||
|
||||
expectedFiles := []string{
|
||||
filepath.Join(config.OutputDir, "admin_docs.go"),
|
||||
filepath.Join(config.OutputDir, "admin_swagger.json"),
|
||||
filepath.Join(config.OutputDir, "admin_swagger.yaml"),
|
||||
}
|
||||
t.Cleanup(func() {
|
||||
for _, expectedFile := range expectedFiles {
|
||||
_ = os.Remove(expectedFile)
|
||||
}
|
||||
})
|
||||
|
||||
// check files
|
||||
for _, expectedFile := range expectedFiles {
|
||||
if _, err := os.Stat(expectedFile); os.IsNotExist(err) {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
}
|
||||
|
||||
// check content
|
||||
jsonOutput, err := os.ReadFile(filepath.Join(config.OutputDir, "admin_swagger.json"))
|
||||
require.NoError(t, err)
|
||||
expectedJSON, err := os.ReadFile(filepath.Join(config.SearchDir, "admin_expected.json"))
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.JSONEq(t, string(expectedJSON), string(jsonOutput))
|
||||
}
|
||||
|
||||
func TestGen_StateUser(t *testing.T) {
|
||||
config := &Config{
|
||||
SearchDir: "../testdata/state",
|
||||
MainAPIFile: "./main.go",
|
||||
OutputDir: "../testdata/state/docs",
|
||||
OutputTypes: outputTypes,
|
||||
PropNamingStrategy: "",
|
||||
State: "user",
|
||||
}
|
||||
|
||||
assert.NoError(t, New().Build(config))
|
||||
|
||||
expectedFiles := []string{
|
||||
filepath.Join(config.OutputDir, "user_docs.go"),
|
||||
filepath.Join(config.OutputDir, "user_swagger.json"),
|
||||
filepath.Join(config.OutputDir, "user_swagger.yaml"),
|
||||
}
|
||||
t.Cleanup(func() {
|
||||
for _, expectedFile := range expectedFiles {
|
||||
_ = os.Remove(expectedFile)
|
||||
}
|
||||
})
|
||||
|
||||
// check files
|
||||
for _, expectedFile := range expectedFiles {
|
||||
if _, err := os.Stat(expectedFile); os.IsNotExist(err) {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
}
|
||||
|
||||
// check content
|
||||
jsonOutput, err := os.ReadFile(filepath.Join(config.OutputDir, "user_swagger.json"))
|
||||
require.NoError(t, err)
|
||||
expectedJSON, err := os.ReadFile(filepath.Join(config.SearchDir, "user_expected.json"))
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.JSONEq(t, string(expectedJSON), string(jsonOutput))
|
||||
}
|
||||
Reference in New Issue
Block a user