Fixed a low level bug with locating nodes.

locating nodes was looking through two levels to locate something. This is not the correct behavior, after making the change - lots of tests needed to be updated to be correct in what they put into as a the root node.
This commit is contained in:
Dave Shanley
2022-11-04 09:50:20 -04:00
parent 131513a6f6
commit a184c5e909
34 changed files with 220 additions and 161 deletions

View File

@@ -24,7 +24,7 @@ email: buckaroo@pb33f.io`
// build low // build low
var lowContact lowbase.Contact var lowContact lowbase.Contact
_ = lowmodel.BuildModel(&cNode, &lowContact) _ = lowmodel.BuildModel(cNode.Content[0], &lowContact)
// build high // build high
highContact := NewContact(&lowContact) highContact := NewContact(&lowContact)
@@ -49,7 +49,7 @@ email: buckaroo@pb33f.io`
// build low // build low
var lowContact lowbase.Contact var lowContact lowbase.Contact
_ = lowmodel.BuildModel(&cNode, &lowContact) _ = lowmodel.BuildModel(cNode.Content[0], &lowContact)
// build high // build high
highContact := NewContact(&lowContact) highContact := NewContact(&lowContact)

View File

@@ -4,56 +4,56 @@
package base package base
import ( import (
"fmt" "fmt"
lowmodel "github.com/pb33f/libopenapi/datamodel/low" lowmodel "github.com/pb33f/libopenapi/datamodel/low"
lowbase "github.com/pb33f/libopenapi/datamodel/low/base" lowbase "github.com/pb33f/libopenapi/datamodel/low/base"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
"testing" "testing"
) )
func TestNewDiscriminator(t *testing.T) { func TestNewDiscriminator(t *testing.T) {
var cNode yaml.Node var cNode yaml.Node
yml := `propertyName: coffee yml := `propertyName: coffee
mapping: mapping:
fogCleaner: in the morning` fogCleaner: in the morning`
_ = yaml.Unmarshal([]byte(yml), &cNode) _ = yaml.Unmarshal([]byte(yml), &cNode)
// build low // build low
var lowDiscriminator lowbase.Discriminator var lowDiscriminator lowbase.Discriminator
_ = lowmodel.BuildModel(&cNode, &lowDiscriminator) _ = lowmodel.BuildModel(cNode.Content[0], &lowDiscriminator)
// build high // build high
highDiscriminator := NewDiscriminator(&lowDiscriminator) highDiscriminator := NewDiscriminator(&lowDiscriminator)
assert.Equal(t, "coffee", highDiscriminator.PropertyName) assert.Equal(t, "coffee", highDiscriminator.PropertyName)
assert.Equal(t, "in the morning", highDiscriminator.Mapping["fogCleaner"]) assert.Equal(t, "in the morning", highDiscriminator.Mapping["fogCleaner"])
assert.Equal(t, 3, highDiscriminator.GoLow().FindMappingValue("fogCleaner").ValueNode.Line) assert.Equal(t, 3, highDiscriminator.GoLow().FindMappingValue("fogCleaner").ValueNode.Line)
} }
func ExampleNewDiscriminator() { func ExampleNewDiscriminator() {
// create a yaml representation of a discriminator (can be JSON, doesn't matter) // create a yaml representation of a discriminator (can be JSON, doesn't matter)
yml := `propertyName: coffee yml := `propertyName: coffee
mapping: mapping:
coffee: in the morning` coffee: in the morning`
// unmarshal into a *yaml.Node // unmarshal into a *yaml.Node
var node yaml.Node var node yaml.Node
_ = yaml.Unmarshal([]byte(yml), &node) _ = yaml.Unmarshal([]byte(yml), &node)
// build low-level model // build low-level model
var lowDiscriminator lowbase.Discriminator var lowDiscriminator lowbase.Discriminator
_ = lowmodel.BuildModel(&node, &lowDiscriminator) _ = lowmodel.BuildModel(node.Content[0], &lowDiscriminator)
// build high-level model // build high-level model
highDiscriminator := NewDiscriminator(&lowDiscriminator) highDiscriminator := NewDiscriminator(&lowDiscriminator)
// print out a mapping defined for the discriminator. // print out a mapping defined for the discriminator.
fmt.Print(highDiscriminator.Mapping["coffee"]) fmt.Print(highDiscriminator.Mapping["coffee"])
// Output: in the morning // Output: in the morning
} }

View File

@@ -26,7 +26,7 @@ x-hack: code`
// build low // build low
var lowExample lowbase.Example var lowExample lowbase.Example
_ = lowmodel.BuildModel(&cNode, &lowExample) _ = lowmodel.BuildModel(cNode.Content[0], &lowExample)
_ = lowExample.Build(cNode.Content[0], nil) _ = lowExample.Build(cNode.Content[0], nil)
@@ -50,7 +50,7 @@ func TestExtractExamples(t *testing.T) {
// build low // build low
var lowExample lowbase.Example var lowExample lowbase.Example
_ = lowmodel.BuildModel(&cNode, &lowExample) _ = lowmodel.BuildModel(cNode.Content[0], &lowExample)
_ = lowExample.Build(cNode.Content[0], nil) _ = lowExample.Build(cNode.Content[0], nil)
@@ -79,7 +79,7 @@ x-hack: code`
// build low-level example // build low-level example
var lowExample lowbase.Example var lowExample lowbase.Example
_ = lowmodel.BuildModel(&node, &lowExample) _ = lowmodel.BuildModel(node.Content[0], &lowExample)
// build out low-level example // build out low-level example
_ = lowExample.Build(node.Content[0], nil) _ = lowExample.Build(node.Content[0], nil)
@@ -90,4 +90,4 @@ x-hack: code`
fmt.Print(highExample.ExternalValue) fmt.Print(highExample.ExternalValue)
// Output: https://pb33f.io // Output: https://pb33f.io
} }

View File

@@ -23,7 +23,7 @@ x-hack: code`
_ = yaml.Unmarshal([]byte(yml), &cNode) _ = yaml.Unmarshal([]byte(yml), &cNode)
var lowExt lowbase.ExternalDoc var lowExt lowbase.ExternalDoc
_ = lowmodel.BuildModel(&cNode, &lowExt) _ = lowmodel.BuildModel(cNode.Content[0], &lowExt)
_ = lowExt.Build(cNode.Content[0], nil) _ = lowExt.Build(cNode.Content[0], nil)
@@ -51,7 +51,7 @@ x-hack: code`
// build low-level ExternalDoc // build low-level ExternalDoc
var lowExt lowbase.ExternalDoc var lowExt lowbase.ExternalDoc
_ = lowmodel.BuildModel(&node, &lowExt) _ = lowmodel.BuildModel(node.Content[0], &lowExt)
// build out low-level properties (like extensions) // build out low-level properties (like extensions)
_ = lowExt.Build(node.Content[0], nil) _ = lowExt.Build(node.Content[0], nil)

View File

@@ -31,7 +31,7 @@ x-cli-name: chicken cli`
_ = yaml.Unmarshal([]byte(yml), &cNode) _ = yaml.Unmarshal([]byte(yml), &cNode)
var lowInfo lowbase.Info var lowInfo lowbase.Info
_ = lowmodel.BuildModel(&cNode, &lowInfo) _ = lowmodel.BuildModel(cNode.Content[0], &lowInfo)
_ = lowInfo.Build(cNode.Content[0], nil) _ = lowInfo.Build(cNode.Content[0], nil)
highInfo := NewInfo(&lowInfo) highInfo := NewInfo(&lowInfo)
@@ -97,7 +97,7 @@ url: https://opensource.org/licenses/MIT`
// build out the low-level model // build out the low-level model
var lowLicense lowbase.License var lowLicense lowbase.License
_ = lowmodel.BuildModel(&node, &lowLicense) _ = lowmodel.BuildModel(node.Content[0], &lowLicense)
_ = lowLicense.Build(node.Content[0], nil) _ = lowLicense.Build(node.Content[0], nil)
// build the high level model // build the high level model

View File

@@ -4,66 +4,66 @@
package base package base
import ( import (
"fmt" "fmt"
lowmodel "github.com/pb33f/libopenapi/datamodel/low" lowmodel "github.com/pb33f/libopenapi/datamodel/low"
lowbase "github.com/pb33f/libopenapi/datamodel/low/base" lowbase "github.com/pb33f/libopenapi/datamodel/low/base"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
"testing" "testing"
) )
func TestNewTag(t *testing.T) { func TestNewTag(t *testing.T) {
var cNode yaml.Node var cNode yaml.Node
yml := `name: chicken yml := `name: chicken
description: nuggets description: nuggets
externalDocs: externalDocs:
url: https://pb33f.io url: https://pb33f.io
x-hack: code` x-hack: code`
_ = yaml.Unmarshal([]byte(yml), &cNode) _ = yaml.Unmarshal([]byte(yml), &cNode)
var lowTag lowbase.Tag var lowTag lowbase.Tag
_ = lowmodel.BuildModel(&cNode, &lowTag) _ = lowmodel.BuildModel(cNode.Content[0], &lowTag)
_ = lowTag.Build(cNode.Content[0], nil) _ = lowTag.Build(cNode.Content[0], nil)
highTag := NewTag(&lowTag) highTag := NewTag(&lowTag)
assert.Equal(t, "chicken", highTag.Name) assert.Equal(t, "chicken", highTag.Name)
assert.Equal(t, "nuggets", highTag.Description) assert.Equal(t, "nuggets", highTag.Description)
assert.Equal(t, "https://pb33f.io", highTag.ExternalDocs.URL) assert.Equal(t, "https://pb33f.io", highTag.ExternalDocs.URL)
assert.Equal(t, "code", highTag.Extensions["x-hack"]) assert.Equal(t, "code", highTag.Extensions["x-hack"])
wentLow := highTag.GoLow() wentLow := highTag.GoLow()
assert.Equal(t, 5, wentLow.FindExtension("x-hack").ValueNode.Line) assert.Equal(t, 5, wentLow.FindExtension("x-hack").ValueNode.Line)
} }
func ExampleNewTag() { func ExampleNewTag() {
// create an example schema object // create an example schema object
// this can be either JSON or YAML. // this can be either JSON or YAML.
yml := ` yml := `
name: Purchases name: Purchases
description: All kinds of purchase related operations description: All kinds of purchase related operations
externalDocs: externalDocs:
url: https://pb33f.io/purchases url: https://pb33f.io/purchases
x-hack: code` x-hack: code`
// unmarshal raw bytes // unmarshal raw bytes
var node yaml.Node var node yaml.Node
_ = yaml.Unmarshal([]byte(yml), &node) _ = yaml.Unmarshal([]byte(yml), &node)
// build out the low-level model // build out the low-level model
var lowTag lowbase.Tag var lowTag lowbase.Tag
_ = lowmodel.BuildModel(&node, &lowTag) _ = lowmodel.BuildModel(node.Content[0], &lowTag)
_ = lowTag.Build(node.Content[0], nil) _ = lowTag.Build(node.Content[0], nil)
// build the high level tag // build the high level tag
highTag := NewTag(&lowTag) highTag := NewTag(&lowTag)
// print out the tag name // print out the tag name
fmt.Print(highTag.Name) fmt.Print(highTag.Name)
// Output: Purchases // Output: Purchases
} }

View File

@@ -4,33 +4,33 @@
package base package base
import ( import (
"fmt" "fmt"
lowmodel "github.com/pb33f/libopenapi/datamodel/low" lowmodel "github.com/pb33f/libopenapi/datamodel/low"
lowbase "github.com/pb33f/libopenapi/datamodel/low/base" lowbase "github.com/pb33f/libopenapi/datamodel/low/base"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
) )
func ExampleNewXML() { func ExampleNewXML() {
// create an example schema object // create an example schema object
// this can be either JSON or YAML. // this can be either JSON or YAML.
yml := ` yml := `
namespace: https://pb33f.io/schema namespace: https://pb33f.io/schema
prefix: sample` prefix: sample`
// unmarshal raw bytes // unmarshal raw bytes
var node yaml.Node var node yaml.Node
_ = yaml.Unmarshal([]byte(yml), &node) _ = yaml.Unmarshal([]byte(yml), &node)
// build out the low-level model // build out the low-level model
var lowXML lowbase.XML var lowXML lowbase.XML
_ = lowmodel.BuildModel(&node, &lowXML) _ = lowmodel.BuildModel(node.Content[0], &lowXML)
_ = lowXML.Build(node.Content[0], nil) _ = lowXML.Build(node.Content[0], nil)
// build the high level tag // build the high level tag
highXML := NewXML(&lowXML) highXML := NewXML(&lowXML)
// print out the XML namespace // print out the XML namespace
fmt.Print(highXML.Namespace) fmt.Print(highXML.Namespace)
// Output: https://pb33f.io/schema // Output: https://pb33f.io/schema
} }

View File

@@ -36,7 +36,7 @@ links:
idx := index.NewSpecIndex(&idxNode) idx := index.NewSpecIndex(&idxNode)
var n v3.Response var n v3.Response
_ = low.BuildModel(&idxNode, &n) _ = low.BuildModel(idxNode.Content[0], &n)
_ = n.Build(idxNode.Content[0], idx) _ = n.Build(idxNode.Content[0], idx)
r := NewResponse(&n) r := NewResponse(&n)

View File

@@ -20,7 +20,7 @@ mapping:
assert.NoError(t, mErr) assert.NoError(t, mErr)
var n Discriminator var n Discriminator
err := low.BuildModel(&idxNode, &n) err := low.BuildModel(idxNode.Content[0], &n)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, "nothing", n.FindMappingValue("something").Value) assert.Equal(t, "nothing", n.FindMappingValue("something").Value)
assert.Nil(t, n.FindMappingValue("freshCakes")) assert.Nil(t, n.FindMappingValue("freshCakes"))

View File

@@ -23,7 +23,7 @@ x-cake: hot`
idx := index.NewSpecIndex(&idxNode) idx := index.NewSpecIndex(&idxNode)
var n Example var n Example
err := low.BuildModel(&idxNode, &n) err := low.BuildModel(idxNode.Content[0], &n)
assert.NoError(t, err) assert.NoError(t, err)
err = n.Build(idxNode.Content[0], idx) err = n.Build(idxNode.Content[0], idx)
@@ -49,7 +49,7 @@ x-cake: hot`
idx := index.NewSpecIndex(&idxNode) idx := index.NewSpecIndex(&idxNode)
var n Example var n Example
err := low.BuildModel(&idxNode, &n) err := low.BuildModel(idxNode.Content[0], &n)
assert.NoError(t, err) assert.NoError(t, err)
err = n.Build(idxNode.Content[0], idx) err = n.Build(idxNode.Content[0], idx)
@@ -76,7 +76,7 @@ value:
idx := index.NewSpecIndex(&idxNode) idx := index.NewSpecIndex(&idxNode)
var n Example var n Example
err := low.BuildModel(&idxNode, &n) err := low.BuildModel(idxNode.Content[0], &n)
assert.NoError(t, err) assert.NoError(t, err)
err = n.Build(idxNode.Content[0], idx) err = n.Build(idxNode.Content[0], idx)
@@ -107,7 +107,7 @@ value:
idx := index.NewSpecIndex(&idxNode) idx := index.NewSpecIndex(&idxNode)
var n Example var n Example
err := low.BuildModel(&idxNode, &n) err := low.BuildModel(idxNode.Content[0], &n)
assert.NoError(t, err) assert.NoError(t, err)
err = n.Build(idxNode.Content[0], idx) err = n.Build(idxNode.Content[0], idx)

View File

@@ -41,7 +41,7 @@ x-b33f: princess`
idx := index.NewSpecIndex(&idxNode) idx := index.NewSpecIndex(&idxNode)
var n ExternalDoc var n ExternalDoc
err := low.BuildModel(&idxNode, &n) err := low.BuildModel(idxNode.Content[0], &n)
assert.NoError(t, err) assert.NoError(t, err)
err = n.Build(idxNode.Content[0], idx) err = n.Build(idxNode.Content[0], idx)

View File

@@ -31,7 +31,7 @@ x-cli-name: pizza cli`
idx := index.NewSpecIndex(&idxNode) idx := index.NewSpecIndex(&idxNode)
var n Info var n Info
err := low.BuildModel(&idxNode, &n) err := low.BuildModel(idxNode.Content[0], &n)
assert.NoError(t, err) assert.NoError(t, err)
err = n.Build(idxNode.Content[0], idx) err = n.Build(idxNode.Content[0], idx)

View File

@@ -17,7 +17,7 @@ func TestSchemaProxy_Build(t *testing.T) {
var idxNode yaml.Node var idxNode yaml.Node
_ = yaml.Unmarshal([]byte(yml), &idxNode) _ = yaml.Unmarshal([]byte(yml), &idxNode)
err := sch.Build(&idxNode, nil) err := sch.Build(idxNode.Content[0], nil)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, "something", sch.Schema().Description.Value) assert.Equal(t, "something", sch.Schema().Description.Value)
assert.Empty(t, sch.GetSchemaReference()) assert.Empty(t, sch.GetSchemaReference())

View File

@@ -125,7 +125,7 @@ func Test_Schema(t *testing.T) {
assert.NoError(t, mErr) assert.NoError(t, mErr)
sch := Schema{} sch := Schema{}
mbErr := low.BuildModel(&rootNode, &sch) mbErr := low.BuildModel(rootNode.Content[0], &sch)
assert.NoError(t, mbErr) assert.NoError(t, mbErr)
schErr := sch.Build(rootNode.Content[0], nil) schErr := sch.Build(rootNode.Content[0], nil)
@@ -280,7 +280,7 @@ examples:
assert.NoError(t, mErr) assert.NoError(t, mErr)
sch := Schema{} sch := Schema{}
mbErr := low.BuildModel(&rootNode, &sch) mbErr := low.BuildModel(rootNode.Content[0], &sch)
assert.NoError(t, mbErr) assert.NoError(t, mbErr)
schErr := sch.Build(rootNode.Content[0], nil) schErr := sch.Build(rootNode.Content[0], nil)

View File

@@ -24,7 +24,7 @@ x-coffee: tasty`
idx := index.NewSpecIndex(&idxNode) idx := index.NewSpecIndex(&idxNode)
var n Tag var n Tag
err := low.BuildModel(&idxNode, &n) err := low.BuildModel(idxNode.Content[0], &n)
assert.NoError(t, err) assert.NoError(t, err)
err = n.Build(idxNode.Content[0], idx) err = n.Build(idxNode.Content[0], idx)

View File

@@ -519,7 +519,7 @@ func TestExtractObjectRaw(t *testing.T) {
var cNode yaml.Node var cNode yaml.Node
_ = yaml.Unmarshal([]byte(yml), &cNode) _ = yaml.Unmarshal([]byte(yml), &cNode)
tag, err := ExtractObjectRaw[*pizza](&cNode, idx) tag, err := ExtractObjectRaw[*pizza](cNode.Content[0], idx)
assert.NoError(t, err) assert.NoError(t, err)
assert.NotNil(t, tag) assert.NotNil(t, tag)
assert.Equal(t, "hello pizza", tag.Description.Value) assert.Equal(t, "hello pizza", tag.Description.Value)
@@ -1143,8 +1143,7 @@ func TestExtractMapFlat_DoubleRef(t *testing.T) {
yml := `components: yml := `components:
schemas: schemas:
stank: stank:
things: almostWork: 99`
almostWork: 99`
var idxNode yaml.Node var idxNode yaml.Node
mErr := yaml.Unmarshal([]byte(yml), &idxNode) mErr := yaml.Unmarshal([]byte(yml), &idxNode)

View File

@@ -46,7 +46,7 @@ func BuildModel(node *yaml.Node, model interface{}) error {
var vn, kn *yaml.Node var vn, kn *yaml.Node
for _, tryCase := range cases { for _, tryCase := range cases {
kn, vn = utils.FindKeyNode(utils.ConvertCase(fName, tryCase), node.Content) kn, vn = utils.FindKeyNodeTop(utils.ConvertCase(fName, tryCase), node.Content)
if vn != nil { if vn != nil {
break break
} }

View File

@@ -104,7 +104,7 @@ there:
assert.NoError(t, mErr) assert.NoError(t, mErr)
hd := hotdog{} hd := hotdog{}
cErr := BuildModel(&rootNode, &hd) cErr := BuildModel(rootNode.Content[0], &hd)
assert.Equal(t, 200, hd.Fat.Value) assert.Equal(t, 200, hd.Fat.Value)
assert.Equal(t, 3, hd.Fat.ValueNode.Line) assert.Equal(t, 3, hd.Fat.ValueNode.Line)
assert.Equal(t, true, hd.Grilled.Value) assert.Equal(t, true, hd.Grilled.Value)
@@ -156,7 +156,7 @@ func TestBuildModel_UseUnsupportedPrimitive(t *testing.T) {
mErr := yaml.Unmarshal([]byte(yml), &rootNode) mErr := yaml.Unmarshal([]byte(yml), &rootNode)
assert.NoError(t, mErr) assert.NoError(t, mErr)
cErr := BuildModel(&rootNode, &ns) cErr := BuildModel(rootNode.Content[0], &ns)
assert.Error(t, cErr) assert.Error(t, cErr)
assert.Empty(t, ns.cake) assert.Empty(t, ns.cake)
@@ -183,7 +183,7 @@ thing: yeah`
try := BuildModel(nil, ins) try := BuildModel(nil, ins)
assert.NoError(t, try) assert.NoError(t, try)
cErr := BuildModel(&rootNode, ins) cErr := BuildModel(rootNode.Content[0], ins)
assert.NoError(t, cErr) assert.NoError(t, cErr)
assert.Empty(t, ins.PathItems.Value) assert.Empty(t, ins.PathItems.Value)
assert.Empty(t, ins.Extensions.Value) assert.Empty(t, ins.Extensions.Value)
@@ -205,7 +205,7 @@ func TestSetField_NodeRefAny_Error(t *testing.T) {
mErr := yaml.Unmarshal([]byte(yml), &rootNode) mErr := yaml.Unmarshal([]byte(yml), &rootNode)
assert.NoError(t, mErr) assert.NoError(t, mErr)
try := BuildModel(&rootNode, ins) try := BuildModel(rootNode.Content[0], ins)
assert.Error(t, try) assert.Error(t, try)
} }
@@ -226,7 +226,7 @@ func TestSetField_MapHelperWrapped(t *testing.T) {
mErr := yaml.Unmarshal([]byte(yml), &rootNode) mErr := yaml.Unmarshal([]byte(yml), &rootNode)
assert.NoError(t, mErr) assert.NoError(t, mErr)
try := BuildModel(&rootNode, ins) try := BuildModel(rootNode.Content[0], ins)
assert.NoError(t, try) assert.NoError(t, try)
assert.Len(t, ins.Thing.Value, 3) assert.Len(t, ins.Thing.Value, 3)
} }
@@ -247,7 +247,7 @@ func TestSetField_MapHelper(t *testing.T) {
mErr := yaml.Unmarshal([]byte(yml), &rootNode) mErr := yaml.Unmarshal([]byte(yml), &rootNode)
assert.NoError(t, mErr) assert.NoError(t, mErr)
try := BuildModel(&rootNode, ins) try := BuildModel(rootNode.Content[0], ins)
assert.NoError(t, try) assert.NoError(t, try)
assert.Len(t, ins.Thing, 3) assert.Len(t, ins.Thing, 3)
} }
@@ -268,7 +268,7 @@ func TestSetField_ArrayHelper(t *testing.T) {
mErr := yaml.Unmarshal([]byte(yml), &rootNode) mErr := yaml.Unmarshal([]byte(yml), &rootNode)
assert.NoError(t, mErr) assert.NoError(t, mErr)
try := BuildModel(&rootNode, ins) try := BuildModel(rootNode.Content[0], ins)
assert.NoError(t, try) assert.NoError(t, try)
assert.Len(t, ins.Thing.Value, 3) assert.Len(t, ins.Thing.Value, 3)
} }
@@ -316,7 +316,7 @@ func TestBuildModelAsync(t *testing.T) {
var wg sync.WaitGroup var wg sync.WaitGroup
var errors []error var errors []error
wg.Add(1) wg.Add(1)
BuildModelAsync(&rootNode, ins, &wg, &errors) BuildModelAsync(rootNode.Content[0], ins, &wg, &errors)
wg.Wait() wg.Wait()
assert.Len(t, ins.Thing.Value, 3) assert.Len(t, ins.Thing.Value, 3)
@@ -340,7 +340,7 @@ func TestBuildModelAsync_Error(t *testing.T) {
var wg sync.WaitGroup var wg sync.WaitGroup
var errors []error var errors []error
wg.Add(1) wg.Add(1)
BuildModelAsync(&rootNode, ins, &wg, &errors) BuildModelAsync(rootNode.Content[0], ins, &wg, &errors)
wg.Wait() wg.Wait()
assert.Len(t, errors, 1) assert.Len(t, errors, 1)
assert.Len(t, ins.Thing, 0) assert.Len(t, ins.Thing, 0)

View File

@@ -4,9 +4,12 @@
package v2 package v2
import ( import (
"crypto/sha256"
"fmt"
"github.com/pb33f/libopenapi/datamodel/low" "github.com/pb33f/libopenapi/datamodel/low"
"github.com/pb33f/libopenapi/index" "github.com/pb33f/libopenapi/index"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
"sort"
"strings" "strings"
) )
@@ -26,6 +29,16 @@ func (p *Paths) FindPath(path string) *low.ValueReference[*PathItem] {
return nil return nil
} }
// FindPathAndKey attempts to locate a PathItem instance, given a path key.
func (p *Paths) FindPathAndKey(path string) (*low.KeyReference[string], *low.ValueReference[*PathItem]) {
for k, j := range p.PathItems {
if k.Value == path {
return &k, &j
}
}
return nil, nil
}
// FindExtension will attempt to locate an extension value given a name. // FindExtension will attempt to locate an extension value given a name.
func (p *Paths) FindExtension(ext string) *low.ValueReference[any] { func (p *Paths) FindExtension(ext string) *low.ValueReference[any] {
return low.FindItemInMap[any](ext, p.Extensions) return low.FindItemInMap[any](ext, p.Extensions)
@@ -96,3 +109,25 @@ func (p *Paths) Build(root *yaml.Node, idx *index.SpecIndex) error {
p.PathItems = pathsMap p.PathItems = pathsMap
return nil return nil
} }
// Hash will return a consistent SHA256 Hash of the PathItem object
func (p *Paths) Hash() [32]byte {
var f []string
l := make([]string, len(p.PathItems))
keys := make(map[string]low.ValueReference[*PathItem])
z := 0
for k := range p.PathItems {
keys[k.Value] = p.PathItems[k]
l[z] = k.Value
z++
}
sort.Strings(l)
for k := range l {
f = append(f, low.GenerateHashString(keys[l[k]].Value))
}
for k := range p.Extensions {
f = append(f, fmt.Sprintf("%s-%x", k.Value,
sha256.Sum256([]byte(fmt.Sprint(p.Extensions[k].Value)))))
}
return sha256.Sum256([]byte(strings.Join(f, "|")))
}

View File

@@ -111,7 +111,7 @@ type Swagger struct {
SpecInfo *datamodel.SpecInfo SpecInfo *datamodel.SpecInfo
} }
// FindExte // FindExtension locates an extension from the root of the Swagger document.
func (s *Swagger) FindExtension(ext string) *low.ValueReference[any] { func (s *Swagger) FindExtension(ext string) *low.ValueReference[any] {
return low.FindItemInMap[any](ext, s.Extensions) return low.FindItemInMap[any](ext, s.Extensions)
} }
@@ -129,7 +129,7 @@ func CreateDocument(info *datamodel.SpecInfo) (*Swagger, []error) {
var errors []error var errors []error
// build out swagger scalar variables. // build out swagger scalar variables.
_ = low.BuildModel(info.RootNode, &doc) _ = low.BuildModel(info.RootNode.Content[0], &doc)
// extract externalDocs // extract externalDocs
extDocs, err := low.ExtractObject[*base.ExternalDoc](base.ExternalDocsLabel, info.RootNode, idx) extDocs, err := low.ExtractObject[*base.ExternalDoc](base.ExternalDocsLabel, info.RootNode, idx)

View File

@@ -44,6 +44,7 @@ func BenchmarkCreateDocument(b *testing.B) {
func TestCreateDocument(t *testing.T) { func TestCreateDocument(t *testing.T) {
initTest() initTest()
doc := doc
assert.Equal(t, "2.0", doc.SpecInfo.Version) assert.Equal(t, "2.0", doc.SpecInfo.Version)
assert.Equal(t, "1.0.6", doc.Info.Value.Version.Value) assert.Equal(t, "1.0.6", doc.Info.Value.Version.Value)
assert.Equal(t, "petstore.swagger.io", doc.Host.Value) assert.Equal(t, "petstore.swagger.io", doc.Host.Value)

View File

@@ -70,7 +70,7 @@ func TestComponents_Build_Success(t *testing.T) {
idx := index.NewSpecIndex(&idxNode) idx := index.NewSpecIndex(&idxNode)
var n Components var n Components
err := low.BuildModel(&idxNode, &n) err := low.BuildModel(idxNode.Content[0], &n)
assert.NoError(t, err) assert.NoError(t, err)
err = n.Build(idxNode.Content[0], idx) err = n.Build(idxNode.Content[0], idx)
@@ -93,9 +93,9 @@ func TestComponents_Build_Success(t *testing.T) {
assert.Equal(t, "fifteen of many", n.FindLink("fifteen").Value.Description.Value) assert.Equal(t, "fifteen of many", n.FindLink("fifteen").Value.Description.Value)
assert.Equal(t, "sixteen of many", n.FindLink("sixteen").Value.Description.Value) assert.Equal(t, "sixteen of many", n.FindLink("sixteen").Value.Description.Value)
assert.Equal(t, "seventeen of many", assert.Equal(t, "seventeen of many",
n.FindCallback("seventeen").Value.FindExpression("{reference}").Value.Description.Value) n.FindCallback("seventeen").Value.FindExpression("{reference}").Value.Post.Value.Description.Value)
assert.Equal(t, "eighteen of many", assert.Equal(t, "eighteen of many",
n.FindCallback("eighteen").Value.FindExpression("{raference}").Value.Description.Value) n.FindCallback("eighteen").Value.FindExpression("{raference}").Value.Post.Value.Description.Value)
} }

View File

@@ -16,6 +16,7 @@ const (
CallbacksLabel = "callbacks" CallbacksLabel = "callbacks"
ContentLabel = "content" ContentLabel = "content"
PathsLabel = "paths" PathsLabel = "paths"
PathLabel = "path"
WebhooksLabel = "webhooks" WebhooksLabel = "webhooks"
JSONSchemaDialectLabel = "jsonSchemaDialect" JSONSchemaDialectLabel = "jsonSchemaDialect"
GetLabel = "get" GetLabel = "get"

View File

@@ -28,7 +28,7 @@ explode: true`
idx := index.NewSpecIndex(&idxNode) idx := index.NewSpecIndex(&idxNode)
var n Encoding var n Encoding
err := low.BuildModel(&idxNode, &n) err := low.BuildModel(idxNode.Content[0], &n)
assert.NoError(t, err) assert.NoError(t, err)
err = n.Build(idxNode.Content[0], idx) err = n.Build(idxNode.Content[0], idx)

View File

@@ -49,7 +49,7 @@ content:
idx := index.NewSpecIndex(&idxNode) idx := index.NewSpecIndex(&idxNode)
var n Header var n Header
err := low.BuildModel(&idxNode, &n) err := low.BuildModel(idxNode.Content[0], &n)
assert.NoError(t, err) assert.NoError(t, err)
err = n.Build(idxNode.Content[0], idx) err = n.Build(idxNode.Content[0], idx)

View File

@@ -30,7 +30,7 @@ x-linky: slinky
idx := index.NewSpecIndex(&idxNode) idx := index.NewSpecIndex(&idxNode)
var n Link var n Link
err := low.BuildModel(&idxNode, &n) err := low.BuildModel(idxNode.Content[0], &n)
assert.NoError(t, err) assert.NoError(t, err)
err = n.Build(idxNode.Content[0], idx) err = n.Build(idxNode.Content[0], idx)

View File

@@ -27,7 +27,7 @@ x-tasty: herbs
idx := index.NewSpecIndex(&idxNode) idx := index.NewSpecIndex(&idxNode)
var n OAuthFlow var n OAuthFlow
err := low.BuildModel(&idxNode, &n) err := low.BuildModel(idxNode.Content[0], &n)
assert.NoError(t, err) assert.NoError(t, err)
err = n.Build(idxNode.Content[0], idx) err = n.Build(idxNode.Content[0], idx)

View File

@@ -46,7 +46,7 @@ servers:
idx := index.NewSpecIndex(&idxNode) idx := index.NewSpecIndex(&idxNode)
var n Operation var n Operation
err := low.BuildModel(&idxNode, &n) err := low.BuildModel(idxNode.Content[0], &n)
assert.NoError(t, err) assert.NoError(t, err)
err = n.Build(idxNode.Content[0], idx) err = n.Build(idxNode.Content[0], idx)

View File

@@ -51,7 +51,7 @@ content:
idx := index.NewSpecIndex(&idxNode) idx := index.NewSpecIndex(&idxNode)
var n Parameter var n Parameter
err := low.BuildModel(&idxNode, &n) err := low.BuildModel(idxNode.Content[0], &n)
assert.NoError(t, err) assert.NoError(t, err)
err = n.Build(idxNode.Content[0], idx) err = n.Build(idxNode.Content[0], idx)

View File

@@ -4,11 +4,13 @@
package v3 package v3
import ( import (
"crypto/sha256"
"fmt" "fmt"
"github.com/pb33f/libopenapi/datamodel/low" "github.com/pb33f/libopenapi/datamodel/low"
"github.com/pb33f/libopenapi/index" "github.com/pb33f/libopenapi/index"
"github.com/pb33f/libopenapi/utils" "github.com/pb33f/libopenapi/utils"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
"sort"
"strings" "strings"
) )
@@ -122,3 +124,25 @@ func (p *Paths) Build(root *yaml.Node, idx *index.SpecIndex) error {
p.PathItems = pathsMap p.PathItems = pathsMap
return nil return nil
} }
// Hash will return a consistent SHA256 Hash of the PathItem object
func (p *Paths) Hash() [32]byte {
var f []string
l := make([]string, len(p.PathItems))
keys := make(map[string]low.ValueReference[*PathItem])
z := 0
for k := range p.PathItems {
keys[k.Value] = p.PathItems[k]
l[z] = k.Value
z++
}
sort.Strings(l)
for k := range l {
f = append(f, low.GenerateHashString(keys[l[k]].Value))
}
for k := range p.Extensions {
f = append(f, fmt.Sprintf("%s-%x", k.Value,
sha256.Sum256([]byte(fmt.Sprint(p.Extensions[k].Value)))))
}
return sha256.Sum256([]byte(strings.Join(f, "|")))
}

View File

@@ -25,7 +25,7 @@ x-requesto: presto`
idx := index.NewSpecIndex(&idxNode) idx := index.NewSpecIndex(&idxNode)
var n RequestBody var n RequestBody
err := low.BuildModel(&idxNode, &n) err := low.BuildModel(idxNode.Content[0], &n)
assert.NoError(t, err) assert.NoError(t, err)
err = n.Build(idxNode.Content[0], idx) err = n.Build(idxNode.Content[0], idx)
@@ -47,7 +47,7 @@ func TestRequestBody_Fail(t *testing.T) {
idx := index.NewSpecIndex(&idxNode) idx := index.NewSpecIndex(&idxNode)
var n RequestBody var n RequestBody
err := low.BuildModel(&idxNode, &n) err := low.BuildModel(idxNode.Content[0], &n)
assert.NoError(t, err) assert.NoError(t, err)
err = n.Build(idxNode.Content[0], idx) err = n.Build(idxNode.Content[0], idx)

View File

@@ -52,7 +52,7 @@ x-milk: please`
idx := index.NewSpecIndex(&idxNode) idx := index.NewSpecIndex(&idxNode)
var n SecurityScheme var n SecurityScheme
err := low.BuildModel(&idxNode, &n) err := low.BuildModel(idxNode.Content[0], &n)
assert.NoError(t, err) assert.NoError(t, err)
err = n.Build(idxNode.Content[0], idx) err = n.Build(idxNode.Content[0], idx)

View File

@@ -26,7 +26,7 @@ variables:
idx := index.NewSpecIndex(&idxNode) idx := index.NewSpecIndex(&idxNode)
var n Server var n Server
err := low.BuildModel(&idxNode, &n) err := low.BuildModel(idxNode.Content[0], &n)
assert.NoError(t, err) assert.NoError(t, err)
err = n.Build(idxNode.Content[0], idx) err = n.Build(idxNode.Content[0], idx)
@@ -48,7 +48,7 @@ description: high quality software for developers.`
idx := index.NewSpecIndex(&idxNode) idx := index.NewSpecIndex(&idxNode)
var n Server var n Server
err := low.BuildModel(&idxNode, &n) err := low.BuildModel(idxNode.Content[0], &n)
assert.NoError(t, err) assert.NoError(t, err)
err = n.Build(idxNode.Content[0], idx) err = n.Build(idxNode.Content[0], idx)

View File

@@ -137,10 +137,32 @@ func ComparePathItems(l, r any) *PathItemChanges {
return nil return nil
} }
props = append(props, compareOpenAPIPathItem(lPath, rPath, &changes, pc)...) // description
props = append(props, &PropertyCheck{
LeftNode: lPath.Description.ValueNode,
RightNode: rPath.Description.ValueNode,
Label: v3.DescriptionLabel,
Changes: &changes,
Breaking: false,
Original: lPath,
New: lPath,
})
// summary
props = append(props, &PropertyCheck{
LeftNode: lPath.Summary.ValueNode,
RightNode: rPath.Summary.ValueNode,
Label: v3.SummaryLabel,
Changes: &changes,
Breaking: false,
Original: lPath,
New: lPath,
})
compareOpenAPIPathItem(lPath, rPath, &changes, pc)
} }
CheckProperties(props) //CheckProperties(props)
pc.Changes = changes pc.Changes = changes
return pc return pc
} }
@@ -380,31 +402,9 @@ func checkParameters(lParams, rParams []low.ValueReference[low.IsParameter], cha
pc.ParameterChanges = paramChanges pc.ParameterChanges = paramChanges
} }
func compareOpenAPIPathItem(lPath, rPath *v3.PathItem, changes *[]*Change, pc *PathItemChanges) []*PropertyCheck { func compareOpenAPIPathItem(lPath, rPath *v3.PathItem, changes *[]*Change, pc *PathItemChanges) {
var props []*PropertyCheck //var props []*PropertyCheck
// description
props = append(props, &PropertyCheck{
LeftNode: lPath.Description.ValueNode,
RightNode: rPath.Description.ValueNode,
Label: v3.DescriptionLabel,
Changes: changes,
Breaking: false,
Original: lPath,
New: lPath,
})
// summary
props = append(props, &PropertyCheck{
LeftNode: lPath.Summary.ValueNode,
RightNode: rPath.Summary.ValueNode,
Label: v3.SummaryLabel,
Changes: changes,
Breaking: false,
Original: lPath,
New: lPath,
})
totalOps := 0 totalOps := 0
opChan := make(chan opCheck) opChan := make(chan opCheck)
@@ -578,7 +578,6 @@ func compareOpenAPIPathItem(lPath, rPath *v3.PathItem, changes *[]*Change, pc *P
} }
} }
pc.ExtensionChanges = CompareExtensions(lPath.Extensions, rPath.Extensions) pc.ExtensionChanges = CompareExtensions(lPath.Extensions, rPath.Extensions)
return props
} }
func checkOperation(l, r any, done chan opCheck, method string) { func checkOperation(l, r any, done chan opCheck, method string) {