From 51e1f62b04f472c14125a826f3c362de5bd34e5f Mon Sep 17 00:00:00 2001 From: Dave Shanley Date: Sat, 27 Aug 2022 12:48:58 -0400 Subject: [PATCH] Test coverage for v3 model is now at 100% This should be very easy to duplicate to 2.0 and 3.1, now extraction code needs testing. Signed-off-by: Dave Shanley --- README.md | 1 + datamodel/high/3.0/components.go | 27 -- datamodel/high/3.0/document.go | 11 +- datamodel/high/3.0/document_test.go | 32 +- datamodel/high/3.0/info.go | 16 +- datamodel/high/3.0/schema.go | 8 +- datamodel/high/3.0/schema_proxy.go | 2 +- datamodel/high/3.0/schema_test.go | 78 ++-- datamodel/low/3.0/components.go | 32 -- datamodel/low/3.0/create_document.go | 1 - datamodel/low/3.0/create_document_test.go | 17 +- datamodel/low/3.0/schema.go | 13 - datamodel/low/3.0/schema_test.go | 33 +- datamodel/low/3.0/server_variable.go | 8 +- datamodel/model_utils.go | 300 ++++++------ datamodel/model_utils_test.go | 164 +++---- datamodel/spec_info.go | 30 +- libopenapi.go | 2 +- utils/utils_test.go | 528 +++++++++++----------- 19 files changed, 634 insertions(+), 669 deletions(-) diff --git a/README.md b/README.md index 71a9c25..60e8db4 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,3 @@ # libopenapi + A place for up to date, modern golang OpenAPI models and utilities. diff --git a/datamodel/high/3.0/components.go b/datamodel/high/3.0/components.go index 2a0af58..119df87 100644 --- a/datamodel/high/3.0/components.go +++ b/datamodel/high/3.0/components.go @@ -7,7 +7,6 @@ import ( "github.com/pb33f/libopenapi/datamodel/high" lowmodel "github.com/pb33f/libopenapi/datamodel/low" low "github.com/pb33f/libopenapi/datamodel/low/3.0" - "sync" ) const ( @@ -21,31 +20,6 @@ const ( callbacks ) -var seenSchemas map[string]*Schema - -func init() { - clearSchemas() -} - -func clearSchemas() { - seenSchemas = make(map[string]*Schema) -} - -var seenSchemaLock sync.RWMutex - -func addSeenSchema(key string, schema *Schema) { - defer seenSchemaLock.Unlock() - seenSchemaLock.Lock() - if seenSchemas[key] == nil { - seenSchemas[key] = schema - } -} -func getSeenSchema(key string) *Schema { - defer seenSchemaLock.Unlock() - seenSchemaLock.Lock() - return seenSchemas[key] -} - type Components struct { Schemas map[string]*SchemaProxy Responses map[string]*Response @@ -110,7 +84,6 @@ func NewComponents(comp *low.Components) *Components { go buildComponent[*SecurityScheme, *low.SecurityScheme](securitySchemes, k.Value, v.Value, securitySchemeChan, NewSecurityScheme) } - for k, v := range comp.Schemas.Value { go buildSchema(k, v, schemaChan) } diff --git a/datamodel/high/3.0/document.go b/datamodel/high/3.0/document.go index 3db0b56..6fc9bec 100644 --- a/datamodel/high/3.0/document.go +++ b/datamodel/high/3.0/document.go @@ -6,6 +6,7 @@ package v3 import ( "github.com/pb33f/libopenapi/datamodel/high" low "github.com/pb33f/libopenapi/datamodel/low/3.0" + "github.com/pb33f/libopenapi/index" ) type Document struct { @@ -18,14 +19,19 @@ type Document struct { Tags []*Tag ExternalDocs *ExternalDoc Extensions map[string]any + Index *index.SpecIndex low *low.Document } func NewDocument(document *low.Document) *Document { d := new(Document) d.low = document - d.Info = NewInfo(document.Info.Value) - d.Version = document.Version.Value + if !document.Info.IsEmpty() { + d.Info = NewInfo(document.Info.Value) + } + if !document.Version.IsEmpty() { + d.Version = document.Version.Value + } var servers []*Server for _, ser := range document.Servers.Value { servers = append(servers, NewServer(ser.Value)) @@ -42,6 +48,7 @@ func NewDocument(document *low.Document) *Document { d.Extensions = high.ExtractExtensions(document.Extensions) d.Components = NewComponents(document.Components.Value) d.Paths = NewPaths(document.Paths.Value) + d.Index = document.Index return d } diff --git a/datamodel/high/3.0/document_test.go b/datamodel/high/3.0/document_test.go index 985e8c5..0a8a897 100644 --- a/datamodel/high/3.0/document_test.go +++ b/datamodel/high/3.0/document_test.go @@ -14,7 +14,7 @@ import ( var doc *lowv3.Document -func init() { +func initTest() { data, _ := ioutil.ReadFile("../../../test_specs/burgershop.openapi.yaml") info, _ := datamodel.ExtractSpecInfo(data) var err []error @@ -25,22 +25,26 @@ func init() { } func BenchmarkNewDocument(b *testing.B) { + initTest() for i := 0; i < b.N; i++ { _ = NewDocument(doc) } } func TestNewDocument_Extensions(t *testing.T) { + initTest() h := NewDocument(doc) assert.Equal(t, "darkside", h.Extensions["x-something-something"]) } func TestNewDocument_ExternalDocs(t *testing.T) { + initTest() h := NewDocument(doc) assert.Equal(t, "https://pb33f.io", h.ExternalDocs.URL) } func TestNewDocument_Info(t *testing.T) { + initTest() highDoc := NewDocument(doc) assert.Equal(t, "3.0.1", highDoc.Version) assert.Equal(t, "Burger Shop", highDoc.Info.Title) @@ -71,6 +75,7 @@ func TestNewDocument_Info(t *testing.T) { } func TestNewDocument_Servers(t *testing.T) { + initTest() h := NewDocument(doc) assert.Len(t, h.Servers, 2) assert.Equal(t, "{scheme}://api.pb33f.io", h.Servers[0].URL) @@ -102,6 +107,7 @@ func TestNewDocument_Servers(t *testing.T) { } func TestNewDocument_Tags(t *testing.T) { + initTest() h := NewDocument(doc) assert.Len(t, h.Tags, 2) assert.Equal(t, "Burgers", h.Tags[0].Name) @@ -123,6 +129,7 @@ func TestNewDocument_Tags(t *testing.T) { } func TestNewDocument_Components_Links(t *testing.T) { + initTest() h := NewDocument(doc) assert.Len(t, h.Components.Links, 2) assert.Equal(t, "locateBurger", h.Components.Links["LocateBurger"].OperationId) @@ -135,6 +142,7 @@ func TestNewDocument_Components_Links(t *testing.T) { } func TestNewDocument_Components_Callbacks(t *testing.T) { + initTest() h := NewDocument(doc) assert.Len(t, h.Components.Callbacks, 1) assert.Equal(t, "Callback payload", @@ -156,6 +164,7 @@ func TestNewDocument_Components_Callbacks(t *testing.T) { } func TestNewDocument_Components_Schemas(t *testing.T) { + initTest() h := NewDocument(doc) assert.Len(t, h.Components.Schemas, 6) @@ -197,6 +206,7 @@ func TestNewDocument_Components_Schemas(t *testing.T) { } func TestNewDocument_Components_Headers(t *testing.T) { + initTest() h := NewDocument(doc) assert.Len(t, h.Components.Headers, 1) assert.Equal(t, "this is a header", h.Components.Headers["UseOil"].Description) @@ -205,6 +215,7 @@ func TestNewDocument_Components_Headers(t *testing.T) { } func TestNewDocument_Components_RequestBodies(t *testing.T) { + initTest() h := NewDocument(doc) assert.Len(t, h.Components.RequestBodies, 1) assert.Equal(t, "Give us the new burger!", h.Components.RequestBodies["BurgerRequest"].Description) @@ -214,6 +225,7 @@ func TestNewDocument_Components_RequestBodies(t *testing.T) { } func TestNewDocument_Components_Examples(t *testing.T) { + initTest() h := NewDocument(doc) assert.Len(t, h.Components.Examples, 1) assert.Equal(t, "A juicy two hander sammich", h.Components.Examples["QuarterPounder"].Summary) @@ -223,6 +235,7 @@ func TestNewDocument_Components_Examples(t *testing.T) { } func TestNewDocument_Components_Responses(t *testing.T) { + initTest() h := NewDocument(doc) assert.Len(t, h.Components.Responses, 1) assert.Equal(t, "all the dressings for a burger.", h.Components.Responses["DressingResponse"].Description) @@ -232,6 +245,7 @@ func TestNewDocument_Components_Responses(t *testing.T) { } func TestNewDocument_Components_SecuritySchemes(t *testing.T) { + initTest() h := NewDocument(doc) assert.Len(t, h.Components.SecuritySchemes, 3) @@ -262,6 +276,7 @@ func TestNewDocument_Components_SecuritySchemes(t *testing.T) { } func TestNewDocument_Components_Parameters(t *testing.T) { + initTest() h := NewDocument(doc) assert.Len(t, h.Components.Parameters, 2) bh := h.Components.Parameters["BurgerHeader"] @@ -278,6 +293,7 @@ func TestNewDocument_Components_Parameters(t *testing.T) { } func TestNewDocument_Paths(t *testing.T) { + initTest() h := NewDocument(doc) assert.Len(t, h.Paths.PathItems, 5) @@ -323,7 +339,6 @@ func TestNewDocument_Paths(t *testing.T) { } func TestStripeAsDoc(t *testing.T) { - data, _ := ioutil.ReadFile("../../../test_specs/stripe.yaml") info, _ := datamodel.ExtractSpecInfo(data) var err []error @@ -334,3 +349,16 @@ func TestStripeAsDoc(t *testing.T) { d := NewDocument(doc) fmt.Println(d) } + +func TestCircularReferencesDoc(t *testing.T) { + data, _ := ioutil.ReadFile("../../../test_specs/circular-tests.yaml") + info, _ := datamodel.ExtractSpecInfo(data) + var err []error + doc, err = lowv3.CreateDocument(info) + if err != nil { + panic("broken something") + } + d := NewDocument(doc) + assert.Len(t, d.Components.Schemas, 9) + assert.Len(t, d.Index.GetCircularReferences(), 3) +} diff --git a/datamodel/high/3.0/info.go b/datamodel/high/3.0/info.go index 0d5f861..c095849 100644 --- a/datamodel/high/3.0/info.go +++ b/datamodel/high/3.0/info.go @@ -18,16 +18,24 @@ type Info struct { func NewInfo(info *low.Info) *Info { i := new(Info) i.low = info - i.Title = info.Title.Value - i.Description = info.Description.Value - i.TermsOfService = info.TermsOfService.Value + if !info.Title.IsEmpty() { + i.Title = info.Title.Value + } + if !info.Description.IsEmpty() { + i.Description = info.Description.Value + } + if !info.TermsOfService.IsEmpty() { + i.TermsOfService = info.TermsOfService.Value + } if !info.Contact.IsEmpty() { i.Contact = NewContact(info.Contact.Value) } if !info.License.IsEmpty() { i.License = NewLicense(info.License.Value) } - i.Version = info.Version.Value + if !info.Version.IsEmpty() { + i.Version = info.Version.Value + } return i } diff --git a/datamodel/high/3.0/schema.go b/datamodel/high/3.0/schema.go index 209d1e7..a1d068e 100644 --- a/datamodel/high/3.0/schema.go +++ b/datamodel/high/3.0/schema.go @@ -111,10 +111,9 @@ func NewSchema(schema *low.Schema) *Schema { buildOutSchema := func(schemas []lowmodel.ValueReference[*low.SchemaProxy], items *[]*SchemaProxy, doneChan chan bool, e chan error) { bChan := make(chan *SchemaProxy) - eChan := make(chan error) // for every item, build schema async - buildSchemaChild := func(sch lowmodel.ValueReference[*low.SchemaProxy], bChan chan *SchemaProxy, e chan error) { + buildSchemaChild := func(sch lowmodel.ValueReference[*low.SchemaProxy], bChan chan *SchemaProxy) { p := &SchemaProxy{schema: &lowmodel.NodeReference[*low.SchemaProxy]{ ValueNode: sch.ValueNode, Value: sch.Value, @@ -123,14 +122,11 @@ func NewSchema(schema *low.Schema) *Schema { } totalSchemas := len(schemas) for v := range schemas { - go buildSchemaChild(schemas[v], bChan, eChan) + go buildSchemaChild(schemas[v], bChan) } j := 0 for j < totalSchemas { select { - case er := <-eChan: - e <- er - return case t := <-bChan: j++ *items = append(*items, t) diff --git a/datamodel/high/3.0/schema_proxy.go b/datamodel/high/3.0/schema_proxy.go index fa9bd57..5cdf87f 100644 --- a/datamodel/high/3.0/schema_proxy.go +++ b/datamodel/high/3.0/schema_proxy.go @@ -16,7 +16,7 @@ type SchemaProxy struct { func (sp *SchemaProxy) Schema() *Schema { s := sp.schema.Value.Schema() if s == nil { - sp.buildError = sp.GetBuildError() + sp.buildError = sp.schema.Value.GetBuildError() return nil } return NewSchema(s) diff --git a/datamodel/high/3.0/schema_test.go b/datamodel/high/3.0/schema_test.go index 075f04e..22e92d3 100644 --- a/datamodel/high/3.0/schema_test.go +++ b/datamodel/high/3.0/schema_test.go @@ -4,50 +4,52 @@ package v3 import ( - "github.com/pb33f/libopenapi/datamodel/low" - v3 "github.com/pb33f/libopenapi/datamodel/low/3.0" - "github.com/pb33f/libopenapi/index" - "github.com/stretchr/testify/assert" - "gopkg.in/yaml.v3" - "testing" + "github.com/pb33f/libopenapi/datamodel/low" + v3 "github.com/pb33f/libopenapi/datamodel/low/3.0" + "github.com/pb33f/libopenapi/index" + "github.com/stretchr/testify/assert" + "gopkg.in/yaml.v3" + "testing" ) -func TestNewSchema(t *testing.T) { +func TestNewSchemaProxy(t *testing.T) { - // tests async schema lookup, by essentially running it twice, without a cache cleanup. - yml := `components: - schemas: + // check proxy + yml := `components: + schemas: + rice: + type: string + nice: + properties: + rice: + $ref: '#/components/schemas/rice' + ice: + properties: + rice: + $ref: '#/components/schemas/rice'` + + var idxNode, compNode yaml.Node + mErr := yaml.Unmarshal([]byte(yml), &idxNode) + assert.NoError(t, mErr) + idx := index.NewSpecIndex(&idxNode) + + yml = `properties: rice: - type: string - nice: - properties: - rice: - $ref: '#/components/schemas/rice' - ice: - properties: - rice: - $ref: '#/components/schemas/rice'` + $ref: '#/components/schemas/I-do-not-exist'` - var idxNode, compNode yaml.Node - mErr := yaml.Unmarshal([]byte(yml), &idxNode) - assert.NoError(t, mErr) - idx := index.NewSpecIndex(&idxNode) + _ = yaml.Unmarshal([]byte(yml), &compNode) - yml = `properties: - rice: - $ref: '#/components/schemas/rice'` + sp := new(v3.SchemaProxy) + err := sp.Build(compNode.Content[0], idx) + assert.NoError(t, err) - var n v3.Schema - _ = yaml.Unmarshal([]byte(yml), &compNode) - err := low.BuildModel(&idxNode, &n) - assert.NoError(t, err) + lowproxy := low.NodeReference[*v3.SchemaProxy]{ + Value: sp, + ValueNode: idxNode.Content[0], + } - err = n.Build(idxNode.Content[0], idx) - assert.NoError(t, err) + sch1 := SchemaProxy{schema: &lowproxy} + assert.Nil(t, sch1.Schema()) + assert.Error(t, sch1.GetBuildError()) - sch1 := NewSchema(&n) - sch2 := NewSchema(&n) - - assert.Equal(t, sch1, sch2) - -} \ No newline at end of file +} diff --git a/datamodel/low/3.0/components.go b/datamodel/low/3.0/components.go index bcfbd33..0a1b7a6 100644 --- a/datamodel/low/3.0/components.go +++ b/datamodel/low/3.0/components.go @@ -10,7 +10,6 @@ import ( "github.com/pb33f/libopenapi/utils" "gopkg.in/yaml.v3" "strings" - "sync" ) const ( @@ -18,31 +17,6 @@ const ( SchemasLabel = "schemas" ) -var seenSchemas map[string]*Schema - -func init() { - clearSchemas() -} - -func clearSchemas() { - seenSchemas = make(map[string]*Schema) -} - -var seenSchemaLock sync.RWMutex - -func addSeenSchema(key string, schema *Schema) { - defer seenSchemaLock.Unlock() - seenSchemaLock.Lock() - if seenSchemas[key] == nil { - seenSchemas[key] = schema - } -} -func getSeenSchema(key string) *Schema { - defer seenSchemaLock.Unlock() - seenSchemaLock.Lock() - return seenSchemas[key] -} - type Components struct { Schemas low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*SchemaProxy]] Responses low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*Response]] @@ -163,12 +137,6 @@ func (co *Components) Build(root *yaml.Node, idx *index.SpecIndex) error { return nil } -func cacheSchemas(sch map[low.KeyReference[string]]low.ValueReference[*Schema]) { - for _, v := range sch { - addSeenSchema(v.GenerateMapKey(), v.Value) - } -} - type componentBuildResult[T any] struct { k low.KeyReference[string] v low.ValueReference[T] diff --git a/datamodel/low/3.0/create_document.go b/datamodel/low/3.0/create_document.go index f0d556b..465211e 100644 --- a/datamodel/low/3.0/create_document.go +++ b/datamodel/low/3.0/create_document.go @@ -12,7 +12,6 @@ import ( func CreateDocument(info *datamodel.SpecInfo) (*Document, []error) { // clean state - clearSchemas() doc := Document{Version: low.ValueReference[string]{Value: info.Version, ValueNode: info.RootNode}} // build an index diff --git a/datamodel/low/3.0/create_document_test.go b/datamodel/low/3.0/create_document_test.go index fd5f12a..18f60d4 100644 --- a/datamodel/low/3.0/create_document_test.go +++ b/datamodel/low/3.0/create_document_test.go @@ -188,8 +188,8 @@ func TestCreateDocument_Paths(t *testing.T) { assert.Len(t, burgerId.Value.Get.Value.Parameters.Value, 2) param := burgerId.Value.Get.Value.Parameters.Value[1] assert.Equal(t, "burgerHeader", param.Value.Name.Value) - prop := param.Value.Schema.Value.Schema().FindProperty("burgerTheme") - assert.Equal(t, "something about a theme?", prop.Value.Schema().Description.Value) + prop := param.Value.Schema.Value.Schema().FindProperty("burgerTheme").Value + assert.Equal(t, "something about a theme?", prop.Schema().Description.Value) assert.Equal(t, "big-mac", param.Value.Example.Value) // check content @@ -502,6 +502,19 @@ func TestCreateDocument_Components_Error(t *testing.T) { assert.Error(t, ob.GetBuildError()) } +func TestCreateDocument_Components_Error_Extract(t *testing.T) { + yml := `components: + parameters: + bork: + $ref: #bork` + + info, _ := datamodel.ExtractSpecInfo([]byte(yml)) + var err []error + doc, err = CreateDocument(info) + assert.Len(t, err, 1) + +} + func TestCreateDocument_Paths_Errors(t *testing.T) { yml := `paths: /p: diff --git a/datamodel/low/3.0/schema.go b/datamodel/low/3.0/schema.go index e85330e..713f420 100644 --- a/datamodel/low/3.0/schema.go +++ b/datamodel/low/3.0/schema.go @@ -65,19 +65,6 @@ func (s *Schema) FindProperty(name string) *low.ValueReference[*SchemaProxy] { } func (s *Schema) Build(root *yaml.Node, idx *index.SpecIndex) error { - return s.BuildLevel(root, idx, 0) -} - -func (s *Schema) BuildLevel(root *yaml.Node, idx *index.SpecIndex, level int) error { - - if low.IsCircular(root, idx) { - return nil // circular references cannot be built. - } - - if level > 30 { - return fmt.Errorf("schema is too nested to continue: %d levels deep, is too deep", level) // we're done, son! too fricken deep. - } - level++ if h, _, _ := utils.IsNodeRefValue(root); h { ref := low.LocateRefNode(root, idx) if ref != nil { diff --git a/datamodel/low/3.0/schema_test.go b/datamodel/low/3.0/schema_test.go index 2c1c7da..244b653 100644 --- a/datamodel/low/3.0/schema_test.go +++ b/datamodel/low/3.0/schema_test.go @@ -9,7 +9,6 @@ import ( ) func Test_Schema(t *testing.T) { - clearSchemas() testSpec := `type: object description: something object discriminator: @@ -225,7 +224,7 @@ additionalProperties: true ` } //func TestSchema_BuildLevel_TooDeep(t *testing.T) { -// clearSchemas() +// // // if you design data models like this, you're doing it fucking wrong. Seriously. why, what is so complex about a model // // that it needs to be 30+ levels deep? I have seen this shit in the wild, it's unreadable, un-parsable garbage. // yml := `type: object @@ -343,7 +342,7 @@ additionalProperties: true ` //} func TestSchema_Build_ErrorAdditionalProps(t *testing.T) { - clearSchemas() + yml := `additionalProperties: $ref: #borko` @@ -361,7 +360,7 @@ func TestSchema_Build_ErrorAdditionalProps(t *testing.T) { } func TestSchema_Build_PropsLookup(t *testing.T) { - clearSchemas() + yml := `components: schemas: Something: @@ -389,7 +388,7 @@ properties: } func TestSchema_Build_PropsLookup_Fail(t *testing.T) { - clearSchemas() + yml := `components: schemas: Something: @@ -416,7 +415,7 @@ properties: } func Test_Schema_Polymorphism_Array_Ref(t *testing.T) { - clearSchemas() + yml := `components: schemas: Something: @@ -464,7 +463,7 @@ items: } func Test_Schema_Polymorphism_Array_Ref_Fail(t *testing.T) { - clearSchemas() + yml := `components: schemas: Something: @@ -506,7 +505,7 @@ items: } func Test_Schema_Polymorphism_Map_Ref(t *testing.T) { - clearSchemas() + yml := `components: schemas: Something: @@ -554,7 +553,7 @@ items: } func Test_Schema_Polymorphism_Map_Ref_Fail(t *testing.T) { - clearSchemas() + yml := `components: schemas: Something: @@ -596,7 +595,6 @@ items: } func Test_Schema_Polymorphism_BorkParent(t *testing.T) { - clearSchemas() yml := `components: schemas: @@ -625,7 +623,6 @@ allOf: } func Test_Schema_Polymorphism_BorkChild(t *testing.T) { - clearSchemas() yml := `components: schemas: @@ -654,7 +651,6 @@ allOf: } func Test_Schema_Polymorphism_BorkChild_Array(t *testing.T) { - clearSchemas() yml := `components: schemas: @@ -687,7 +683,6 @@ allOf: } func Test_Schema_Polymorphism_RefMadness(t *testing.T) { - clearSchemas() yml := `components: schemas: @@ -721,7 +716,6 @@ allOf: } func Test_Schema_Polymorphism_RefMadnessBork(t *testing.T) { - clearSchemas() yml := `components: schemas: @@ -752,7 +746,6 @@ allOf: } func Test_Schema_Polymorphism_RefMadnessIllegal(t *testing.T) { - clearSchemas() // this does not work, but it won't error out. @@ -783,7 +776,6 @@ func Test_Schema_Polymorphism_RefMadnessIllegal(t *testing.T) { } func TestExtractSchema(t *testing.T) { - clearSchemas() yml := `components: schemas: @@ -813,7 +805,6 @@ func TestExtractSchema(t *testing.T) { } func TestExtractSchema_Ref(t *testing.T) { - clearSchemas() yml := `components: schemas: @@ -839,7 +830,6 @@ func TestExtractSchema_Ref(t *testing.T) { } func TestExtractSchema_Ref_Fail(t *testing.T) { - clearSchemas() yml := `components: schemas: @@ -863,7 +853,6 @@ func TestExtractSchema_Ref_Fail(t *testing.T) { } func TestExtractSchema_RefRoot(t *testing.T) { - clearSchemas() yml := `components: schemas: @@ -888,7 +877,6 @@ func TestExtractSchema_RefRoot(t *testing.T) { } func TestExtractSchema_RefRoot_Fail(t *testing.T) { - clearSchemas() yml := `components: schemas: @@ -912,7 +900,6 @@ func TestExtractSchema_RefRoot_Fail(t *testing.T) { } func TestExtractSchema_RefRoot_Child_Fail(t *testing.T) { - clearSchemas() yml := `components: schemas: @@ -939,8 +926,6 @@ func TestExtractSchema_RefRoot_Child_Fail(t *testing.T) { func TestExtractSchema_DoNothing(t *testing.T) { - clearSchemas() - yml := `components: schemas: Something: @@ -964,8 +949,6 @@ func TestExtractSchema_DoNothing(t *testing.T) { func TestExtractSchema_OneOfRef(t *testing.T) { - clearSchemas() - yml := `components: schemas: Error: diff --git a/datamodel/low/3.0/server_variable.go b/datamodel/low/3.0/server_variable.go index 4d7f5af..ec18ac9 100644 --- a/datamodel/low/3.0/server_variable.go +++ b/datamodel/low/3.0/server_variable.go @@ -1,11 +1,11 @@ package v3 import ( - "github.com/pb33f/libopenapi/datamodel/low" + "github.com/pb33f/libopenapi/datamodel/low" ) type ServerVariable struct { - Enum []low.NodeReference[string] - Default low.NodeReference[string] - Description low.NodeReference[string] + Enum []low.NodeReference[string] + Default low.NodeReference[string] + Description low.NodeReference[string] } diff --git a/datamodel/model_utils.go b/datamodel/model_utils.go index 697651f..cce4a0f 100644 --- a/datamodel/model_utils.go +++ b/datamodel/model_utils.go @@ -1,19 +1,19 @@ package datamodel import ( - _ "embed" - "encoding/json" - "errors" - "fmt" - "github.com/pb33f/libopenapi/utils" - "gopkg.in/yaml.v3" - "strings" + _ "embed" + "encoding/json" + "errors" + "fmt" + "github.com/pb33f/libopenapi/utils" + "gopkg.in/yaml.v3" + "strings" ) const ( - OAS2 = "oas2" - OAS3 = "oas3" - OAS31 = "oas3_1" + OAS2 = "oas2" + OAS3 = "oas3" + OAS31 = "oas3_1" ) //go:embed schemas/oas3-schema.json @@ -32,181 +32,181 @@ var AllFormats = []string{OAS3, OAS31, OAS2} // if the spec cannot be parsed correctly. func ExtractSpecInfo(spec []byte) (*SpecInfo, error) { - var parsedSpec yaml.Node + var parsedSpec yaml.Node - specVersion := &SpecInfo{} - specVersion.JsonParsingChannel = make(chan bool) + specVersion := &SpecInfo{} + specVersion.JsonParsingChannel = make(chan bool) - // set original bytes - specVersion.SpecBytes = &spec + // set original bytes + specVersion.SpecBytes = &spec - runes := []rune(strings.TrimSpace(string(spec))) - if len(runes) <= 0 { - return specVersion, errors.New("there are no runes in the spec") - } + runes := []rune(strings.TrimSpace(string(spec))) + if len(runes) <= 0 { + return specVersion, errors.New("there are no runes in the spec") + } - if runes[0] == '{' && runes[len(runes)-1] == '}' { - specVersion.SpecFileType = "json" - } else { - specVersion.SpecFileType = "yaml" - } + if runes[0] == '{' && runes[len(runes)-1] == '}' { + specVersion.SpecFileType = "json" + } else { + specVersion.SpecFileType = "yaml" + } - err := yaml.Unmarshal(spec, &parsedSpec) - if err != nil { - return nil, fmt.Errorf("unable to parse specification: %s", err.Error()) - } + err := yaml.Unmarshal(spec, &parsedSpec) + if err != nil { + return nil, fmt.Errorf("unable to parse specification: %s", err.Error()) + } - specVersion.RootNode = &parsedSpec + specVersion.RootNode = &parsedSpec - _, openAPI3 := utils.FindKeyNode(utils.OpenApi3, parsedSpec.Content) - _, openAPI2 := utils.FindKeyNode(utils.OpenApi2, parsedSpec.Content) - _, asyncAPI := utils.FindKeyNode(utils.AsyncApi, parsedSpec.Content) + _, openAPI3 := utils.FindKeyNode(utils.OpenApi3, parsedSpec.Content) + _, openAPI2 := utils.FindKeyNode(utils.OpenApi2, parsedSpec.Content) + _, asyncAPI := utils.FindKeyNode(utils.AsyncApi, parsedSpec.Content) - parseJSON := func(bytes []byte, spec *SpecInfo) { - var jsonSpec map[string]interface{} + parseJSON := func(bytes []byte, spec *SpecInfo) { + var jsonSpec map[string]interface{} - // no point in worrying about errors here, extract JSON friendly format. - // run in a separate thread, don't block. + // no point in worrying about errors here, extract JSON friendly format. + // run in a separate thread, don't block. - if spec.SpecType == utils.OpenApi3 { - spec.APISchema = OpenAPI3SchemaData - } - if spec.SpecType == utils.OpenApi2 { - spec.APISchema = OpenAPI2SchemaData - } + if spec.SpecType == utils.OpenApi3 { + spec.APISchema = OpenAPI3SchemaData + } + if spec.SpecType == utils.OpenApi2 { + spec.APISchema = OpenAPI2SchemaData + } - if utils.IsYAML(string(bytes)) { - yaml.Unmarshal(bytes, &jsonSpec) - jsonData, _ := json.Marshal(jsonSpec) - spec.SpecJSONBytes = &jsonData - spec.SpecJSON = &jsonSpec - } else { - json.Unmarshal(bytes, &jsonSpec) - spec.SpecJSONBytes = &bytes - spec.SpecJSON = &jsonSpec - } - spec.JsonParsingChannel <- true - close(spec.JsonParsingChannel) - } - // check for specific keys - if openAPI3 != nil { - specVersion.SpecType = utils.OpenApi3 - version, majorVersion := parseVersionTypeData(openAPI3.Value) + if utils.IsYAML(string(bytes)) { + yaml.Unmarshal(bytes, &jsonSpec) + jsonData, _ := json.Marshal(jsonSpec) + spec.SpecJSONBytes = &jsonData + spec.SpecJSON = &jsonSpec + } else { + json.Unmarshal(bytes, &jsonSpec) + spec.SpecJSONBytes = &bytes + spec.SpecJSON = &jsonSpec + } + spec.JsonParsingChannel <- true + close(spec.JsonParsingChannel) + } + // check for specific keys + if openAPI3 != nil { + specVersion.SpecType = utils.OpenApi3 + version, majorVersion := parseVersionTypeData(openAPI3.Value) - // parse JSON - go parseJSON(spec, specVersion) + // parse JSON + go parseJSON(spec, specVersion) - // double check for the right version, people mix this up. - if majorVersion < 3 { - specVersion.Error = errors.New("spec is defined as an openapi spec, but is using a swagger (2.0), or unknown version") - return specVersion, specVersion.Error - } - specVersion.Version = version - specVersion.SpecFormat = OAS3 - } - if openAPI2 != nil { - specVersion.SpecType = utils.OpenApi2 - version, majorVersion := parseVersionTypeData(openAPI2.Value) + // double check for the right version, people mix this up. + if majorVersion < 3 { + specVersion.Error = errors.New("spec is defined as an openapi spec, but is using a swagger (2.0), or unknown version") + return specVersion, specVersion.Error + } + specVersion.Version = version + specVersion.SpecFormat = OAS3 + } + if openAPI2 != nil { + specVersion.SpecType = utils.OpenApi2 + version, majorVersion := parseVersionTypeData(openAPI2.Value) - // parse JSON - go parseJSON(spec, specVersion) + // parse JSON + go parseJSON(spec, specVersion) - // I am not certain this edge-case is very frequent, but let's make sure we handle it anyway. - if majorVersion > 2 { - specVersion.Error = errors.New("spec is defined as a swagger (openapi 2.0) spec, but is an openapi 3 or unknown version") - return specVersion, specVersion.Error - } - specVersion.Version = version - specVersion.SpecFormat = OAS2 - } - if asyncAPI != nil { - specVersion.SpecType = utils.AsyncApi - version, majorVersion := parseVersionTypeData(asyncAPI.Value) + // I am not certain this edge-case is very frequent, but let's make sure we handle it anyway. + if majorVersion > 2 { + specVersion.Error = errors.New("spec is defined as a swagger (openapi 2.0) spec, but is an openapi 3 or unknown version") + return specVersion, specVersion.Error + } + specVersion.Version = version + specVersion.SpecFormat = OAS2 + } + if asyncAPI != nil { + specVersion.SpecType = utils.AsyncApi + version, majorVersion := parseVersionTypeData(asyncAPI.Value) - // parse JSON - go parseJSON(spec, specVersion) + // parse JSON + go parseJSON(spec, specVersion) - // so far there is only 2 as a major release of AsyncAPI - if majorVersion > 2 { - specVersion.Error = errors.New("spec is defined as asyncapi, but has a major version that is invalid") - return specVersion, specVersion.Error - } - specVersion.Version = version - // TODO: format for AsyncAPI. + // so far there is only 2 as a major release of AsyncAPI + if majorVersion > 2 { + specVersion.Error = errors.New("spec is defined as asyncapi, but has a major version that is invalid") + return specVersion, specVersion.Error + } + specVersion.Version = version + // TODO: format for AsyncAPI. - } + } - if specVersion.SpecType == "" { + if specVersion.SpecType == "" { - // parse JSON - go parseJSON(spec, specVersion) + // parse JSON + go parseJSON(spec, specVersion) - specVersion.Error = errors.New("spec type not supported by vacuum, sorry") - return specVersion, specVersion.Error - } + specVersion.Error = errors.New("spec type not supported by vacuum, sorry") + return specVersion, specVersion.Error + } - return specVersion, nil + return specVersion, nil } func parseVersionTypeData(d interface{}) (string, int) { - r := []rune(strings.TrimSpace(fmt.Sprintf("%v", d))) - return string(r), int(r[0]) - '0' + r := []rune(strings.TrimSpace(fmt.Sprintf("%v", d))) + return string(r), int(r[0]) - '0' } // AreValuesCorrectlyTyped will look through an array of unknown values and check they match // against the supplied type as a string. The return value is empty if everything is OK, or it // contains failures in the form of a value as a key and a message as to why it's not valid func AreValuesCorrectlyTyped(valType string, values interface{}) map[string]string { - var arr []interface{} - if _, ok := values.([]interface{}); !ok { - return nil - } - arr = values.([]interface{}) + var arr []interface{} + if _, ok := values.([]interface{}); !ok { + return nil + } + arr = values.([]interface{}) - results := make(map[string]string) - for _, v := range arr { - switch v.(type) { - case string: - if valType != "string" { - results[v.(string)] = fmt.Sprintf("enum value '%v' is a "+ - "string, but it's defined as a '%v'", v, valType) - } - case int64: - if valType != "integer" && valType != "number" { - results[fmt.Sprintf("%v", v)] = fmt.Sprintf("enum value '%v' is a "+ - "integer, but it's defined as a '%v'", v, valType) - } - case int: - if valType != "integer" && valType != "number" { - results[fmt.Sprintf("%v", v)] = fmt.Sprintf("enum value '%v' is a "+ - "integer, but it's defined as a '%v'", v, valType) - } - case float64: - if valType != "number" { - results[fmt.Sprintf("%v", v)] = fmt.Sprintf("enum value '%v' is a "+ - "number, but it's defined as a '%v'", v, valType) - } - case bool: - if valType != "boolean" { - results[fmt.Sprintf("%v", v)] = fmt.Sprintf("enum value '%v' is a "+ - "boolean, but it's defined as a '%v'", v, valType) - } - } - } - return results + results := make(map[string]string) + for _, v := range arr { + switch v.(type) { + case string: + if valType != "string" { + results[v.(string)] = fmt.Sprintf("enum value '%v' is a "+ + "string, but it's defined as a '%v'", v, valType) + } + case int64: + if valType != "integer" && valType != "number" { + results[fmt.Sprintf("%v", v)] = fmt.Sprintf("enum value '%v' is a "+ + "integer, but it's defined as a '%v'", v, valType) + } + case int: + if valType != "integer" && valType != "number" { + results[fmt.Sprintf("%v", v)] = fmt.Sprintf("enum value '%v' is a "+ + "integer, but it's defined as a '%v'", v, valType) + } + case float64: + if valType != "number" { + results[fmt.Sprintf("%v", v)] = fmt.Sprintf("enum value '%v' is a "+ + "number, but it's defined as a '%v'", v, valType) + } + case bool: + if valType != "boolean" { + results[fmt.Sprintf("%v", v)] = fmt.Sprintf("enum value '%v' is a "+ + "boolean, but it's defined as a '%v'", v, valType) + } + } + } + return results } // CheckEnumForDuplicates will check an array of nodes to check if there are any duplicates. func CheckEnumForDuplicates(seq []*yaml.Node) []*yaml.Node { - var res []*yaml.Node - seen := make(map[string]*yaml.Node) + var res []*yaml.Node + seen := make(map[string]*yaml.Node) - for _, enum := range seq { - if seen[enum.Value] != nil { - res = append(res, enum) - continue - } - seen[enum.Value] = enum - } - return res + for _, enum := range seq { + if seen[enum.Value] != nil { + res = append(res, enum) + continue + } + seen[enum.Value] = enum + } + return res } diff --git a/datamodel/model_utils_test.go b/datamodel/model_utils_test.go index 00d841d..bd06957 100644 --- a/datamodel/model_utils_test.go +++ b/datamodel/model_utils_test.go @@ -1,21 +1,21 @@ package datamodel import ( - "github.com/pb33f/libopenapi/utils" - "github.com/stretchr/testify/assert" - "gopkg.in/yaml.v3" - "testing" + "github.com/pb33f/libopenapi/utils" + "github.com/stretchr/testify/assert" + "gopkg.in/yaml.v3" + "testing" ) const ( - // OpenApi3 is used by all OpenAPI 3+ docs - OpenApi3 = "openapi" + // OpenApi3 is used by all OpenAPI 3+ docs + OpenApi3 = "openapi" - // OpenApi2 is used by all OpenAPI 2 docs, formerly known as swagger. - OpenApi2 = "swagger" + // OpenApi2 is used by all OpenAPI 2 docs, formerly known as swagger. + OpenApi2 = "swagger" - // AsyncApi is used by akk AsyncAPI docs, all versions. - AsyncApi = "asyncapi" + // AsyncApi is used by akk AsyncAPI docs, all versions. + AsyncApi = "asyncapi" ) var goodJSON = `{"name":"kitty", "noises":["meow","purrrr","gggrrraaaaaooooww"]}` @@ -95,140 +95,140 @@ info: version: '0.1.0'` func TestExtractSpecInfo_ValidJSON(t *testing.T) { - _, e := ExtractSpecInfo([]byte(goodJSON)) - assert.Error(t, e) + _, e := ExtractSpecInfo([]byte(goodJSON)) + assert.Error(t, e) } func TestExtractSpecInfo_InvalidJSON(t *testing.T) { - _, e := ExtractSpecInfo([]byte(badJSON)) - assert.Error(t, e) + _, e := ExtractSpecInfo([]byte(badJSON)) + assert.Error(t, e) } func TestExtractSpecInfo_Nothing(t *testing.T) { - _, e := ExtractSpecInfo([]byte("")) - assert.Error(t, e) + _, e := ExtractSpecInfo([]byte("")) + assert.Error(t, e) } func TestExtractSpecInfo_ValidYAML(t *testing.T) { - _, e := ExtractSpecInfo([]byte(goodYAML)) - assert.Error(t, e) + _, e := ExtractSpecInfo([]byte(goodYAML)) + assert.Error(t, e) } func TestExtractSpecInfo_InvalidYAML(t *testing.T) { - _, e := ExtractSpecInfo([]byte(badYAML)) - assert.Error(t, e) + _, e := ExtractSpecInfo([]byte(badYAML)) + assert.Error(t, e) } func TestExtractSpecInfo_InvalidOpenAPIVersion(t *testing.T) { - _, e := ExtractSpecInfo([]byte(OpenApiOne)) - assert.Error(t, e) + _, e := ExtractSpecInfo([]byte(OpenApiOne)) + assert.Error(t, e) } func TestExtractSpecInfo_OpenAPI3(t *testing.T) { - r, e := ExtractSpecInfo([]byte(OpenApi3Spec)) - assert.Nil(t, e) - assert.Equal(t, utils.OpenApi3, r.SpecType) - assert.Equal(t, "3.0.1", r.Version) + r, e := ExtractSpecInfo([]byte(OpenApi3Spec)) + assert.Nil(t, e) + assert.Equal(t, utils.OpenApi3, r.SpecType) + assert.Equal(t, "3.0.1", r.Version) } func TestExtractSpecInfo_OpenAPIWat(t *testing.T) { - r, e := ExtractSpecInfo([]byte(OpenApiWat)) - assert.Nil(t, e) - assert.Equal(t, OpenApi3, r.SpecType) - assert.Equal(t, "3.2", r.Version) + r, e := ExtractSpecInfo([]byte(OpenApiWat)) + assert.Nil(t, e) + assert.Equal(t, OpenApi3, r.SpecType) + assert.Equal(t, "3.2", r.Version) } func TestExtractSpecInfo_OpenAPIFalse(t *testing.T) { - spec, e := ExtractSpecInfo([]byte(OpenApiFalse)) - assert.NoError(t, e) - assert.Equal(t, "false", spec.Version) + spec, e := ExtractSpecInfo([]byte(OpenApiFalse)) + assert.NoError(t, e) + assert.Equal(t, "false", spec.Version) } func TestExtractSpecInfo_OpenAPI2(t *testing.T) { - r, e := ExtractSpecInfo([]byte(OpenApi2Spec)) - assert.Nil(t, e) - assert.Equal(t, OpenApi2, r.SpecType) - assert.Equal(t, "2.0.1", r.Version) + r, e := ExtractSpecInfo([]byte(OpenApi2Spec)) + assert.Nil(t, e) + assert.Equal(t, OpenApi2, r.SpecType) + assert.Equal(t, "2.0.1", r.Version) } func TestExtractSpecInfo_OpenAPI2_OddVersion(t *testing.T) { - _, e := ExtractSpecInfo([]byte(OpenApi2SpecOdd)) - assert.NotNil(t, e) - assert.Equal(t, - "spec is defined as a swagger (openapi 2.0) spec, but is an openapi 3 or unknown version", e.Error()) + _, e := ExtractSpecInfo([]byte(OpenApi2SpecOdd)) + assert.NotNil(t, e) + assert.Equal(t, + "spec is defined as a swagger (openapi 2.0) spec, but is an openapi 3 or unknown version", e.Error()) } func TestExtractSpecInfo_AsyncAPI(t *testing.T) { - r, e := ExtractSpecInfo([]byte(AsyncAPISpec)) - assert.Nil(t, e) - assert.Equal(t, AsyncApi, r.SpecType) - assert.Equal(t, "2.0.0", r.Version) + r, e := ExtractSpecInfo([]byte(AsyncAPISpec)) + assert.Nil(t, e) + assert.Equal(t, AsyncApi, r.SpecType) + assert.Equal(t, "2.0.0", r.Version) } func TestExtractSpecInfo_AsyncAPI_OddVersion(t *testing.T) { - _, e := ExtractSpecInfo([]byte(AsyncAPISpecOdd)) - assert.NotNil(t, e) - assert.Equal(t, - "spec is defined as asyncapi, but has a major version that is invalid", e.Error()) + _, e := ExtractSpecInfo([]byte(AsyncAPISpecOdd)) + assert.NotNil(t, e) + assert.Equal(t, + "spec is defined as asyncapi, but has a major version that is invalid", e.Error()) } func TestAreValuesCorrectlyTyped(t *testing.T) { - assert.Len(t, AreValuesCorrectlyTyped("string", []interface{}{"hi"}), 0) - assert.Len(t, AreValuesCorrectlyTyped("string", []interface{}{1}), 1) - assert.Len(t, AreValuesCorrectlyTyped("string", []interface{}{"nice", 123, int64(12345)}), 2) - assert.Len(t, AreValuesCorrectlyTyped("string", []interface{}{1.2, "burgers"}), 1) - assert.Len(t, AreValuesCorrectlyTyped("string", []interface{}{true, false, "what"}), 2) + assert.Len(t, AreValuesCorrectlyTyped("string", []interface{}{"hi"}), 0) + assert.Len(t, AreValuesCorrectlyTyped("string", []interface{}{1}), 1) + assert.Len(t, AreValuesCorrectlyTyped("string", []interface{}{"nice", 123, int64(12345)}), 2) + assert.Len(t, AreValuesCorrectlyTyped("string", []interface{}{1.2, "burgers"}), 1) + assert.Len(t, AreValuesCorrectlyTyped("string", []interface{}{true, false, "what"}), 2) - assert.Len(t, AreValuesCorrectlyTyped("integer", []interface{}{1, 2, 3, 4}), 0) - assert.Len(t, AreValuesCorrectlyTyped("integer", []interface{}{"no way!"}), 1) - assert.Len(t, AreValuesCorrectlyTyped("integer", []interface{}{"nice", 123, int64(12345)}), 1) - assert.Len(t, AreValuesCorrectlyTyped("integer", []interface{}{999, 1.2, "burgers"}), 2) - assert.Len(t, AreValuesCorrectlyTyped("integer", []interface{}{true, false, "what"}), 3) + assert.Len(t, AreValuesCorrectlyTyped("integer", []interface{}{1, 2, 3, 4}), 0) + assert.Len(t, AreValuesCorrectlyTyped("integer", []interface{}{"no way!"}), 1) + assert.Len(t, AreValuesCorrectlyTyped("integer", []interface{}{"nice", 123, int64(12345)}), 1) + assert.Len(t, AreValuesCorrectlyTyped("integer", []interface{}{999, 1.2, "burgers"}), 2) + assert.Len(t, AreValuesCorrectlyTyped("integer", []interface{}{true, false, "what"}), 3) - assert.Len(t, AreValuesCorrectlyTyped("number", []interface{}{1.2345}), 0) - assert.Len(t, AreValuesCorrectlyTyped("number", []interface{}{"no way!"}), 1) - assert.Len(t, AreValuesCorrectlyTyped("number", []interface{}{"nice", 123, 2.353}), 1) - assert.Len(t, AreValuesCorrectlyTyped("number", []interface{}{999, 1.2, "burgers"}), 1) - assert.Len(t, AreValuesCorrectlyTyped("number", []interface{}{true, false, "what"}), 3) + assert.Len(t, AreValuesCorrectlyTyped("number", []interface{}{1.2345}), 0) + assert.Len(t, AreValuesCorrectlyTyped("number", []interface{}{"no way!"}), 1) + assert.Len(t, AreValuesCorrectlyTyped("number", []interface{}{"nice", 123, 2.353}), 1) + assert.Len(t, AreValuesCorrectlyTyped("number", []interface{}{999, 1.2, "burgers"}), 1) + assert.Len(t, AreValuesCorrectlyTyped("number", []interface{}{true, false, "what"}), 3) - assert.Len(t, AreValuesCorrectlyTyped("boolean", []interface{}{true, false, true}), 0) - assert.Len(t, AreValuesCorrectlyTyped("boolean", []interface{}{"no way!"}), 1) - assert.Len(t, AreValuesCorrectlyTyped("boolean", []interface{}{"nice", 123, 2.353, true}), 3) - assert.Len(t, AreValuesCorrectlyTyped("boolean", []interface{}{true, true, "burgers"}), 1) - assert.Len(t, AreValuesCorrectlyTyped("boolean", []interface{}{true, false, "what", 1.2, 4}), 3) + assert.Len(t, AreValuesCorrectlyTyped("boolean", []interface{}{true, false, true}), 0) + assert.Len(t, AreValuesCorrectlyTyped("boolean", []interface{}{"no way!"}), 1) + assert.Len(t, AreValuesCorrectlyTyped("boolean", []interface{}{"nice", 123, 2.353, true}), 3) + assert.Len(t, AreValuesCorrectlyTyped("boolean", []interface{}{true, true, "burgers"}), 1) + assert.Len(t, AreValuesCorrectlyTyped("boolean", []interface{}{true, false, "what", 1.2, 4}), 3) - assert.Nil(t, AreValuesCorrectlyTyped("boolean", []string{"hi"})) + assert.Nil(t, AreValuesCorrectlyTyped("boolean", []string{"hi"})) } func TestCheckEnumForDuplicates_Success(t *testing.T) { - yml := "- yes\n- no\n- crisps" - var rootNode yaml.Node - yaml.Unmarshal([]byte(yml), &rootNode) - assert.Len(t, CheckEnumForDuplicates(rootNode.Content[0].Content), 0) + yml := "- yes\n- no\n- crisps" + var rootNode yaml.Node + yaml.Unmarshal([]byte(yml), &rootNode) + assert.Len(t, CheckEnumForDuplicates(rootNode.Content[0].Content), 0) } func TestCheckEnumForDuplicates_Fail(t *testing.T) { - yml := "- yes\n- no\n- crisps\n- no" - var rootNode yaml.Node - yaml.Unmarshal([]byte(yml), &rootNode) - assert.Len(t, CheckEnumForDuplicates(rootNode.Content[0].Content), 1) + yml := "- yes\n- no\n- crisps\n- no" + var rootNode yaml.Node + yaml.Unmarshal([]byte(yml), &rootNode) + assert.Len(t, CheckEnumForDuplicates(rootNode.Content[0].Content), 1) } func TestCheckEnumForDuplicates_FailMultiple(t *testing.T) { - yml := "- yes\n- no\n- crisps\n- no\n- rice\n- yes\n- no" + yml := "- yes\n- no\n- crisps\n- no\n- rice\n- yes\n- no" - var rootNode yaml.Node - yaml.Unmarshal([]byte(yml), &rootNode) - assert.Len(t, CheckEnumForDuplicates(rootNode.Content[0].Content), 3) + var rootNode yaml.Node + yaml.Unmarshal([]byte(yml), &rootNode) + assert.Len(t, CheckEnumForDuplicates(rootNode.Content[0].Content), 3) } diff --git a/datamodel/spec_info.go b/datamodel/spec_info.go index e0c68b6..5eb87cc 100644 --- a/datamodel/spec_info.go +++ b/datamodel/spec_info.go @@ -1,28 +1,28 @@ package datamodel import ( - "gopkg.in/yaml.v3" - "time" + "gopkg.in/yaml.v3" + "time" ) // SpecInfo represents information about a supplied specification. type SpecInfo struct { - SpecType string `json:"type"` - Version string `json:"version"` - SpecFormat string `json:"format"` - SpecFileType string `json:"fileType"` - RootNode *yaml.Node `json:"-"` // reference to the root node of the spec. - SpecBytes *[]byte `json:"bytes"` // the original bytes - SpecJSONBytes *[]byte `json:"-"` // original bytes converted to JSON - SpecJSON *map[string]interface{} `json:"-"` // standard JSON map of original bytes - Error error `json:"-"` // something go wrong? - APISchema string `json:"-"` // API Schema for supplied spec type (2 or 3) - Generated time.Time `json:"-"` - JsonParsingChannel chan bool `json:"-"` + SpecType string `json:"type"` + Version string `json:"version"` + SpecFormat string `json:"format"` + SpecFileType string `json:"fileType"` + RootNode *yaml.Node `json:"-"` // reference to the root node of the spec. + SpecBytes *[]byte `json:"bytes"` // the original bytes + SpecJSONBytes *[]byte `json:"-"` // original bytes converted to JSON + SpecJSON *map[string]interface{} `json:"-"` // standard JSON map of original bytes + Error error `json:"-"` // something go wrong? + APISchema string `json:"-"` // API Schema for supplied spec type (2 or 3) + Generated time.Time `json:"-"` + JsonParsingChannel chan bool `json:"-"` } // GetJSONParsingChannel returns a channel that will close once async JSON parsing is completed. // This is required as rules may start executing before we're even done reading in the spec to JSON. func (si SpecInfo) GetJSONParsingChannel() chan bool { - return si.JsonParsingChannel + return si.JsonParsingChannel } diff --git a/libopenapi.go b/libopenapi.go index 7ddf557..b84dfbe 100644 --- a/libopenapi.go +++ b/libopenapi.go @@ -3,5 +3,5 @@ package main import "github.com/pb33f/libopenapi/utils" func main() { - utils.BuildPath("nope", []string{"one"}) + utils.BuildPath("nope", []string{"one"}) } diff --git a/utils/utils_test.go b/utils/utils_test.go index 990df3d..9199830 100644 --- a/utils/utils_test.go +++ b/utils/utils_test.go @@ -1,11 +1,11 @@ package utils import ( - "github.com/stretchr/testify/assert" - "gopkg.in/yaml.v3" - "io/ioutil" - "sync" - "testing" + "github.com/stretchr/testify/assert" + "gopkg.in/yaml.v3" + "io/ioutil" + "sync" + "testing" ) type petstore []byte @@ -13,429 +13,429 @@ type petstore []byte var once sync.Once var ( - psBytes petstore + psBytes petstore ) func getPetstore() petstore { - once.Do(func() { - psBytes, _ = ioutil.ReadFile("../test_specs/petstorev3.json") - }) - return psBytes + once.Do(func() { + psBytes, _ = ioutil.ReadFile("../test_specs/petstorev3.json") + }) + return psBytes } func TestRenderCodeSnippet(t *testing.T) { - code := []string{"hey", "ho", "let's", "go!"} - startNode := &yaml.Node{ - Line: 1, - } - rendered := RenderCodeSnippet(startNode, code, 1, 3) - assert.Equal(t, "hey\nho\nlet's\n", rendered) + code := []string{"hey", "ho", "let's", "go!"} + startNode := &yaml.Node{ + Line: 1, + } + rendered := RenderCodeSnippet(startNode, code, 1, 3) + assert.Equal(t, "hey\nho\nlet's\n", rendered) } func TestFindNodes(t *testing.T) { - nodes, err := FindNodes(getPetstore(), "$.info.contact") - assert.NoError(t, err) - assert.NotNil(t, nodes) - assert.Len(t, nodes, 1) + nodes, err := FindNodes(getPetstore(), "$.info.contact") + assert.NoError(t, err) + assert.NotNil(t, nodes) + assert.Len(t, nodes, 1) } func TestFindNodes_BadPath(t *testing.T) { - nodes, err := FindNodes(getPetstore(), "I am not valid") - assert.Error(t, err) - assert.Nil(t, nodes) + nodes, err := FindNodes(getPetstore(), "I am not valid") + assert.Error(t, err) + assert.Nil(t, nodes) } func TestFindLastChildNode(t *testing.T) { - nodes, _ := FindNodes(getPetstore(), "$.info") - lastNode := FindLastChildNode(nodes[0]) - assert.Equal(t, "1.0.11", lastNode.Value) // should be the version. + nodes, _ := FindNodes(getPetstore(), "$.info") + lastNode := FindLastChildNode(nodes[0]) + assert.Equal(t, "1.0.11", lastNode.Value) // should be the version. } func TestFindLastChildNode_WithKids(t *testing.T) { - nodes, _ := FindNodes(getPetstore(), "$.paths./pet") - lastNode := FindLastChildNode(nodes[0]) - assert.Equal(t, "read:pets", lastNode.Value) + nodes, _ := FindNodes(getPetstore(), "$.paths./pet") + lastNode := FindLastChildNode(nodes[0]) + assert.Equal(t, "read:pets", lastNode.Value) } func TestFindLastChildNode_NotFound(t *testing.T) { - node := &yaml.Node{ - Value: "same", - } - lastNode := FindLastChildNode(node) - assert.Equal(t, "same", lastNode.Value) // should be the same node + node := &yaml.Node{ + Value: "same", + } + lastNode := FindLastChildNode(node) + assert.Equal(t, "same", lastNode.Value) // should be the same node } func TestBuildPath(t *testing.T) { - assert.Equal(t, "$.fresh.fish.and.chicken.nuggets", - BuildPath("$.fresh.fish", []string{"and", "chicken", "nuggets"})) + assert.Equal(t, "$.fresh.fish.and.chicken.nuggets", + BuildPath("$.fresh.fish", []string{"and", "chicken", "nuggets"})) } func TestBuildPath_WithTrailingPeriod(t *testing.T) { - assert.Equal(t, "$.fresh.fish.and.chicken.nuggets", - BuildPath("$.fresh.fish", []string{"and", "chicken", "nuggets", ""})) + assert.Equal(t, "$.fresh.fish.and.chicken.nuggets", + BuildPath("$.fresh.fish", []string{"and", "chicken", "nuggets", ""})) } func TestFindNodesWithoutDeserializing(t *testing.T) { - root, err := FindNodes(getPetstore(), "$") - nodes, err := FindNodesWithoutDeserializing(root[0], "$.info.contact") - assert.NoError(t, err) - assert.NotNil(t, nodes) - assert.Len(t, nodes, 1) + root, err := FindNodes(getPetstore(), "$") + nodes, err := FindNodesWithoutDeserializing(root[0], "$.info.contact") + assert.NoError(t, err) + assert.NotNil(t, nodes) + assert.Len(t, nodes, 1) } func TestFindNodesWithoutDeserializing_InvalidPath(t *testing.T) { - root, err := FindNodes(getPetstore(), "$") - nodes, err := FindNodesWithoutDeserializing(root[0], "I love a good curry") - assert.Error(t, err) - assert.Nil(t, nodes) + root, err := FindNodes(getPetstore(), "$") + nodes, err := FindNodesWithoutDeserializing(root[0], "I love a good curry") + assert.Error(t, err) + assert.Nil(t, nodes) } func TestConvertInterfaceIntoStringMap(t *testing.T) { - var d interface{} - n := make(map[string]string) - n["melody"] = "baby girl" - d = n - parsed := ConvertInterfaceIntoStringMap(d) - assert.Equal(t, "baby girl", parsed["melody"]) + var d interface{} + n := make(map[string]string) + n["melody"] = "baby girl" + d = n + parsed := ConvertInterfaceIntoStringMap(d) + assert.Equal(t, "baby girl", parsed["melody"]) } func TestConvertInterfaceIntoStringMap_NoType(t *testing.T) { - var d interface{} - n := make(map[string]interface{}) - n["melody"] = "baby girl" - d = n - parsed := ConvertInterfaceIntoStringMap(d) - assert.Equal(t, "baby girl", parsed["melody"]) + var d interface{} + n := make(map[string]interface{}) + n["melody"] = "baby girl" + d = n + parsed := ConvertInterfaceIntoStringMap(d) + assert.Equal(t, "baby girl", parsed["melody"]) } func TestConvertInterfaceToStringArray(t *testing.T) { - var d interface{} - n := make(map[string][]string) - n["melody"] = []string{"melody", "is", "my", "baby"} - d = n - parsed := ConvertInterfaceToStringArray(d) - assert.Equal(t, "baby", parsed[3]) + var d interface{} + n := make(map[string][]string) + n["melody"] = []string{"melody", "is", "my", "baby"} + d = n + parsed := ConvertInterfaceToStringArray(d) + assert.Equal(t, "baby", parsed[3]) } func TestConvertInterfaceToStringArray_NoType(t *testing.T) { - var d interface{} - m := make([]interface{}, 4) - n := make(map[string]interface{}) - m[0] = "melody" - m[1] = "is" - m[2] = "my" - m[3] = "baby" - n["melody"] = m - d = n - parsed := ConvertInterfaceToStringArray(d) - assert.Equal(t, "baby", parsed[3]) + var d interface{} + m := make([]interface{}, 4) + n := make(map[string]interface{}) + m[0] = "melody" + m[1] = "is" + m[2] = "my" + m[3] = "baby" + n["melody"] = m + d = n + parsed := ConvertInterfaceToStringArray(d) + assert.Equal(t, "baby", parsed[3]) } func TestConvertInterfaceToStringArray_Invalid(t *testing.T) { - var d interface{} - d = "I am a carrot" - parsed := ConvertInterfaceToStringArray(d) - assert.Nil(t, parsed) + var d interface{} + d = "I am a carrot" + parsed := ConvertInterfaceToStringArray(d) + assert.Nil(t, parsed) } func TestConvertInterfaceArrayToStringArray(t *testing.T) { - var d interface{} - m := []string{"maddox", "is", "my", "little", "champion"} - d = m - parsed := ConvertInterfaceArrayToStringArray(d) - assert.Equal(t, "little", parsed[3]) + var d interface{} + m := []string{"maddox", "is", "my", "little", "champion"} + d = m + parsed := ConvertInterfaceArrayToStringArray(d) + assert.Equal(t, "little", parsed[3]) } func TestConvertInterfaceArrayToStringArray_NoType(t *testing.T) { - var d interface{} - m := make([]interface{}, 4) - m[0] = "melody" - m[1] = "is" - m[2] = "my" - m[3] = "baby" - d = m - parsed := ConvertInterfaceArrayToStringArray(d) - assert.Equal(t, "baby", parsed[3]) + var d interface{} + m := make([]interface{}, 4) + m[0] = "melody" + m[1] = "is" + m[2] = "my" + m[3] = "baby" + d = m + parsed := ConvertInterfaceArrayToStringArray(d) + assert.Equal(t, "baby", parsed[3]) } func TestConvertInterfaceArrayToStringArray_Invalid(t *testing.T) { - var d interface{} - d = "weed is good" - parsed := ConvertInterfaceArrayToStringArray(d) - assert.Nil(t, parsed) + var d interface{} + d = "weed is good" + parsed := ConvertInterfaceArrayToStringArray(d) + assert.Nil(t, parsed) } func TestExtractValueFromInterfaceMap(t *testing.T) { - var d interface{} - m := make(map[string][]string) - m["melody"] = []string{"is", "my", "baby"} - d = m - parsed := ExtractValueFromInterfaceMap("melody", d) - assert.Equal(t, "baby", parsed.([]string)[2]) + var d interface{} + m := make(map[string][]string) + m["melody"] = []string{"is", "my", "baby"} + d = m + parsed := ExtractValueFromInterfaceMap("melody", d) + assert.Equal(t, "baby", parsed.([]string)[2]) } func TestExtractValueFromInterfaceMap_NoType(t *testing.T) { - var d interface{} - m := make(map[string]interface{}) - n := make([]interface{}, 3) - n[0] = "maddy" - n[1] = "the" - n[2] = "champion" - m["maddy"] = n - d = m - parsed := ExtractValueFromInterfaceMap("maddy", d) - assert.Equal(t, "champion", parsed.([]interface{})[2]) + var d interface{} + m := make(map[string]interface{}) + n := make([]interface{}, 3) + n[0] = "maddy" + n[1] = "the" + n[2] = "champion" + m["maddy"] = n + d = m + parsed := ExtractValueFromInterfaceMap("maddy", d) + assert.Equal(t, "champion", parsed.([]interface{})[2]) } func TestExtractValueFromInterfaceMap_Flat(t *testing.T) { - var d interface{} - m := make(map[string]interface{}) - m["maddy"] = "niblet" - d = m - parsed := ExtractValueFromInterfaceMap("maddy", d) - assert.Equal(t, "niblet", parsed.(interface{})) + var d interface{} + m := make(map[string]interface{}) + m["maddy"] = "niblet" + d = m + parsed := ExtractValueFromInterfaceMap("maddy", d) + assert.Equal(t, "niblet", parsed.(interface{})) } func TestExtractValueFromInterfaceMap_NotFound(t *testing.T) { - var d interface{} - d = "not a map" - parsed := ExtractValueFromInterfaceMap("melody", d) - assert.Nil(t, parsed) + var d interface{} + d = "not a map" + parsed := ExtractValueFromInterfaceMap("melody", d) + assert.Nil(t, parsed) } func TestFindFirstKeyNode(t *testing.T) { - nodes, _ := FindNodes(getPetstore(), "$") - key, value := FindFirstKeyNode("operationId", nodes, 0) - assert.NotNil(t, key) - assert.NotNil(t, value) - assert.Equal(t, 55, key.Line) + nodes, _ := FindNodes(getPetstore(), "$") + key, value := FindFirstKeyNode("operationId", nodes, 0) + assert.NotNil(t, key) + assert.NotNil(t, value) + assert.Equal(t, 55, key.Line) } func TestFindFirstKeyNode_NotFound(t *testing.T) { - nodes, _ := FindNodes(getPetstore(), "$") - key, value := FindFirstKeyNode("i-do-not-exist-in-the-doc", nodes, 0) - assert.Nil(t, key) - assert.Nil(t, value) + nodes, _ := FindNodes(getPetstore(), "$") + key, value := FindFirstKeyNode("i-do-not-exist-in-the-doc", nodes, 0) + assert.Nil(t, key) + assert.Nil(t, value) } func TestFindFirstKeyNode_Map(t *testing.T) { - nodes, _ := FindNodes(getPetstore(), "$") - key, value := FindFirstKeyNode("pet", nodes, 0) - assert.NotNil(t, key) - assert.NotNil(t, value) - assert.Equal(t, 27, key.Line) + nodes, _ := FindNodes(getPetstore(), "$") + key, value := FindFirstKeyNode("pet", nodes, 0) + assert.NotNil(t, key) + assert.NotNil(t, value) + assert.Equal(t, 27, key.Line) } func TestFindKeyNodeTop(t *testing.T) { - nodes, _ := FindNodes(getPetstore(), "$") - k, v := FindKeyNodeTop("info", nodes[0].Content) - assert.NotNil(t, k) - assert.NotNil(t, v) - assert.Equal(t, 3, k.Line) + nodes, _ := FindNodes(getPetstore(), "$") + k, v := FindKeyNodeTop("info", nodes[0].Content) + assert.NotNil(t, k) + assert.NotNil(t, v) + assert.Equal(t, 3, k.Line) } func TestFindKeyNodeTop_NotFound(t *testing.T) { - nodes, _ := FindNodes(getPetstore(), "$") - k, v := FindKeyNodeTop("i am a giant potato", nodes[0].Content) - assert.Nil(t, k) - assert.Nil(t, v) + nodes, _ := FindNodes(getPetstore(), "$") + k, v := FindKeyNodeTop("i am a giant potato", nodes[0].Content) + assert.Nil(t, k) + assert.Nil(t, v) } func TestFindKeyNode(t *testing.T) { - nodes, _ := FindNodes(getPetstore(), "$") - k, v := FindKeyNode("/pet", nodes[0].Content) - assert.NotNil(t, k) - assert.NotNil(t, v) - assert.Equal(t, 47, k.Line) + nodes, _ := FindNodes(getPetstore(), "$") + k, v := FindKeyNode("/pet", nodes[0].Content) + assert.NotNil(t, k) + assert.NotNil(t, v) + assert.Equal(t, 47, k.Line) } func TestFindKeyNode_NotFound(t *testing.T) { - nodes, _ := FindNodes(getPetstore(), "$") - k, v := FindKeyNode("I am not anything at all", nodes[0].Content) - assert.Nil(t, k) - assert.Nil(t, v) + nodes, _ := FindNodes(getPetstore(), "$") + k, v := FindKeyNode("I am not anything at all", nodes[0].Content) + assert.Nil(t, k) + assert.Nil(t, v) } func TestMakeTagReadable(t *testing.T) { - n := &yaml.Node{ - Tag: "!!map", - } - assert.Equal(t, ObjectLabel, MakeTagReadable(n)) - n.Tag = "!!seq" - assert.Equal(t, ArrayLabel, MakeTagReadable(n)) - n.Tag = "!!str" - assert.Equal(t, StringLabel, MakeTagReadable(n)) - n.Tag = "!!int" - assert.Equal(t, IntegerLabel, MakeTagReadable(n)) - n.Tag = "!!float" - assert.Equal(t, NumberLabel, MakeTagReadable(n)) - n.Tag = "!!bool" - assert.Equal(t, BooleanLabel, MakeTagReadable(n)) - n.Tag = "mr potato man is here" - assert.Equal(t, "unknown", MakeTagReadable(n)) + n := &yaml.Node{ + Tag: "!!map", + } + assert.Equal(t, ObjectLabel, MakeTagReadable(n)) + n.Tag = "!!seq" + assert.Equal(t, ArrayLabel, MakeTagReadable(n)) + n.Tag = "!!str" + assert.Equal(t, StringLabel, MakeTagReadable(n)) + n.Tag = "!!int" + assert.Equal(t, IntegerLabel, MakeTagReadable(n)) + n.Tag = "!!float" + assert.Equal(t, NumberLabel, MakeTagReadable(n)) + n.Tag = "!!bool" + assert.Equal(t, BooleanLabel, MakeTagReadable(n)) + n.Tag = "mr potato man is here" + assert.Equal(t, "unknown", MakeTagReadable(n)) } func TestIsNodeMap(t *testing.T) { - n := &yaml.Node{ - Tag: "!!map", - } - assert.True(t, IsNodeMap(n)) - n.Tag = "!!pizza" - assert.False(t, IsNodeMap(n)) + n := &yaml.Node{ + Tag: "!!map", + } + assert.True(t, IsNodeMap(n)) + n.Tag = "!!pizza" + assert.False(t, IsNodeMap(n)) } func TestIsNodeMap_Nil(t *testing.T) { - assert.False(t, IsNodeMap(nil)) + assert.False(t, IsNodeMap(nil)) } func TestIsNodePolyMorphic(t *testing.T) { - n := &yaml.Node{ - Content: []*yaml.Node{ - { - Value: "anyOf", - }, - }, - } - assert.True(t, IsNodePolyMorphic(n)) - n.Content[0].Value = "cakes" - assert.False(t, IsNodePolyMorphic(n)) + n := &yaml.Node{ + Content: []*yaml.Node{ + { + Value: "anyOf", + }, + }, + } + assert.True(t, IsNodePolyMorphic(n)) + n.Content[0].Value = "cakes" + assert.False(t, IsNodePolyMorphic(n)) } func TestIsNodeArray(t *testing.T) { - n := &yaml.Node{ - Tag: "!!seq", - } - assert.True(t, IsNodeArray(n)) - n.Tag = "!!pizza" - assert.False(t, IsNodeArray(n)) + n := &yaml.Node{ + Tag: "!!seq", + } + assert.True(t, IsNodeArray(n)) + n.Tag = "!!pizza" + assert.False(t, IsNodeArray(n)) } func TestIsNodeArray_Nil(t *testing.T) { - assert.False(t, IsNodeArray(nil)) + assert.False(t, IsNodeArray(nil)) } func TestIsNodeStringValue(t *testing.T) { - n := &yaml.Node{ - Tag: "!!str", - } - assert.True(t, IsNodeStringValue(n)) - n.Tag = "!!pizza" - assert.False(t, IsNodeStringValue(n)) + n := &yaml.Node{ + Tag: "!!str", + } + assert.True(t, IsNodeStringValue(n)) + n.Tag = "!!pizza" + assert.False(t, IsNodeStringValue(n)) } func TestIsNodeStringValue_Nil(t *testing.T) { - assert.False(t, IsNodeStringValue(nil)) + assert.False(t, IsNodeStringValue(nil)) } func TestIsNodeIntValue(t *testing.T) { - n := &yaml.Node{ - Tag: "!!int", - } - assert.True(t, IsNodeIntValue(n)) - n.Tag = "!!pizza" - assert.False(t, IsNodeIntValue(n)) + n := &yaml.Node{ + Tag: "!!int", + } + assert.True(t, IsNodeIntValue(n)) + n.Tag = "!!pizza" + assert.False(t, IsNodeIntValue(n)) } func TestIsNodeIntValue_Nil(t *testing.T) { - assert.False(t, IsNodeIntValue(nil)) + assert.False(t, IsNodeIntValue(nil)) } func TestIsNodeFloatValue(t *testing.T) { - n := &yaml.Node{ - Tag: "!!float", - } - assert.True(t, IsNodeFloatValue(n)) - n.Tag = "!!pizza" - assert.False(t, IsNodeFloatValue(n)) + n := &yaml.Node{ + Tag: "!!float", + } + assert.True(t, IsNodeFloatValue(n)) + n.Tag = "!!pizza" + assert.False(t, IsNodeFloatValue(n)) } func TestIsNodeFloatValue_Nil(t *testing.T) { - assert.False(t, IsNodeFloatValue(nil)) + assert.False(t, IsNodeFloatValue(nil)) } func TestIsNodeBoolValue(t *testing.T) { - n := &yaml.Node{ - Tag: "!!bool", - } - assert.True(t, IsNodeBoolValue(n)) - n.Tag = "!!pizza" - assert.False(t, IsNodeBoolValue(n)) + n := &yaml.Node{ + Tag: "!!bool", + } + assert.True(t, IsNodeBoolValue(n)) + n.Tag = "!!pizza" + assert.False(t, IsNodeBoolValue(n)) } func TestIsNodeBoolValue_Nil(t *testing.T) { - assert.False(t, IsNodeBoolValue(nil)) + assert.False(t, IsNodeBoolValue(nil)) } func TestFixContext(t *testing.T) { - assert.Equal(t, "$.nuggets[12].name", FixContext("(root).nuggets.12.name")) + assert.Equal(t, "$.nuggets[12].name", FixContext("(root).nuggets.12.name")) } func TestFixContext_HttpCode(t *testing.T) { - assert.Equal(t, "$.nuggets.404.name", FixContext("(root).nuggets.404.name")) + assert.Equal(t, "$.nuggets.404.name", FixContext("(root).nuggets.404.name")) } func TestIsJSON(t *testing.T) { - assert.True(t, IsJSON("{'hello':'there'}")) - assert.False(t, IsJSON("potato shoes")) - assert.False(t, IsJSON("")) + assert.True(t, IsJSON("{'hello':'there'}")) + assert.False(t, IsJSON("potato shoes")) + assert.False(t, IsJSON("")) } func TestIsYAML(t *testing.T) { - assert.True(t, IsYAML("hello:\n there:\n my-name: is quobix")) - assert.True(t, IsYAML("potato shoes")) - assert.False(t, IsYAML("{'hello':'there'}")) - assert.False(t, IsYAML("")) - assert.False(t, IsYAML("8908: hello: yeah: \n12309812: :123")) + assert.True(t, IsYAML("hello:\n there:\n my-name: is quobix")) + assert.True(t, IsYAML("potato shoes")) + assert.False(t, IsYAML("{'hello':'there'}")) + assert.False(t, IsYAML("")) + assert.False(t, IsYAML("8908: hello: yeah: \n12309812: :123")) } func TestConvertYAMLtoJSON(t *testing.T) { - str, err := ConvertYAMLtoJSON([]byte("hello: there")) - assert.NoError(t, err) - assert.NotNil(t, str) - assert.Equal(t, "{\"hello\":\"there\"}", string(str)) + str, err := ConvertYAMLtoJSON([]byte("hello: there")) + assert.NoError(t, err) + assert.NotNil(t, str) + assert.Equal(t, "{\"hello\":\"there\"}", string(str)) - str, err = ConvertYAMLtoJSON([]byte("gonna: break: you:\nyeah:yeah:yeah")) - assert.Error(t, err) - assert.Nil(t, str) + str, err = ConvertYAMLtoJSON([]byte("gonna: break: you:\nyeah:yeah:yeah")) + assert.Error(t, err) + assert.Nil(t, str) } func TestIsHttpVerb(t *testing.T) { - assert.True(t, IsHttpVerb("get")) - assert.True(t, IsHttpVerb("post")) - assert.False(t, IsHttpVerb("nuggets")) + assert.True(t, IsHttpVerb("get")) + assert.True(t, IsHttpVerb("post")) + assert.False(t, IsHttpVerb("nuggets")) } func TestConvertComponentIdIntoFriendlyPathSearch(t *testing.T) { - segment, path := ConvertComponentIdIntoFriendlyPathSearch("#/chicken/chips/pizza/cake") - assert.Equal(t, "$.chicken.chips.pizza['cake']", path) - assert.Equal(t, "cake", segment) + segment, path := ConvertComponentIdIntoFriendlyPathSearch("#/chicken/chips/pizza/cake") + assert.Equal(t, "$.chicken.chips.pizza['cake']", path) + assert.Equal(t, "cake", segment) } func TestConvertComponentIdIntoPath(t *testing.T) { - segment, path := ConvertComponentIdIntoPath("#/chicken/chips/pizza/cake") - assert.Equal(t, "$.chicken.chips.pizza.cake", path) - assert.Equal(t, "cake", segment) + segment, path := ConvertComponentIdIntoPath("#/chicken/chips/pizza/cake") + assert.Equal(t, "$.chicken.chips.pizza.cake", path) + assert.Equal(t, "cake", segment) } func TestDetectCase(t *testing.T) { - assert.Equal(t, PascalCase, DetectCase("PizzaPie")) - assert.Equal(t, CamelCase, DetectCase("anyoneForTennis")) - assert.Equal(t, ScreamingSnakeCase, DetectCase("I_LOVE_BEER")) - assert.Equal(t, ScreamingKebabCase, DetectCase("I-LOVE-BURGERS")) - assert.Equal(t, SnakeCase, DetectCase("snakes_on_a_plane")) - assert.Equal(t, KebabCase, DetectCase("chicken-be-be-beef-or-pork")) - assert.Equal(t, RegularCase, DetectCase("kebab-TimeIn_london-TOWN")) + assert.Equal(t, PascalCase, DetectCase("PizzaPie")) + assert.Equal(t, CamelCase, DetectCase("anyoneForTennis")) + assert.Equal(t, ScreamingSnakeCase, DetectCase("I_LOVE_BEER")) + assert.Equal(t, ScreamingKebabCase, DetectCase("I-LOVE-BURGERS")) + assert.Equal(t, SnakeCase, DetectCase("snakes_on_a_plane")) + assert.Equal(t, KebabCase, DetectCase("chicken-be-be-beef-or-pork")) + assert.Equal(t, RegularCase, DetectCase("kebab-TimeIn_london-TOWN")) } func TestConvertCase(t *testing.T) { - str1 := "chicken-nuggets-chicken-soup" - assert.Equal(t, "chickenNuggetsChickenSoup", ConvertCase(str1, CamelCase)) - assert.Equal(t, "ChickenNuggetsChickenSoup", ConvertCase(str1, PascalCase)) - assert.Equal(t, "chicken_nuggets_chicken_soup", ConvertCase(str1, SnakeCase)) - assert.Equal(t, str1, ConvertCase(str1, KebabCase)) - assert.Equal(t, "CHICKEN-NUGGETS-CHICKEN-SOUP", ConvertCase(str1, ScreamingKebabCase)) - assert.Equal(t, "CHICKEN_NUGGETS_CHICKEN_SOUP", ConvertCase(str1, ScreamingSnakeCase)) + str1 := "chicken-nuggets-chicken-soup" + assert.Equal(t, "chickenNuggetsChickenSoup", ConvertCase(str1, CamelCase)) + assert.Equal(t, "ChickenNuggetsChickenSoup", ConvertCase(str1, PascalCase)) + assert.Equal(t, "chicken_nuggets_chicken_soup", ConvertCase(str1, SnakeCase)) + assert.Equal(t, str1, ConvertCase(str1, KebabCase)) + assert.Equal(t, "CHICKEN-NUGGETS-CHICKEN-SOUP", ConvertCase(str1, ScreamingKebabCase)) + assert.Equal(t, "CHICKEN_NUGGETS_CHICKEN_SOUP", ConvertCase(str1, ScreamingSnakeCase)) }