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 <dave@quobix.com>
This commit is contained in:
Dave Shanley
2022-08-27 12:48:58 -04:00
parent c34c4f668c
commit 51e1f62b04
19 changed files with 634 additions and 669 deletions

View File

@@ -1,2 +1,3 @@
# libopenapi
A place for up to date, modern golang OpenAPI models and utilities.

View File

@@ -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)
}

View File

@@ -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
}

View File

@@ -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)
}

View File

@@ -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
}

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)
}
}

View File

@@ -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]

View File

@@ -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

View File

@@ -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:

View File

@@ -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 {

View File

@@ -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:

View File

@@ -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]
}

View File

@@ -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
}

View File

@@ -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)
}

View File

@@ -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
}

View File

@@ -3,5 +3,5 @@ package main
import "github.com/pb33f/libopenapi/utils"
func main() {
utils.BuildPath("nope", []string{"one"})
utils.BuildPath("nope", []string{"one"})
}

View File

@@ -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))
}