diff --git a/datamodel/high/base/security_requirement_test.go b/datamodel/high/base/security_requirement_test.go new file mode 100644 index 0000000..e056255 --- /dev/null +++ b/datamodel/high/base/security_requirement_test.go @@ -0,0 +1,35 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package base + +import ( + lowmodel "github.com/pb33f/libopenapi/datamodel/low" + lowbase "github.com/pb33f/libopenapi/datamodel/low/base" + "github.com/stretchr/testify/assert" + "gopkg.in/yaml.v3" + "testing" +) + +func TestNewSecurityRequirement(t *testing.T) { + + var cNode yaml.Node + + yml := `pizza: + - cheese + - tomato` + + _ = yaml.Unmarshal([]byte(yml), &cNode) + + var lowExt lowbase.SecurityRequirement + _ = lowmodel.BuildModel(cNode.Content[0], &lowExt) + + _ = lowExt.Build(cNode.Content[0], nil) + + highExt := NewSecurityRequirement(&lowExt) + + assert.Len(t, highExt.Requirements["pizza"], 2) + + wentLow := highExt.GoLow() + assert.Len(t, wentLow.Requirements.Value, 1) +} diff --git a/datamodel/high/v2/swagger_test.go b/datamodel/high/v2/swagger_test.go index 6a3cab3..9d5c0df 100644 --- a/datamodel/high/v2/swagger_test.go +++ b/datamodel/high/v2/swagger_test.go @@ -182,10 +182,10 @@ func TestNewSwaggerDocument_Definitions_Responses(t *testing.T) { assert.Len(t, x.Enum, 2) wentQuiteLow := y.GoLow() - assert.Equal(t, 717, wentQuiteLow.Type.KeyNode.Line) + assert.Equal(t, 729, wentQuiteLow.Type.KeyNode.Line) wentLowest := x.GoLow() - assert.Equal(t, 733, wentLowest.UniqueItems.KeyNode.Line) + assert.Equal(t, 745, wentLowest.UniqueItems.KeyNode.Line) } func TestNewSwaggerDocument_Definitions(t *testing.T) { @@ -195,7 +195,7 @@ func TestNewSwaggerDocument_Definitions(t *testing.T) { assert.Len(t, highDoc.Definitions.Definitions, 6) wentLow := highDoc.Definitions.GoLow() - assert.Equal(t, 836, wentLow.FindSchema("User").ValueNode.Line) + assert.Equal(t, 848, wentLow.FindSchema("User").ValueNode.Line) } diff --git a/datamodel/low/base/schema_proxy_test.go b/datamodel/low/base/schema_proxy_test.go index 5df8126..4525a48 100644 --- a/datamodel/low/base/schema_proxy_test.go +++ b/datamodel/low/base/schema_proxy_test.go @@ -4,6 +4,7 @@ package base import ( + "github.com/pb33f/libopenapi/datamodel/low" "github.com/stretchr/testify/assert" "gopkg.in/yaml.v3" "testing" @@ -19,10 +20,19 @@ func TestSchemaProxy_Build(t *testing.T) { err := sch.Build(idxNode.Content[0], nil) assert.NoError(t, err) + + assert.Equal(t, "3fc9b689459d738f8c88a3a48aa9e33542016b7a4052e001aaa536fca74813cb", + low.GenerateHashString(&sch)) + assert.Equal(t, "something", sch.Schema().Description.Value) assert.Empty(t, sch.GetSchemaReference()) assert.NotNil(t, sch.GetValueNode()) assert.False(t, sch.IsSchemaReference()) + + // already rendered, should spit out the same + assert.Equal(t, "3fc9b689459d738f8c88a3a48aa9e33542016b7a4052e001aaa536fca74813cb", + low.GenerateHashString(&sch)) + } func TestSchemaProxy_Build_CheckRef(t *testing.T) { @@ -37,4 +47,6 @@ func TestSchemaProxy_Build_CheckRef(t *testing.T) { assert.NoError(t, err) assert.True(t, sch.IsSchemaReference()) assert.Equal(t, "wat", sch.GetSchemaReference()) + assert.Equal(t, "f00a787f7492a95e165b470702f4fe9373583fbdc025b2c8bdf0262cc48fcff4", + low.GenerateHashString(&sch)) } diff --git a/datamodel/low/extraction_functions_test.go b/datamodel/low/extraction_functions_test.go index 431f02d..1c0479e 100644 --- a/datamodel/low/extraction_functions_test.go +++ b/datamodel/low/extraction_functions_test.go @@ -4,6 +4,7 @@ package low import ( + "crypto/sha256" "fmt" "github.com/pb33f/libopenapi/index" "github.com/pb33f/libopenapi/resolver" @@ -1488,3 +1489,26 @@ x-tacos: [1,2,3]` } } } + +type test_fresh struct { + val string +} + +func (f test_fresh) Hash() [32]byte { + return sha256.Sum256([]byte(f.val)) +} +func TestAreEqual(t *testing.T) { + assert.True(t, AreEqual(test_fresh{val: "hello"}, test_fresh{val: "hello"})) + assert.False(t, AreEqual(test_fresh{val: "hello"}, test_fresh{val: "goodbye"})) + assert.False(t, AreEqual(nil, nil)) +} + +func TestGenerateHashString(t *testing.T) { + + assert.Equal(t, "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824", + GenerateHashString(test_fresh{val: "hello"})) + + assert.Equal(t, "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824", + GenerateHashString("hello")) + +} diff --git a/datamodel/low/model_builder_test.go b/datamodel/low/model_builder_test.go index 900793a..1989899 100644 --- a/datamodel/low/model_builder_test.go +++ b/datamodel/low/model_builder_test.go @@ -273,6 +273,51 @@ func TestSetField_ArrayHelper(t *testing.T) { assert.Len(t, ins.Thing.Value, 3) } +func TestSetField_Enum_Helper(t *testing.T) { + + type internal struct { + Thing NodeReference[[]ValueReference[any]] + } + + yml := `thing: + - nice + - rice + - slice` + + ins := new(internal) + var rootNode yaml.Node + mErr := yaml.Unmarshal([]byte(yml), &rootNode) + assert.NoError(t, mErr) + + try := BuildModel(rootNode.Content[0], ins) + assert.NoError(t, try) + assert.Len(t, ins.Thing.Value, 3) +} + +func TestSetField_Default_Helper(t *testing.T) { + + type cake struct { + thing int + } + + // this should be ignored, no custom objects in here my friend. + type internal struct { + Thing cake + } + + yml := `thing: + type: cake` + + ins := new(internal) + var rootNode yaml.Node + mErr := yaml.Unmarshal([]byte(yml), &rootNode) + assert.NoError(t, mErr) + + try := BuildModel(rootNode.Content[0], ins) + assert.NoError(t, try) + assert.Equal(t, 0, ins.Thing.thing) +} + func TestSetField_Ignore(t *testing.T) { type Complex struct { diff --git a/datamodel/low/reference.go b/datamodel/low/reference.go index 85e17a9..e0d9c06 100644 --- a/datamodel/low/reference.go +++ b/datamodel/low/reference.go @@ -87,10 +87,12 @@ func (n NodeReference[T]) IsEmpty() bool { } func (n NodeReference[T]) IsReferenceNode() bool { - for k := range n.KeyNode.Content { - if k%2 == 0 { - if n.KeyNode.Content[k].Value == "$ref" { - return true + if n.KeyNode != nil { + for k := range n.KeyNode.Content { + if k%2 == 0 { + if n.KeyNode.Content[k].Value == "$ref" { + return true + } } } } diff --git a/datamodel/low/reference_test.go b/datamodel/low/reference_test.go index 0c697e7..fd26971 100644 --- a/datamodel/low/reference_test.go +++ b/datamodel/low/reference_test.go @@ -4,6 +4,7 @@ package low import ( + "crypto/sha256" "github.com/pb33f/libopenapi/index" "github.com/pb33f/libopenapi/resolver" "github.com/stretchr/testify/assert" @@ -31,11 +32,28 @@ func TestNodeReference_Mutate(t *testing.T) { Line: 22, Column: 23, } + nr.KeyNode = &yaml.Node{ + Line: 22, + Column: 23, + } n := nr.Mutate("nice one!") + assert.NotNil(t, nr.GetValueNode()) + assert.Empty(t, nr.GetValue()) + assert.False(t, nr.IsReferenceNode()) assert.Equal(t, "nice one!", n.Value) assert.Equal(t, "nice one!", nr.ValueNode.Value) } +func TestNodeReference_RefNode(t *testing.T) { + nr := new(NodeReference[string]) + nr.KeyNode = &yaml.Node{ + Content: []*yaml.Node{&yaml.Node{ + Value: "$ref", + }}, + } + assert.True(t, nr.IsReferenceNode()) +} + func TestValueReference_Mutate(t *testing.T) { nr := new(ValueReference[string]) nr.ValueNode = &yaml.Node{ @@ -59,6 +77,8 @@ func TestValueReference_GenerateMapKey(t *testing.T) { Column: 23, } assert.Equal(t, "22:23", nr.GenerateMapKey()) + assert.NotNil(t, nr.GetValueNode()) + assert.Empty(t, nr.GetValue()) } func TestKeyReference_IsEmpty(t *testing.T) { @@ -307,5 +327,10 @@ func TestGetCircularReferenceResult_NothingFound(t *testing.T) { _ = yaml.Unmarshal([]byte(yml), &idxNode) assert.Nil(t, GetCircularReferenceResult(idxNode.Content[0], idx)) +} + +func TestHashToString(t *testing.T) { + assert.Equal(t, "5994471abb01112afcc18159f6cc74b4f511b99806da59b3caf5a9c173cacfc5", + HashToString(sha256.Sum256([]byte("12345")))) } diff --git a/datamodel/low/v2/definitions_test.go b/datamodel/low/v2/definitions_test.go index 5d35893..2195e8b 100644 --- a/datamodel/low/v2/definitions_test.go +++ b/datamodel/low/v2/definitions_test.go @@ -49,6 +49,26 @@ func TestDefinitions_Parameters_Build_Error(t *testing.T) { } +func TestDefinitions_Hash(t *testing.T) { + + yml := `nice: + description: rice` + + var idxNode yaml.Node + mErr := yaml.Unmarshal([]byte(yml), &idxNode) + assert.NoError(t, mErr) + idx := index.NewSpecIndex(&idxNode) + + var n Definitions + err := low.BuildModel(&idxNode, &n) + assert.NoError(t, err) + + _ = n.Build(idxNode.Content[0], idx) + assert.Equal(t, "26d23786e6873e1a337f8e9be85f7de1490e4ff6cd303c3b15e593a25a6a149d", + low.GenerateHashString(&n)) + +} + func TestDefinitions_Responses_Build_Error(t *testing.T) { yml := `gonna: diff --git a/datamodel/low/v3/components.go b/datamodel/low/v3/components.go index 9f7fd55..3175b8f 100644 --- a/datamodel/low/v3/components.go +++ b/datamodel/low/v3/components.go @@ -166,14 +166,14 @@ func extractComponentValues[T low.Buildable[N], N any](label string, root *yaml. // for every component, build in a new thread! bChan := make(chan componentBuildResult[T]) eChan := make(chan error) - var buildComponent = func(label *yaml.Node, value *yaml.Node, c chan componentBuildResult[T], ec chan<- error) { + var buildComponent = func(parentLabel string, label *yaml.Node, value *yaml.Node, c chan componentBuildResult[T], ec chan<- error) { var n T = new(N) // if this is a reference, extract it (although components with references is an antipattern) // If you're building components as references... pls... stop, this code should not need to be here. // TODO: check circular crazy on this. It may explode var err error - if h, _, _ := utils.IsNodeRefValue(value); h && label.Value != SchemasLabel { + if h, _, _ := utils.IsNodeRefValue(value); h && parentLabel != SchemasLabel { value, err = low.LocateRefNode(value, idx) } if err != nil { @@ -210,7 +210,7 @@ func extractComponentValues[T low.Buildable[N], N any](label string, root *yaml. continue } totalComponents++ - go buildComponent(currentLabel, v, bChan, eChan) + go buildComponent(label, currentLabel, v, bChan, eChan) } completedComponents := 0 diff --git a/datamodel/low/v3/components_test.go b/datamodel/low/v3/components_test.go index e385337..deb363f 100644 --- a/datamodel/low/v3/components_test.go +++ b/datamodel/low/v3/components_test.go @@ -138,6 +138,28 @@ func TestComponents_Build_Fail(t *testing.T) { } +func TestComponents_Build_ParameterFail(t *testing.T) { + + yml := `components: + parameters: + pizza: + schema: + $ref: '#/this is a problem.'` + + var idxNode yaml.Node + mErr := yaml.Unmarshal([]byte(yml), &idxNode) + assert.NoError(t, mErr) + idx := index.NewSpecIndex(&idxNode) + + var n Components + err := low.BuildModel(&idxNode, &n) + assert.NoError(t, err) + + err = n.Build(idxNode.Content[0], idx) + assert.Error(t, err) + +} + func TestComponents_Build_Fail_TypeFail(t *testing.T) { yml := `components: diff --git a/datamodel/spec_info_test.go b/datamodel/spec_info_test.go index 7836341..75647a5 100644 --- a/datamodel/spec_info_test.go +++ b/datamodel/spec_info_test.go @@ -53,6 +53,12 @@ info: servers: - url: https://quobix.com/api` +var OpenApi31 = `openapi: 3.1 +info: + title: Test API, valid, but not quite valid +servers: + - url: https://quobix.com/api` + var OpenApiFalse = `openapi: false info: title: Test API version is a bool? @@ -161,6 +167,14 @@ func TestExtractSpecInfo_OpenAPIWat(t *testing.T) { assert.Equal(t, "3.2", r.Version) } +func TestExtractSpecInfo_OpenAPI31(t *testing.T) { + + r, e := ExtractSpecInfo([]byte(OpenApi31)) + assert.Nil(t, e) + assert.Equal(t, OpenApi3, r.SpecType) + assert.Equal(t, "3.1", r.Version) +} + func TestExtractSpecInfo_OpenAPIFalse(t *testing.T) { spec, e := ExtractSpecInfo([]byte(OpenApiFalse)) diff --git a/test_specs/petstorev2-complete.yaml b/test_specs/petstorev2-complete.yaml index c017f04..fce75ea 100644 --- a/test_specs/petstorev2-complete.yaml +++ b/test_specs/petstorev2-complete.yaml @@ -714,6 +714,18 @@ responses: $ref: '#/definitions/ApiResponse' headers: someHeader: + format: something + pattern: a nice pattern + exclusiveMinimum: false + exclusiveMaximum: false + minimum: 1 + maximum: 2 + maxItems: 3 + minItems: 1 + minLength: 1 + maxLength: 10 + multipleOf: 20 + uniqueItems: false type: array enum: [one, two] items: diff --git a/utils/utils.go b/utils/utils.go index c6fe555..40c8f9e 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -274,22 +274,6 @@ func FindKeyNodeFullTop(key string, nodes []*yaml.Node) (keyNode *yaml.Node, lab return nodes[i], nodes[i], nodes[i+1] // next node is what we need. } } - for q, v := range nodes { - if q%2 != 0 { - continue - } - if key == v.Value { - if IsNodeMap(v) { - if q+1 == len(v.Content) { - return v, v.Content[q], v.Content[q] - } - return v, v.Content[q], v.Content[q+1] - } - if IsNodeArray(v) { - return v, v.Content[q], v.Content[q] - } - } - } return nil, nil, nil } diff --git a/utils/utils_test.go b/utils/utils_test.go index 03f869c..5024a6e 100644 --- a/utils/utils_test.go +++ b/utils/utils_test.go @@ -424,6 +424,34 @@ func TestFindKeyNode_NotFound(t *testing.T) { assert.Nil(t, v) } +func TestFindKeyFullNodeTop(t *testing.T) { + a := &yaml.Node{ + Value: "fish", + } + b := &yaml.Node{ + Value: "paste", + } + + c, d, e := FindKeyNodeFullTop("fish", []*yaml.Node{a, b}) + assert.Equal(t, "fish", c.Value) + assert.Equal(t, "fish", d.Value) + assert.Equal(t, "paste", e.Value) +} + +func TestFindKeyFullNode_NotFound(t *testing.T) { + a := &yaml.Node{ + Value: "fish", + } + b := &yaml.Node{ + Value: "paste", + } + + c, d, e := FindKeyNodeFullTop("lemons", []*yaml.Node{a, b}) + assert.Nil(t, c) + assert.Nil(t, d) + assert.Nil(t, e) +} + func TestMakeTagReadable(t *testing.T) { n := &yaml.Node{ Tag: "!!map", @@ -599,6 +627,8 @@ func TestDetectCase(t *testing.T) { 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, UnknownCase, DetectCase("")) + } func TestIsNodeRefValue(t *testing.T) { diff --git a/what-changed/model/comparison_functions.go b/what-changed/model/comparison_functions.go index 529525f..f1dd086 100644 --- a/what-changed/model/comparison_functions.go +++ b/what-changed/model/comparison_functions.go @@ -175,9 +175,10 @@ func CheckForModification[T any](l, r *yaml.Node, label string, changes *[]*Chan CreateChange(changes, Modified, label, l, r, breaking, orig, new) } // the values may have not changed, but the tag (node type) type may have - if l != nil && l.Value != "" && r != nil && r.Value != "" && r.Value != l.Value && r.Tag != l.Tag { - CreateChange(changes, Modified, label, l, r, breaking, orig, new) - } + // todo: this is currently untestable, no a single test triggers it (yet) + //if l != nil && l.Value != "" && r != nil && r.Value != "" && r.Value != l.Value && r.Tag != l.Tag { + // CreateChange(changes, Modified, label, l, r, breaking, orig, new) + //} } // CheckMapForChanges checks a left and right low level map for any additions, subtractions or modifications to @@ -227,6 +228,7 @@ func CheckMapForChanges[T any, R any](expLeft, expRight map[low.KeyReference[str chLock.Lock() expChanges[k] = compareFunc(p[k].Value, h[k].Value) chLock.Unlock() + doneChan <- true } @@ -256,75 +258,6 @@ func CheckMapForChanges[T any, R any](expLeft, expRight map[low.KeyReference[str return expChanges } -//// CheckMapForChangesUntyped checks a left and right low level map for any additions, subtractions or modifications to -//// values. The compareFunc can be generic and accept any type -//func CheckMapForChangesUntyped[T any, R any](expLeft, expRight map[low.KeyReference[string]]low.ValueReference[T], -// changes *[]*Change, label string, compareFunc func(l, r any) R) map[string]R { -// -// lHashes := make(map[string]string) -// rHashes := make(map[string]string) -// lValues := make(map[string]low.ValueReference[T]) -// rValues := make(map[string]low.ValueReference[T]) -// -// for k := range expLeft { -// lHashes[k.Value] = low.GenerateHashString(expLeft[k].Value) -// lValues[k.Value] = expLeft[k] -// } -// -// for k := range expRight { -// rHashes[k.Value] = low.GenerateHashString(expRight[k].Value) -// rValues[k.Value] = expRight[k] -// } -// -// expChanges := make(map[string]R) -// -// checkLeft := func(k string, doneChan chan bool, f, g map[string]string, p, h map[string]low.ValueReference[T]) { -// rhash := g[k] -// if rhash == "" { -// if p[k].GetValueNode().Value == "" { -// p[k].GetValueNode().Value = k // yes, a dirty thing, but it's clean for the consumer. -// } -// CreateChange(changes, ObjectRemoved, label, -// p[k].GetValueNode(), nil, true, -// p[k].GetValue(), nil) -// doneChan <- true -// return -// } -// if f[k] == g[k] { -// doneChan <- true -// return -// } -// // run comparison. -// expChanges[k] = compareFunc(p[k].Value, h[k].Value) -// doneChan <- true -// } -// -// doneChan := make(chan bool) -// count := 0 -// -// // check left example hashes -// for k := range lHashes { -// count++ -// go checkLeft(k, doneChan, lHashes, rHashes, lValues, rValues) -// } -// -// //check right example hashes -// for k := range rHashes { -// count++ -// go checkRightValue(k, doneChan, lHashes, rValues, changes, label) -// } -// -// // wait for all done signals. -// completed := 0 -// for completed < count { -// select { -// case <-doneChan: -// completed++ -// } -// } -// return expChanges -//} - func checkRightValue[T any](k string, doneChan chan bool, f map[string]string, p map[string]low.ValueReference[T], changes *[]*Change, label string, lock *sync.Mutex) { diff --git a/what-changed/model/components_test.go b/what-changed/model/components_test.go index 55a0b5a..703a411 100644 --- a/what-changed/model/components_test.go +++ b/what-changed/model/components_test.go @@ -8,6 +8,7 @@ import ( "github.com/pb33f/libopenapi/datamodel/low/v2" "github.com/pb33f/libopenapi/datamodel/low/v3" "github.com/pb33f/libopenapi/index" + "github.com/pb33f/libopenapi/resolver" "github.com/stretchr/testify/assert" "gopkg.in/yaml.v3" "testing" @@ -770,6 +771,50 @@ func TestCompareComponents_OpenAPI_Responses_FullBuild_IdenticalRef(t *testing.T assert.Nil(t, extChanges) } +func TestCompareComponents_OpenAPI_Responses_FullBuild_CircularRef(t *testing.T) { + left := `components: + responses: + coffee: + $ref: '#/components/responses/tv' + tv: + $ref: '#/components/responses/coffee'` + + right := `components: + responses: + coffee: + $ref: '#/components/responses/tv' + tv: + $ref: '#/components/responses/coffee'` + + var lNode, rNode yaml.Node + _ = yaml.Unmarshal([]byte(left), &lNode) + _ = yaml.Unmarshal([]byte(right), &rNode) + + // create low level objects + var lDoc v3.Components + var rDoc v3.Components + + _ = low.BuildModel(lNode.Content[0], &lDoc) + _ = low.BuildModel(rNode.Content[0], &rDoc) + + idx := index.NewSpecIndex(&lNode) + idx2 := index.NewSpecIndex(&rNode) + + // resolver required to check circular refs. + re1 := resolver.NewResolver(idx) + re2 := resolver.NewResolver(idx2) + + re1.CheckForCircularReferences() + re2.CheckForCircularReferences() + + _ = lDoc.Build(lNode.Content[0], idx) + _ = rDoc.Build(rNode.Content[0], idx2) + + // compare. + extChanges := CompareComponents(&lDoc, &rDoc) + assert.Nil(t, extChanges) +} + func TestCompareComponents_OpenAPI_Responses_Modify(t *testing.T) { left := `responses: @@ -1205,6 +1250,38 @@ func TestCompareComponents_OpenAPI_SecuritySchemes_Equal(t *testing.T) { assert.Nil(t, extChanges) } +func TestCompareComponents_OpenAPI_SecuritySchemes_Modified(t *testing.T) { + + left := `securitySchemes: + scheme1: + description: a scheme + scheme2: + description: another scheme` + + right := `securitySchemes: + scheme1: + description: a scheme that changed + scheme2: + description: another scheme that also changed` + + var lNode, rNode yaml.Node + _ = yaml.Unmarshal([]byte(left), &lNode) + _ = yaml.Unmarshal([]byte(right), &rNode) + + // create low level objects + var lDoc v3.Components + var rDoc v3.Components + _ = low.BuildModel(lNode.Content[0], &lDoc) + _ = low.BuildModel(rNode.Content[0], &rDoc) + _ = lDoc.Build(lNode.Content[0], nil) + _ = rDoc.Build(rNode.Content[0], nil) + + // compare. + extChanges := CompareComponents(&lDoc, &rDoc) + assert.Equal(t, 2, extChanges.TotalChanges()) + assert.Equal(t, 0, extChanges.TotalBreakingChanges()) +} + func TestCompareComponents_OpenAPI_Links_Equal(t *testing.T) { left := `links: diff --git a/what-changed/model/schema_test.go b/what-changed/model/schema_test.go index 03be331..81c7926 100644 --- a/what-changed/model/schema_test.go +++ b/what-changed/model/schema_test.go @@ -225,7 +225,7 @@ func TestCompareSchemas_RefChanged(t *testing.T) { assert.NotNil(t, changes) assert.Len(t, changes.Changes, 1) assert.Equal(t, Modified, changes.Changes[0].ChangeType) - assert.Equal(t, "string", changes.Changes[0].New) + assert.Equal(t, "#/components/schemas/Yo", changes.Changes[0].New) } func TestCompareSchemas_RefToInline(t *testing.T) { @@ -253,8 +253,8 @@ func TestCompareSchemas_RefToInline(t *testing.T) { assert.NotNil(t, changes) assert.Len(t, changes.Changes, 1) assert.Equal(t, Modified, changes.Changes[0].ChangeType) - assert.Equal(t, v3.TypeLabel, changes.Changes[0].Property) - assert.Equal(t, "int", changes.Changes[0].Original) + assert.Equal(t, v3.RefLabel, changes.Changes[0].Property) + assert.Equal(t, "#/components/schemas/Yo", changes.Changes[0].Original) } @@ -283,8 +283,8 @@ func TestCompareSchemas_InlineToRef(t *testing.T) { assert.NotNil(t, changes) assert.Len(t, changes.Changes, 1) assert.Equal(t, Modified, changes.Changes[0].ChangeType) - assert.Equal(t, v3.TypeLabel, changes.Changes[0].Property) - assert.Equal(t, "int", changes.Changes[0].New) + assert.Equal(t, v3.RefLabel, changes.Changes[0].Property) + assert.Equal(t, "#/components/schemas/Yo", changes.Changes[0].New) } @@ -313,6 +313,31 @@ func TestCompareSchemas_Identical(t *testing.T) { assert.Nil(t, changes) } +func TestCompareSchemas_Identical_Ref(t *testing.T) { + left := `components: + schemas: + Yo: + type: int + OK: + $ref: '#/components/schemas/Yo'` + + right := `components: + schemas: + Yo: + type: int + OK: + $ref: '#/components/schemas/Yo'` + + leftDoc, rightDoc := test_BuildDoc(left, right) + + // extract left reference schema and non reference schema. + lSchemaProxy := leftDoc.Components.Value.FindSchema("OK").Value + rSchemaProxy := rightDoc.Components.Value.FindSchema("OK").Value + + changes := CompareSchemas(rSchemaProxy, lSchemaProxy) + assert.Nil(t, changes) +} + func TestCompareSchemas_RequiredAdded(t *testing.T) { left := `components: schemas: