fix: fixed tests after merge

This commit is contained in:
Tristan Cartledge
2023-11-27 17:05:37 +00:00
parent 2de65e4ca0
commit 785824a271
23 changed files with 194 additions and 220 deletions

View File

@@ -6,6 +6,7 @@ package base
import ( import (
low2 "github.com/pb33f/libopenapi/datamodel/high" low2 "github.com/pb33f/libopenapi/datamodel/high"
low "github.com/pb33f/libopenapi/datamodel/low/base" low "github.com/pb33f/libopenapi/datamodel/low/base"
"github.com/pb33f/libopenapi/orderedmap"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
) )
@@ -19,8 +20,8 @@ import (
// //
// v3 - https://spec.openapis.org/oas/v3.1.0#discriminator-object // v3 - https://spec.openapis.org/oas/v3.1.0#discriminator-object
type Discriminator struct { type Discriminator struct {
PropertyName string `json:"propertyName,omitempty" yaml:"propertyName,omitempty"` PropertyName string `json:"propertyName,omitempty" yaml:"propertyName,omitempty"`
Mapping map[string]string `json:"mapping,omitempty" yaml:"mapping,omitempty"` Mapping orderedmap.Map[string, string] `json:"mapping,omitempty" yaml:"mapping,omitempty"`
low *low.Discriminator low *low.Discriminator
} }
@@ -29,9 +30,9 @@ func NewDiscriminator(disc *low.Discriminator) *Discriminator {
d := new(Discriminator) d := new(Discriminator)
d.low = disc d.low = disc
d.PropertyName = disc.PropertyName.Value d.PropertyName = disc.PropertyName.Value
mapping := make(map[string]string) mapping := orderedmap.New[string, string]()
for k, v := range disc.Mapping.Value { for pair := disc.Mapping.Value.First(); pair != nil; pair = pair.Next() {
mapping[k.Value] = v.Value mapping.Set(pair.Key().Value, pair.Value().Value)
} }
d.Mapping = mapping d.Mapping = mapping
return d return d

View File

@@ -5,16 +5,16 @@ package base
import ( import (
"fmt" "fmt"
"strings"
"testing"
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"
"strings"
"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
@@ -31,17 +31,15 @@ mapping:
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.GetOrZero("fogCleaner"))
assert.Equal(t, 3, highDiscriminator.GoLow().FindMappingValue("fogCleaner").ValueNode.Line) assert.Equal(t, 3, highDiscriminator.GoLow().FindMappingValue("fogCleaner").ValueNode.Line)
// render the example as YAML // render the example as YAML
rendered, _ := highDiscriminator.Render() rendered, _ := highDiscriminator.Render()
assert.Equal(t, strings.TrimSpace(string(rendered)), yml) assert.Equal(t, strings.TrimSpace(string(rendered)), yml)
} }
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:
@@ -59,6 +57,6 @@ mapping:
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.GetOrZero("coffee"))
// Output: in the morning // Output: in the morning
} }

View File

@@ -5,13 +5,14 @@ package base
import ( import (
"context" "context"
"strings"
"testing"
"github.com/pb33f/libopenapi/datamodel/low" "github.com/pb33f/libopenapi/datamodel/low"
lowbase "github.com/pb33f/libopenapi/datamodel/low/base" lowbase "github.com/pb33f/libopenapi/datamodel/low/base"
"github.com/pb33f/libopenapi/index" "github.com/pb33f/libopenapi/index"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
"strings"
"testing"
) )
func TestDynamicValue_Render_A(t *testing.T) { func TestDynamicValue_Render_A(t *testing.T) {
@@ -57,7 +58,6 @@ func TestDynamicValue_Render_Float64(t *testing.T) {
} }
func TestDynamicValue_Render_Ptr(t *testing.T) { func TestDynamicValue_Render_Ptr(t *testing.T) {
type cake struct { type cake struct {
Cake string Cake string
} }
@@ -68,7 +68,6 @@ func TestDynamicValue_Render_Ptr(t *testing.T) {
} }
func TestDynamicValue_Render_PtrRenderable(t *testing.T) { func TestDynamicValue_Render_PtrRenderable(t *testing.T) {
tag := &Tag{ tag := &Tag{
Name: "cake", Name: "cake",
} }
@@ -79,7 +78,6 @@ func TestDynamicValue_Render_PtrRenderable(t *testing.T) {
} }
func TestDynamicValue_RenderInline(t *testing.T) { func TestDynamicValue_RenderInline(t *testing.T) {
tag := &Tag{ tag := &Tag{
Name: "cake", Name: "cake",
} }
@@ -90,7 +88,6 @@ func TestDynamicValue_RenderInline(t *testing.T) {
} }
func TestDynamicValue_MarshalYAMLInline(t *testing.T) { func TestDynamicValue_MarshalYAMLInline(t *testing.T) {
const ymlComponents = `components: const ymlComponents = `components:
schemas: schemas:
rice: rice:
@@ -130,11 +127,10 @@ func TestDynamicValue_MarshalYAMLInline(t *testing.T) {
// convert node into yaml // convert node into yaml
bits, _ := yaml.Marshal(rend) bits, _ := yaml.Marshal(rend)
assert.Equal(t, "properties:\n rice:\n type: array\n items:\n type: string", strings.TrimSpace(string(bits))) assert.Equal(t, "properties:\n rice:\n $ref: '#/components/schemas/rice'", strings.TrimSpace(string(bits)))
} }
func TestDynamicValue_MarshalYAMLInline_Error(t *testing.T) { func TestDynamicValue_MarshalYAMLInline_Error(t *testing.T) {
const ymlComponents = `components: const ymlComponents = `components:
schemas: schemas:
rice: rice:

View File

@@ -231,7 +231,7 @@ func TestNewDocument_Components_Schemas(t *testing.T) {
assert.Len(t, d.Schema().Required, 2) assert.Len(t, d.Schema().Required, 2)
assert.True(t, d.Schema().AdditionalProperties.B) assert.True(t, d.Schema().AdditionalProperties.B)
assert.Equal(t, "drinkType", d.Schema().Discriminator.PropertyName) assert.Equal(t, "drinkType", d.Schema().Discriminator.PropertyName)
assert.Equal(t, "some value", d.Schema().Discriminator.Mapping["drink"]) assert.Equal(t, "some value", d.Schema().Discriminator.Mapping.GetOrZero("drink"))
assert.Equal(t, 516, d.Schema().Discriminator.GoLow().PropertyName.ValueNode.Line) assert.Equal(t, 516, d.Schema().Discriminator.GoLow().PropertyName.ValueNode.Line)
assert.Equal(t, 23, d.Schema().Discriminator.GoLow().PropertyName.ValueNode.Column) assert.Equal(t, 23, d.Schema().Discriminator.GoLow().PropertyName.ValueNode.Column)
@@ -300,8 +300,8 @@ func TestNewDocument_Components_SecuritySchemes(t *testing.T) {
assert.Equal(t, "an oAuth security scheme", oAuth.Description) assert.Equal(t, "an oAuth security scheme", oAuth.Description)
assert.Equal(t, 375, oAuth.GoLow().Description.ValueNode.Line) assert.Equal(t, 375, oAuth.GoLow().Description.ValueNode.Line)
assert.Equal(t, 20, oAuth.GoLow().Description.ValueNode.Column) assert.Equal(t, 20, oAuth.GoLow().Description.ValueNode.Column)
assert.Equal(t, 2, len(oAuth.Flows.Implicit.Scopes)) assert.Equal(t, 2, oAuth.Flows.Implicit.Scopes.Len())
assert.Equal(t, "read all burgers", oAuth.Flows.Implicit.Scopes["read:burgers"]) assert.Equal(t, "read all burgers", oAuth.Flows.Implicit.Scopes.GetOrZero("read:burgers"))
assert.Equal(t, "https://pb33f.io/oauth", oAuth.Flows.AuthorizationCode.AuthorizationUrl) assert.Equal(t, "https://pb33f.io/oauth", oAuth.Flows.AuthorizationCode.AuthorizationUrl)
// check the lowness is low. // check the lowness is low.
@@ -553,7 +553,7 @@ func TestCircularReferencesDoc(t *testing.T) {
lDoc, err := lowv3.CreateDocumentFromConfig(info, datamodel.NewDocumentConfiguration()) lDoc, err := lowv3.CreateDocumentFromConfig(info, datamodel.NewDocumentConfiguration())
assert.Len(t, utils.UnwrapErrors(err), 3) assert.Len(t, utils.UnwrapErrors(err), 3)
d := NewDocument(lDoc) d := NewDocument(lDoc)
assert.Len(t, d.Components.Schemas, 9) assert.Equal(t, 9, d.Components.Schemas.Len())
assert.Len(t, d.Index.GetCircularReferences(), 3) assert.Len(t, d.Index.GetCircularReferences(), 3)
} }

View File

@@ -6,6 +6,7 @@ package v3
import ( import (
"github.com/pb33f/libopenapi/datamodel/high" "github.com/pb33f/libopenapi/datamodel/high"
low "github.com/pb33f/libopenapi/datamodel/low/v3" low "github.com/pb33f/libopenapi/datamodel/low/v3"
"github.com/pb33f/libopenapi/orderedmap"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
) )
@@ -15,8 +16,7 @@ type OAuthFlow struct {
AuthorizationUrl string `json:"authorizationUrl,omitempty" yaml:"authorizationUrl,omitempty"` AuthorizationUrl string `json:"authorizationUrl,omitempty" yaml:"authorizationUrl,omitempty"`
TokenUrl string `json:"tokenUrl,omitempty" yaml:"tokenUrl,omitempty"` TokenUrl string `json:"tokenUrl,omitempty" yaml:"tokenUrl,omitempty"`
RefreshUrl string `json:"refreshUrl,omitempty" yaml:"refreshUrl,omitempty"` RefreshUrl string `json:"refreshUrl,omitempty" yaml:"refreshUrl,omitempty"`
// FIXME: Scopes must be converted to orderedmap.Map. Fix unmarshaling issue causing omitted `scopes` stanza on parsing. Scopes orderedmap.Map[string, string] `json:"scopes,omitempty" yaml:"scopes,omitempty"`
Scopes map[string]string `json:"scopes,omitempty" yaml:"scopes,omitempty"`
Extensions map[string]any `json:"-" yaml:"-"` Extensions map[string]any `json:"-" yaml:"-"`
low *low.OAuthFlow low *low.OAuthFlow
} }
@@ -28,9 +28,9 @@ func NewOAuthFlow(flow *low.OAuthFlow) *OAuthFlow {
o.TokenUrl = flow.TokenUrl.Value o.TokenUrl = flow.TokenUrl.Value
o.AuthorizationUrl = flow.AuthorizationUrl.Value o.AuthorizationUrl = flow.AuthorizationUrl.Value
o.RefreshUrl = flow.RefreshUrl.Value o.RefreshUrl = flow.RefreshUrl.Value
scopes := map[string]string{} scopes := orderedmap.New[string, string]()
for k, v := range flow.Scopes.Value { for pair := flow.Scopes.Value.First(); pair != nil; pair = pair.Next() {
scopes[k.Value] = v.Value scopes.Set(pair.Key().Value, pair.Value().Value)
} }
o.Scopes = scopes o.Scopes = scopes
o.Extensions = high.ExtractExtensions(flow.Extensions) o.Extensions = high.ExtractExtensions(flow.Extensions)

View File

@@ -7,19 +7,20 @@ import (
"strings" "strings"
"testing" "testing"
"github.com/pb33f/libopenapi/orderedmap"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func TestOAuthFlow_MarshalYAML(t *testing.T) { func TestOAuthFlow_MarshalYAML(t *testing.T) {
scopes := orderedmap.New[string, string]()
scopes.Set("chicken", "nuggets")
scopes.Set("beefy", "soup")
oflow := &OAuthFlow{ oflow := &OAuthFlow{
AuthorizationUrl: "https://pb33f.io", AuthorizationUrl: "https://pb33f.io",
TokenUrl: "https://pb33f.io/token", TokenUrl: "https://pb33f.io/token",
RefreshUrl: "https://pb33f.io/refresh", RefreshUrl: "https://pb33f.io/refresh",
Scopes: map[string]string{ Scopes: scopes,
"chicken": "nuggets",
"beefy": "soup",
},
} }
rend, _ := oflow.Render() rend, _ := oflow.Render()
@@ -45,5 +46,4 @@ x-burgers: why not?`
rend, _ = oflow.Render() rend, _ = oflow.Render()
assert.Equal(t, desired, strings.TrimSpace(string(rend))) assert.Equal(t, desired, strings.TrimSpace(string(rend)))
} }

View File

@@ -16,7 +16,6 @@ import (
) )
func TestNewOAuthFlows(t *testing.T) { func TestNewOAuthFlows(t *testing.T) {
yml := `implicit: yml := `implicit:
authorizationUrl: https://pb33f.io/oauth/implicit authorizationUrl: https://pb33f.io/oauth/implicit
scopes: scopes:
@@ -49,10 +48,10 @@ clientCredentials:
r := NewOAuthFlows(&n) r := NewOAuthFlows(&n)
assert.Len(t, r.Implicit.Scopes, 2) assert.Equal(t, 2, r.Implicit.Scopes.Len())
assert.Len(t, r.AuthorizationCode.Scopes, 2) assert.Equal(t, 2, r.AuthorizationCode.Scopes.Len())
assert.Len(t, r.Password.Scopes, 2) assert.Equal(t, 2, r.Password.Scopes.Len())
assert.Len(t, r.ClientCredentials.Scopes, 2) assert.Equal(t, 2, r.ClientCredentials.Scopes.Len())
assert.Equal(t, 2, r.GoLow().Implicit.Value.AuthorizationUrl.KeyNode.Line) assert.Equal(t, 2, r.GoLow().Implicit.Value.AuthorizationUrl.KeyNode.Line)
// now render it back out, and it should be identical! // now render it back out, and it should be identical!
@@ -83,8 +82,7 @@ clientCredentials:
CHIP:CHOP: microwave a sock` CHIP:CHOP: microwave a sock`
// now modify it and render it back out, and it should be identical! // now modify it and render it back out, and it should be identical!
r.ClientCredentials.Scopes["CHIP:CHOP"] = "microwave a sock" r.ClientCredentials.Scopes.Set("CHIP:CHOP", "microwave a sock")
rBytes, _ = r.Render() rBytes, _ = r.Render()
assert.Equal(t, modified, strings.TrimSpace(string(rBytes))) assert.Equal(t, modified, strings.TrimSpace(string(rBytes)))
} }

View File

@@ -5,9 +5,10 @@ package base
import ( import (
"crypto/sha256" "crypto/sha256"
"github.com/pb33f/libopenapi/datamodel/low"
"sort"
"strings" "strings"
"github.com/pb33f/libopenapi/datamodel/low"
"github.com/pb33f/libopenapi/orderedmap"
) )
// Discriminator is only used by OpenAPI 3+ documents, it represents a polymorphic discriminator used for schemas // Discriminator is only used by OpenAPI 3+ documents, it represents a polymorphic discriminator used for schemas
@@ -21,14 +22,15 @@ import (
// v3 - https://spec.openapis.org/oas/v3.1.0#discriminator-object // v3 - https://spec.openapis.org/oas/v3.1.0#discriminator-object
type Discriminator struct { type Discriminator struct {
PropertyName low.NodeReference[string] PropertyName low.NodeReference[string]
Mapping low.NodeReference[map[low.KeyReference[string]]low.ValueReference[string]] Mapping low.NodeReference[orderedmap.Map[low.KeyReference[string], low.ValueReference[string]]]
low.Reference low.Reference
} }
// FindMappingValue will return a ValueReference containing the string mapping value // FindMappingValue will return a ValueReference containing the string mapping value
func (d *Discriminator) FindMappingValue(key string) *low.ValueReference[string] { func (d *Discriminator) FindMappingValue(key string) *low.ValueReference[string] {
for k, v := range d.Mapping.Value { for pair := d.Mapping.Value.First(); pair != nil; pair = pair.Next() {
if k.Value == key { if pair.Key().Value == key {
v := pair.Value()
return &v return &v
} }
} }
@@ -37,20 +39,15 @@ func (d *Discriminator) FindMappingValue(key string) *low.ValueReference[string]
// Hash will return a consistent SHA256 Hash of the Discriminator object // Hash will return a consistent SHA256 Hash of the Discriminator object
func (d *Discriminator) Hash() [32]byte { func (d *Discriminator) Hash() [32]byte {
// calculate a hash from every property. // calculate a hash from every property.
var f []string var f []string
if d.PropertyName.Value != "" { if d.PropertyName.Value != "" {
f = append(f, d.PropertyName.Value) f = append(f, d.PropertyName.Value)
} }
propertyKeys := make([]string, 0, len(d.Mapping.Value))
for i := range d.Mapping.Value { for pair := orderedmap.First(d.Mapping.Value); pair != nil; pair = pair.Next() {
propertyKeys = append(propertyKeys, i.Value) f = append(f, pair.Value().Value)
}
sort.Strings(propertyKeys)
for k := range propertyKeys {
prop := d.FindMappingValue(propertyKeys[k])
f = append(f, prop.Value)
} }
return sha256.Sum256([]byte(strings.Join(f, "|"))) return sha256.Sum256([]byte(strings.Join(f, "|")))
} }

View File

@@ -549,7 +549,6 @@ func (s *Schema) Build(ctx context.Context, root *yaml.Node, idx *index.SpecInde
// determine exclusive minimum type, bool (3.0) or int (3.1) // determine exclusive minimum type, bool (3.0) or int (3.1)
_, exMinLabel, exMinValue := utils.FindKeyNodeFullTop(ExclusiveMinimumLabel, root.Content) _, exMinLabel, exMinValue := utils.FindKeyNodeFullTop(ExclusiveMinimumLabel, root.Content)
if exMinValue != nil { if exMinValue != nil {
// if there is an index, determine if this a 3.0 or 3.1 schema // if there is an index, determine if this a 3.0 or 3.1 schema
if idx != nil { if idx != nil {
if idx.GetConfig().SpecInfo.VersionNumeric == 3.1 { if idx.GetConfig().SpecInfo.VersionNumeric == 3.1 {
@@ -593,7 +592,6 @@ func (s *Schema) Build(ctx context.Context, root *yaml.Node, idx *index.SpecInde
// determine exclusive maximum type, bool (3.0) or int (3.1) // determine exclusive maximum type, bool (3.0) or int (3.1)
_, exMaxLabel, exMaxValue := utils.FindKeyNodeFullTop(ExclusiveMaximumLabel, root.Content) _, exMaxLabel, exMaxValue := utils.FindKeyNodeFullTop(ExclusiveMaximumLabel, root.Content)
if exMaxValue != nil { if exMaxValue != nil {
// if there is an index, determine if this a 3.0 or 3.1 schema // if there is an index, determine if this a 3.0 or 3.1 schema
if idx != nil { if idx != nil {
if idx.GetConfig().SpecInfo.VersionNumeric == 3.1 { if idx.GetConfig().SpecInfo.VersionNumeric == 3.1 {
@@ -1038,62 +1036,40 @@ func (s *Schema) Build(ctx context.Context, root *yaml.Node, idx *index.SpecInde
} }
func buildPropertyMap(ctx context.Context, root *yaml.Node, idx *index.SpecIndex, label string) (*low.NodeReference[orderedmap.Map[low.KeyReference[string], low.ValueReference[*SchemaProxy]]], error) { func buildPropertyMap(ctx context.Context, root *yaml.Node, idx *index.SpecIndex, label string) (*low.NodeReference[orderedmap.Map[low.KeyReference[string], low.ValueReference[*SchemaProxy]]], error) {
// for property, build in a new thread!
bChan := make(chan schemaProxyBuildResult)
buildProperty := func(ctx context.Context, label *yaml.Node, value *yaml.Node, c chan schemaProxyBuildResult, isRef bool,
refString string,
) {
c <- schemaProxyBuildResult{
k: low.KeyReference[string]{
KeyNode: label,
Value: label.Value,
},
v: low.ValueReference[*SchemaProxy]{
Value: &SchemaProxy{ctx: ctx, kn: label, vn: value, idx: idx, isReference: isRef, referenceLookup: refString},
ValueNode: value,
},
}
}
_, propLabel, propsNode := utils.FindKeyNodeFullTop(label, root.Content) _, propLabel, propsNode := utils.FindKeyNodeFullTop(label, root.Content)
if propsNode != nil { if propsNode != nil {
propertyMap := orderedmap.New[low.KeyReference[string], low.ValueReference[*SchemaProxy]]() propertyMap := orderedmap.New[low.KeyReference[string], low.ValueReference[*SchemaProxy]]()
var currentProp *yaml.Node var currentProp *yaml.Node
totalProps := 0
for i, prop := range propsNode.Content { for i, prop := range propsNode.Content {
if i%2 == 0 { if i%2 == 0 {
currentProp = prop currentProp = prop
continue continue
} }
foundCtx := ctx
// check our prop isn't reference // check our prop isn't reference
isRef := false isRef := false
refString := "" refString := ""
if h, _, l := utils.IsNodeRefValue(prop); h { if h, _, l := utils.IsNodeRefValue(prop); h {
ref, _, _, fctx := low.LocateRefNodeWithContext(ctx, prop, idx) ref, _, _, _ := low.LocateRefNodeWithContext(ctx, prop, idx)
if ref != nil { if ref != nil {
isRef = true isRef = true
prop = ref prop = ref
refString = l refString = l
foundCtx = fctx
} else { } else {
return nil, fmt.Errorf("schema properties build failed: cannot find reference %s, line %d, col %d", return nil, fmt.Errorf("schema properties build failed: cannot find reference %s, line %d, col %d",
prop.Content[1].Value, prop.Content[1].Line, prop.Content[1].Column) prop.Content[1].Value, prop.Content[1].Line, prop.Content[1].Column)
} }
} }
totalProps++
go buildProperty(foundCtx, currentProp, prop, bChan, isRef, refString) propertyMap.Set(low.KeyReference[string]{
} KeyNode: currentProp,
completedProps := 0 Value: currentProp.Value,
for completedProps < totalProps { }, low.ValueReference[*SchemaProxy]{
select { Value: &SchemaProxy{ctx: ctx, kn: currentProp, vn: prop, idx: idx, isReference: isRef, referenceLookup: refString},
case res := <-bChan: ValueNode: prop,
completedProps++ })
propertyMap.Set(res.k, res.v)
}
} }
return &low.NodeReference[orderedmap.Map[low.KeyReference[string], low.ValueReference[*SchemaProxy]]]{ return &low.NodeReference[orderedmap.Map[low.KeyReference[string], low.ValueReference[*SchemaProxy]]]{
Value: propertyMap, Value: propertyMap,
KeyNode: propLabel, KeyNode: propLabel,
@@ -1280,7 +1256,7 @@ func ExtractSchema(ctx context.Context, root *yaml.Node, idx *index.SpecIndex) (
schNode = ref schNode = ref
if foundIdx != nil { if foundIdx != nil {
// TODO: check on this // TODO: check on this
//idx = foundIdx // idx = foundIdx
} }
ctx = nCtx ctx = nCtx
} else { } else {

View File

@@ -10,6 +10,7 @@ import (
"strings" "strings"
"sync" "sync"
"github.com/pb33f/libopenapi/orderedmap"
"github.com/pb33f/libopenapi/utils" "github.com/pb33f/libopenapi/utils"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
) )
@@ -389,25 +390,25 @@ func SetField(field *reflect.Value, valueNode *yaml.Node, keyNode *yaml.Node) er
field.Set(reflect.ValueOf(ref)) field.Set(reflect.ValueOf(ref))
} }
} }
case reflect.TypeOf(NodeReference[map[KeyReference[string]]ValueReference[string]]{}): case reflect.TypeOf(NodeReference[orderedmap.Map[KeyReference[string], ValueReference[string]]]{}):
if utils.IsNodeMap(valueNode) { if utils.IsNodeMap(valueNode) {
if field.CanSet() { if field.CanSet() {
items := make(map[KeyReference[string]]ValueReference[string]) items := orderedmap.New[KeyReference[string], ValueReference[string]]()
var cf *yaml.Node var cf *yaml.Node
for i, sliceItem := range valueNode.Content { for i, sliceItem := range valueNode.Content {
if i%2 == 0 { if i%2 == 0 {
cf = sliceItem cf = sliceItem
continue continue
} }
items[KeyReference[string]{ items.Set(KeyReference[string]{
Value: cf.Value, Value: cf.Value,
KeyNode: cf, KeyNode: cf,
}] = ValueReference[string]{ }, ValueReference[string]{
Value: sliceItem.Value, Value: sliceItem.Value,
ValueNode: sliceItem, ValueNode: sliceItem,
} })
} }
ref := NodeReference[map[KeyReference[string]]ValueReference[string]]{ ref := NodeReference[orderedmap.Map[KeyReference[string], ValueReference[string]]]{
Value: items, Value: items,
KeyNode: keyNode, KeyNode: keyNode,
ValueNode: valueNode, ValueNode: valueNode,

View File

@@ -1,10 +1,12 @@
package low package low
import ( import (
"github.com/stretchr/testify/assert"
"gopkg.in/yaml.v3"
"sync" "sync"
"testing" "testing"
"github.com/pb33f/libopenapi/orderedmap"
"github.com/stretchr/testify/assert"
"gopkg.in/yaml.v3"
) )
type hotdog struct { type hotdog struct {
@@ -27,11 +29,10 @@ type hotdog struct {
LotsOfUnknowns []NodeReference[any] LotsOfUnknowns []NodeReference[any]
Where map[string]NodeReference[any] Where map[string]NodeReference[any]
There map[string]NodeReference[string] There map[string]NodeReference[string]
AllTheThings NodeReference[map[KeyReference[string]]ValueReference[string]] AllTheThings NodeReference[orderedmap.Map[KeyReference[string], ValueReference[string]]]
} }
func TestBuildModel_Mismatch(t *testing.T) { func TestBuildModel_Mismatch(t *testing.T) {
yml := `crisps: are tasty` yml := `crisps: are tasty`
var rootNode yaml.Node var rootNode yaml.Node
@@ -42,11 +43,9 @@ func TestBuildModel_Mismatch(t *testing.T) {
cErr := BuildModel(&rootNode, &hd) cErr := BuildModel(&rootNode, &hd)
assert.NoError(t, cErr) assert.NoError(t, cErr)
assert.Empty(t, hd.Name) assert.Empty(t, hd.Name)
} }
func TestBuildModel(t *testing.T) { func TestBuildModel(t *testing.T) {
yml := `name: yummy yml := `name: yummy
valueName: yammy valueName: yammy
beef: true beef: true
@@ -135,19 +134,18 @@ allTheThings:
assert.Equal(t, 324938249028.98234892374892374923874823974, hd.Mustard.Value) assert.Equal(t, 324938249028.98234892374892374923874823974, hd.Mustard.Value)
allTheThings := hd.AllTheThings.Value allTheThings := hd.AllTheThings.Value
for i := range allTheThings { for pair := allTheThings.First(); pair != nil; pair = pair.Next() {
if i.Value == "beer" { if pair.Key().Value == "beer" {
assert.Equal(t, "isGood", allTheThings[i].Value) assert.Equal(t, "isGood", pair.Value().Value)
} }
if i.Value == "cake" { if pair.Key().Value == "cake" {
assert.Equal(t, "isNice", allTheThings[i].Value) assert.Equal(t, "isNice", pair.Value().Value)
} }
} }
assert.NoError(t, cErr) assert.NoError(t, cErr)
} }
func TestBuildModel_UseCopyNotRef(t *testing.T) { func TestBuildModel_UseCopyNotRef(t *testing.T) {
yml := `cake: -99999` yml := `cake: -99999`
var rootNode yaml.Node var rootNode yaml.Node
@@ -158,11 +156,9 @@ func TestBuildModel_UseCopyNotRef(t *testing.T) {
cErr := BuildModel(&rootNode, hd) cErr := BuildModel(&rootNode, hd)
assert.Error(t, cErr) assert.Error(t, cErr)
assert.Empty(t, hd.Name) assert.Empty(t, hd.Name)
} }
func TestBuildModel_UseUnsupportedPrimitive(t *testing.T) { func TestBuildModel_UseUnsupportedPrimitive(t *testing.T) {
type notSupported struct { type notSupported struct {
cake string cake string
} }
@@ -176,11 +172,9 @@ func TestBuildModel_UseUnsupportedPrimitive(t *testing.T) {
cErr := BuildModel(rootNode.Content[0], &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)
} }
func TestBuildModel_UsingInternalConstructs(t *testing.T) { func TestBuildModel_UsingInternalConstructs(t *testing.T) {
type internal struct { type internal struct {
Extensions NodeReference[string] Extensions NodeReference[string]
PathItems NodeReference[string] PathItems NodeReference[string]
@@ -208,7 +202,6 @@ thing: yeah`
} }
func TestSetField_NodeRefAny_Error(t *testing.T) { func TestSetField_NodeRefAny_Error(t *testing.T) {
type internal struct { type internal struct {
Thing []NodeReference[any] Thing []NodeReference[any]
} }
@@ -224,11 +217,9 @@ func TestSetField_NodeRefAny_Error(t *testing.T) {
try := BuildModel(rootNode.Content[0], ins) try := BuildModel(rootNode.Content[0], ins)
assert.Error(t, try) assert.Error(t, try)
} }
func TestSetField_MapHelperWrapped(t *testing.T) { func TestSetField_MapHelperWrapped(t *testing.T) {
type internal struct { type internal struct {
Thing KeyReference[map[KeyReference[string]]ValueReference[string]] Thing KeyReference[map[KeyReference[string]]ValueReference[string]]
} }
@@ -249,7 +240,6 @@ func TestSetField_MapHelperWrapped(t *testing.T) {
} }
func TestSetField_MapHelper(t *testing.T) { func TestSetField_MapHelper(t *testing.T) {
type internal struct { type internal struct {
Thing map[KeyReference[string]]ValueReference[string] Thing map[KeyReference[string]]ValueReference[string]
} }
@@ -270,7 +260,6 @@ func TestSetField_MapHelper(t *testing.T) {
} }
func TestSetField_ArrayHelper(t *testing.T) { func TestSetField_ArrayHelper(t *testing.T) {
type internal struct { type internal struct {
Thing NodeReference[[]ValueReference[string]] Thing NodeReference[[]ValueReference[string]]
} }
@@ -291,7 +280,6 @@ func TestSetField_ArrayHelper(t *testing.T) {
} }
func TestSetField_Enum_Helper(t *testing.T) { func TestSetField_Enum_Helper(t *testing.T) {
type internal struct { type internal struct {
Thing NodeReference[[]ValueReference[any]] Thing NodeReference[[]ValueReference[any]]
} }
@@ -312,7 +300,6 @@ func TestSetField_Enum_Helper(t *testing.T) {
} }
func TestSetField_Default_Helper(t *testing.T) { func TestSetField_Default_Helper(t *testing.T) {
type cake struct { type cake struct {
thing int thing int
} }
@@ -336,7 +323,6 @@ func TestSetField_Default_Helper(t *testing.T) {
} }
func TestHandleSlicesOfInts(t *testing.T) { func TestHandleSlicesOfInts(t *testing.T) {
type internal struct { type internal struct {
Thing NodeReference[[]ValueReference[any]] Thing NodeReference[[]ValueReference[any]]
} }
@@ -377,7 +363,6 @@ func TestHandleSlicesOfBools(t *testing.T) {
} }
func TestSetField_Ignore(t *testing.T) { func TestSetField_Ignore(t *testing.T) {
type Complex struct { type Complex struct {
name string name string
} }
@@ -401,7 +386,6 @@ func TestSetField_Ignore(t *testing.T) {
} }
func TestBuildModelAsync(t *testing.T) { func TestBuildModelAsync(t *testing.T) {
type internal struct { type internal struct {
Thing KeyReference[map[KeyReference[string]]ValueReference[string]] Thing KeyReference[map[KeyReference[string]]ValueReference[string]]
} }
@@ -422,11 +406,9 @@ func TestBuildModelAsync(t *testing.T) {
BuildModelAsync(rootNode.Content[0], 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)
} }
func TestBuildModelAsync_Error(t *testing.T) { func TestBuildModelAsync_Error(t *testing.T) {
type internal struct { type internal struct {
Thing []NodeReference[any] Thing []NodeReference[any]
} }
@@ -447,5 +429,4 @@ func TestBuildModelAsync_Error(t *testing.T) {
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

@@ -2,14 +2,15 @@ package v3
import ( import (
"fmt" "fmt"
"github.com/pb33f/libopenapi/index"
"github.com/pb33f/libopenapi/utils"
"log/slog" "log/slog"
"net/http" "net/http"
"net/url" "net/url"
"os" "os"
"testing" "testing"
"github.com/pb33f/libopenapi/index"
"github.com/pb33f/libopenapi/utils"
"github.com/pb33f/libopenapi/datamodel" "github.com/pb33f/libopenapi/datamodel"
"github.com/pb33f/libopenapi/orderedmap" "github.com/pb33f/libopenapi/orderedmap"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@@ -525,7 +526,7 @@ func TestCreateDocument_Components_Schemas(t *testing.T) {
components := doc.Components.Value components := doc.Components.Value
assert.NotNil(t, components) assert.NotNil(t, components)
assert.Len(t, components.Schemas.Value, 6) assert.Equal(t, 6, components.Schemas.Value.Len())
burger := components.FindSchema("Burger").Value burger := components.FindSchema("Burger").Value
assert.NotNil(t, burger) assert.NotNil(t, burger)
@@ -539,7 +540,7 @@ func TestCreateDocument_Components_Schemas(t *testing.T) {
fries := components.FindSchema("Fries") fries := components.FindSchema("Fries")
assert.NotNil(t, fries.Value) assert.NotNil(t, fries.Value)
assert.Len(t, fries.Value.Schema().Properties.Value, 3) assert.Equal(t, 3, fries.Value.Schema().Properties.Value.Len())
p := fries.Value.Schema().FindProperty("favoriteDrink") p := fries.Value.Schema().FindProperty("favoriteDrink")
assert.Equal(t, "a frosty cold beverage can be coke or sprite", assert.Equal(t, "a frosty cold beverage can be coke or sprite",
p.Value.Schema().Description.Value) p.Value.Schema().Description.Value)
@@ -549,7 +550,7 @@ func TestCreateDocument_Components_SecuritySchemes(t *testing.T) {
initTest() initTest()
components := doc.Components.Value components := doc.Components.Value
securitySchemes := components.SecuritySchemes.Value securitySchemes := components.SecuritySchemes.Value
assert.Len(t, securitySchemes, 3) assert.Equal(t, 3, securitySchemes.Len())
apiKey := components.FindSecurityScheme("APIKeyScheme").Value apiKey := components.FindSecurityScheme("APIKeyScheme").Value
assert.NotNil(t, apiKey) assert.NotNil(t, apiKey)
@@ -577,19 +578,19 @@ func TestCreateDocument_Components_Responses(t *testing.T) {
initTest() initTest()
components := doc.Components.Value components := doc.Components.Value
responses := components.Responses.Value responses := components.Responses.Value
assert.Len(t, responses, 1) assert.Equal(t, 1, responses.Len())
dressingResponse := components.FindResponse("DressingResponse") dressingResponse := components.FindResponse("DressingResponse")
assert.NotNil(t, dressingResponse.Value) assert.NotNil(t, dressingResponse.Value)
assert.Equal(t, "all the dressings for a burger.", dressingResponse.Value.Description.Value) assert.Equal(t, "all the dressings for a burger.", dressingResponse.Value.Description.Value)
assert.Len(t, dressingResponse.Value.Content.Value, 1) assert.Equal(t, 1, dressingResponse.Value.Content.Value.Len())
} }
func TestCreateDocument_Components_Examples(t *testing.T) { func TestCreateDocument_Components_Examples(t *testing.T) {
initTest() initTest()
components := doc.Components.Value components := doc.Components.Value
examples := components.Examples.Value examples := components.Examples.Value
assert.Len(t, examples, 1) assert.Equal(t, 1, examples.Len())
quarterPounder := components.FindExample("QuarterPounder") quarterPounder := components.FindExample("QuarterPounder")
assert.NotNil(t, quarterPounder.Value) assert.NotNil(t, quarterPounder.Value)
@@ -601,19 +602,19 @@ func TestCreateDocument_Components_RequestBodies(t *testing.T) {
initTest() initTest()
components := doc.Components.Value components := doc.Components.Value
requestBodies := components.RequestBodies.Value requestBodies := components.RequestBodies.Value
assert.Len(t, requestBodies, 1) assert.Equal(t, 1, requestBodies.Len())
burgerRequest := components.FindRequestBody("BurgerRequest") burgerRequest := components.FindRequestBody("BurgerRequest")
assert.NotNil(t, burgerRequest.Value) assert.NotNil(t, burgerRequest.Value)
assert.Equal(t, "Give us the new burger!", burgerRequest.Value.Description.Value) assert.Equal(t, "Give us the new burger!", burgerRequest.Value.Description.Value)
assert.Len(t, burgerRequest.Value.Content.Value, 1) assert.Equal(t, 1, burgerRequest.Value.Content.Value.Len())
} }
func TestCreateDocument_Components_Headers(t *testing.T) { func TestCreateDocument_Components_Headers(t *testing.T) {
initTest() initTest()
components := doc.Components.Value components := doc.Components.Value
headers := components.Headers.Value headers := components.Headers.Value
assert.Len(t, headers, 1) assert.Equal(t, 1, headers.Len())
useOil := components.FindHeader("UseOil") useOil := components.FindHeader("UseOil")
assert.NotNil(t, useOil.Value) assert.NotNil(t, useOil.Value)
@@ -625,7 +626,7 @@ func TestCreateDocument_Components_Links(t *testing.T) {
initTest() initTest()
components := doc.Components.Value components := doc.Components.Value
links := components.Links.Value links := components.Links.Value
assert.Len(t, links, 2) assert.Equal(t, 2, links.Len())
locateBurger := components.FindLink("LocateBurger") locateBurger := components.FindLink("LocateBurger")
assert.NotNil(t, locateBurger.Value) assert.NotNil(t, locateBurger.Value)
@@ -646,11 +647,11 @@ func TestCreateDocument_Doc_Security(t *testing.T) {
func TestCreateDocument_Callbacks(t *testing.T) { func TestCreateDocument_Callbacks(t *testing.T) {
initTest() initTest()
callbacks := doc.Components.Value.Callbacks.Value callbacks := doc.Components.Value.Callbacks.Value
assert.Len(t, callbacks, 1) assert.Equal(t, 1, callbacks.Len())
bCallback := doc.Components.Value.FindCallback("BurgerCallback") bCallback := doc.Components.Value.FindCallback("BurgerCallback")
assert.NotNil(t, bCallback.Value) assert.NotNil(t, bCallback.Value)
assert.Len(t, callbacks, 1) assert.Equal(t, 1, callbacks.Len())
exp := bCallback.Value.FindExpression("{$request.query.queryUrl}") exp := bCallback.Value.FindExpression("{$request.query.queryUrl}")
assert.NotNil(t, exp.Value) assert.NotNil(t, exp.Value)
@@ -791,7 +792,6 @@ func TestCreateDocument_YamlAnchor(t *testing.T) {
// build low-level document model // build low-level document model
document, err := CreateDocumentFromConfig(info, &datamodel.DocumentConfiguration{}) document, err := CreateDocumentFromConfig(info, &datamodel.DocumentConfiguration{})
if err != nil { if err != nil {
fmt.Printf("error: %s\n", err.Error()) fmt.Printf("error: %s\n", err.Error())
panic("cannot build document") panic("cannot build document")
@@ -851,7 +851,6 @@ func ExampleCreateDocument() {
// build low-level document model // build low-level document model
document, err := CreateDocumentFromConfig(info, &datamodel.DocumentConfiguration{}) document, err := CreateDocumentFromConfig(info, &datamodel.DocumentConfiguration{})
if err != nil { if err != nil {
fmt.Printf("error: %s\n", err.Error()) fmt.Printf("error: %s\n", err.Error())
panic("cannot build document") panic("cannot build document")

View File

@@ -5,12 +5,14 @@ package v3
import ( import (
"context" "context"
"testing"
"github.com/pb33f/libopenapi/datamodel/low" "github.com/pb33f/libopenapi/datamodel/low"
"github.com/pb33f/libopenapi/datamodel/low/base" "github.com/pb33f/libopenapi/datamodel/low/base"
"github.com/pb33f/libopenapi/index" "github.com/pb33f/libopenapi/index"
"github.com/pb33f/libopenapi/orderedmap"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
"testing"
) )
func TestHeader_Build(t *testing.T) { func TestHeader_Build(t *testing.T) {
@@ -168,7 +170,6 @@ func TestHeader_Build_Fail_Content(t *testing.T) {
} }
func TestEncoding_Hash_n_Grab(t *testing.T) { func TestEncoding_Hash_n_Grab(t *testing.T) {
yml := `description: heady yml := `description: heady
required: true required: true
deprecated: true deprecated: true
@@ -241,7 +242,6 @@ schema:
sch := n.GetSchema().Value.(*base.SchemaProxy).Schema() sch := n.GetSchema().Value.(*base.SchemaProxy).Schema()
assert.Len(t, sch.Type.Value.B, 2) // using multiple types for 3.1 testing. assert.Len(t, sch.Type.Value.B, 2) // using multiple types for 3.1 testing.
assert.Equal(t, "what a good puppy", n.GetExample().Value) assert.Equal(t, "what a good puppy", n.GetExample().Value)
assert.Len(t, n.GetExamples().Value, 1) assert.Equal(t, 1, orderedmap.Cast[low.KeyReference[string], low.ValueReference[*base.Example]](n.GetExamples().Value).Len())
assert.Len(t, n.GetContent().Value.(map[low.KeyReference[string]]low.ValueReference[*MediaType]), 1) assert.Equal(t, 1, orderedmap.Cast[low.KeyReference[string], low.ValueReference[*MediaType]](n.GetContent().Value).Len())
} }

View File

@@ -5,11 +5,12 @@ package v3
import ( import (
"context" "context"
"testing"
"github.com/pb33f/libopenapi/datamodel/low" "github.com/pb33f/libopenapi/datamodel/low"
"github.com/pb33f/libopenapi/index" "github.com/pb33f/libopenapi/index"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
"testing"
) )
func TestMediaType_Build(t *testing.T) { func TestMediaType_Build(t *testing.T) {
@@ -42,7 +43,7 @@ x-rock: and roll`
assert.Equal(t, "why?", n.FindExample("what").Value.Value.Value) assert.Equal(t, "why?", n.FindExample("what").Value.Value.Value)
assert.Equal(t, "there?", n.FindExample("where").Value.Value.Value) assert.Equal(t, "there?", n.FindExample("where").Value.Value.Value)
assert.True(t, n.FindPropertyEncoding("chicken").Value.Explode.Value) assert.True(t, n.FindPropertyEncoding("chicken").Value.Explode.Value)
assert.Len(t, n.GetAllExamples(), 2) assert.Equal(t, n.GetAllExamples().Len(), 2)
} }
func TestMediaType_Build_Fail_Schema(t *testing.T) { func TestMediaType_Build_Fail_Schema(t *testing.T) {
@@ -76,7 +77,6 @@ func TestMediaType_Build_Fail_Examples(t *testing.T) {
err = n.Build(context.Background(), nil, idxNode.Content[0], idx) err = n.Build(context.Background(), nil, idxNode.Content[0], idx)
assert.Error(t, err) assert.Error(t, err)
} }
func TestMediaType_Build_Fail_Encoding(t *testing.T) { func TestMediaType_Build_Fail_Encoding(t *testing.T) {
@@ -97,7 +97,6 @@ func TestMediaType_Build_Fail_Encoding(t *testing.T) {
} }
func TestMediaType_Hash(t *testing.T) { func TestMediaType_Hash(t *testing.T) {
yml := `schema: yml := `schema:
type: string type: string
example: a thing example: a thing

View File

@@ -12,6 +12,7 @@ import (
"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/orderedmap"
"github.com/pb33f/libopenapi/utils" "github.com/pb33f/libopenapi/utils"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
) )
@@ -97,7 +98,7 @@ type OAuthFlow struct {
AuthorizationUrl low.NodeReference[string] AuthorizationUrl low.NodeReference[string]
TokenUrl low.NodeReference[string] TokenUrl low.NodeReference[string]
RefreshUrl low.NodeReference[string] RefreshUrl low.NodeReference[string]
Scopes low.NodeReference[map[low.KeyReference[string]]low.ValueReference[string]] Scopes low.NodeReference[orderedmap.Map[low.KeyReference[string], low.ValueReference[string]]]
Extensions map[low.KeyReference[string]]low.ValueReference[any] Extensions map[low.KeyReference[string]]low.ValueReference[any]
*low.Reference *low.Reference
} }
@@ -109,7 +110,7 @@ func (o *OAuthFlow) GetExtensions() map[low.KeyReference[string]]low.ValueRefere
// FindScope attempts to locate a scope using a specified name. // FindScope attempts to locate a scope using a specified name.
func (o *OAuthFlow) FindScope(scope string) *low.ValueReference[string] { func (o *OAuthFlow) FindScope(scope string) *low.ValueReference[string] {
return low.FindItemInMap[string](scope, o.Scopes.Value) return low.FindItemInOrderedMap[string](scope, o.Scopes.Value)
} }
// FindExtension attempts to locate an extension with a specified key // FindExtension attempts to locate an extension with a specified key
@@ -136,10 +137,10 @@ func (o *OAuthFlow) Hash() [32]byte {
if !o.RefreshUrl.IsEmpty() { if !o.RefreshUrl.IsEmpty() {
f = append(f, o.RefreshUrl.Value) f = append(f, o.RefreshUrl.Value)
} }
keys := make([]string, len(o.Scopes.Value)) keys := make([]string, orderedmap.Len(o.Scopes.Value))
z := 0 z := 0
for k, v := range o.Scopes.Value { for pair := orderedmap.First(o.Scopes.Value); pair != nil; pair = pair.Next() {
keys[z] = fmt.Sprintf("%s-%s", k.Value, sha256.Sum256([]byte(fmt.Sprint(v.Value)))) keys[z] = fmt.Sprintf("%s-%s", pair.Key().Value, sha256.Sum256([]byte(fmt.Sprint(pair.Value().Value))))
z++ z++
} }
sort.Strings(keys) sort.Strings(keys)

View File

@@ -5,16 +5,16 @@ package v3
import ( import (
"context" "context"
"testing"
"github.com/pb33f/libopenapi/datamodel/low" "github.com/pb33f/libopenapi/datamodel/low"
"github.com/pb33f/libopenapi/datamodel/low/base" "github.com/pb33f/libopenapi/datamodel/low/base"
"github.com/pb33f/libopenapi/index" "github.com/pb33f/libopenapi/index"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
"testing"
) )
func TestOperation_Build(t *testing.T) { func TestOperation_Build(t *testing.T) {
yml := `tags: yml := `tags:
- meddy - meddy
- maddy - maddy
@@ -61,9 +61,9 @@ servers:
assert.Equal(t, "beefyBeef", n.OperationId.Value) assert.Equal(t, "beefyBeef", n.OperationId.Value)
assert.Len(t, n.Parameters.Value, 2) assert.Len(t, n.Parameters.Value, 2)
assert.Equal(t, "a requestBody", n.RequestBody.Value.Description.Value) assert.Equal(t, "a requestBody", n.RequestBody.Value.Description.Value)
assert.Len(t, n.Responses.Value.Codes, 1) assert.Equal(t, 1, n.Responses.Value.Codes.Len())
assert.Equal(t, "an OK response", n.Responses.Value.FindResponseByCode("200").Value.Description.Value) assert.Equal(t, "an OK response", n.Responses.Value.FindResponseByCode("200").Value.Description.Value)
assert.Len(t, n.Callbacks.Value, 1) assert.Equal(t, 1, n.Callbacks.Value.Len())
assert.Equal(t, "a nice callback", assert.Equal(t, "a nice callback",
n.FindCallback("niceCallback").Value.FindExpression("ohISee").Value.Description.Value) n.FindCallback("niceCallback").Value.FindExpression("ohISee").Value.Description.Value)
assert.True(t, n.Deprecated.Value) assert.True(t, n.Deprecated.Value)
@@ -76,7 +76,6 @@ servers:
} }
func TestOperation_Build_FailDocs(t *testing.T) { func TestOperation_Build_FailDocs(t *testing.T) {
yml := `externalDocs: yml := `externalDocs:
$ref: #borked` $ref: #borked`
@@ -93,7 +92,6 @@ func TestOperation_Build_FailDocs(t *testing.T) {
} }
func TestOperation_Build_FailParams(t *testing.T) { func TestOperation_Build_FailParams(t *testing.T) {
yml := `parameters: yml := `parameters:
$ref: #borked` $ref: #borked`
@@ -110,7 +108,6 @@ func TestOperation_Build_FailParams(t *testing.T) {
} }
func TestOperation_Build_FailRequestBody(t *testing.T) { func TestOperation_Build_FailRequestBody(t *testing.T) {
yml := `requestBody: yml := `requestBody:
$ref: #borked` $ref: #borked`
@@ -127,7 +124,6 @@ func TestOperation_Build_FailRequestBody(t *testing.T) {
} }
func TestOperation_Build_FailResponses(t *testing.T) { func TestOperation_Build_FailResponses(t *testing.T) {
yml := `responses: yml := `responses:
$ref: #borked` $ref: #borked`
@@ -144,7 +140,6 @@ func TestOperation_Build_FailResponses(t *testing.T) {
} }
func TestOperation_Build_FailCallbacks(t *testing.T) { func TestOperation_Build_FailCallbacks(t *testing.T) {
yml := `callbacks: yml := `callbacks:
$ref: #borked` $ref: #borked`
@@ -161,7 +156,6 @@ func TestOperation_Build_FailCallbacks(t *testing.T) {
} }
func TestOperation_Build_FailSecurity(t *testing.T) { func TestOperation_Build_FailSecurity(t *testing.T) {
yml := `security: yml := `security:
$ref: #borked` $ref: #borked`
@@ -178,7 +172,6 @@ func TestOperation_Build_FailSecurity(t *testing.T) {
} }
func TestOperation_Build_FailServers(t *testing.T) { func TestOperation_Build_FailServers(t *testing.T) {
yml := `servers: yml := `servers:
$ref: #borked` $ref: #borked`
@@ -195,7 +188,6 @@ func TestOperation_Build_FailServers(t *testing.T) {
} }
func TestOperation_Hash_n_Grab(t *testing.T) { func TestOperation_Hash_n_Grab(t *testing.T) {
yml := `tags: yml := `tags:
- nice - nice
- rice - rice
@@ -282,14 +274,12 @@ x-mint: sweet`
assert.True(t, n.GetDeprecated().Value) assert.True(t, n.GetDeprecated().Value)
assert.Len(t, n.GetExtensions(), 1) assert.Len(t, n.GetExtensions(), 1)
assert.Len(t, n.GetServers().Value.([]low.ValueReference[*Server]), 1) assert.Len(t, n.GetServers().Value.([]low.ValueReference[*Server]), 1)
assert.Len(t, n.GetCallbacks().Value, 1) assert.Equal(t, 1, n.GetCallbacks().Value.Len())
assert.Len(t, n.GetResponses().Value.(*Responses).Codes, 1) assert.Equal(t, 1, n.GetResponses().Value.(*Responses).Codes.Len())
assert.Nil(t, n.FindSecurityRequirement("I do not exist")) assert.Nil(t, n.FindSecurityRequirement("I do not exist"))
} }
func TestOperation_EmptySecurity(t *testing.T) { func TestOperation_EmptySecurity(t *testing.T) {
yml := ` yml := `
security: []` security: []`
@@ -305,5 +295,4 @@ security: []`
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, n.Security.Value, 0) assert.Len(t, n.Security.Value, 0)
} }

View File

@@ -5,12 +5,14 @@ package v3
import ( import (
"context" "context"
"testing"
"github.com/pb33f/libopenapi/datamodel/low" "github.com/pb33f/libopenapi/datamodel/low"
"github.com/pb33f/libopenapi/datamodel/low/base" "github.com/pb33f/libopenapi/datamodel/low/base"
"github.com/pb33f/libopenapi/index" "github.com/pb33f/libopenapi/index"
"github.com/pb33f/libopenapi/orderedmap"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
"testing"
) )
func TestParameter_Build(t *testing.T) { func TestParameter_Build(t *testing.T) {
@@ -172,7 +174,6 @@ func TestParameter_Build_Fail_Content(t *testing.T) {
} }
func TestParameter_Hash_n_grab(t *testing.T) { func TestParameter_Hash_n_grab(t *testing.T) {
yml := `description: michelle, meddy and maddy yml := `description: michelle, meddy and maddy
required: true required: true
deprecated: false deprecated: false
@@ -275,11 +276,11 @@ content:
assert.True(t, n.GetRequired().Value) assert.True(t, n.GetRequired().Value)
assert.False(t, n.GetDeprecated().Value) assert.False(t, n.GetDeprecated().Value)
assert.False(t, n.GetAllowEmptyValue().Value) assert.False(t, n.GetAllowEmptyValue().Value)
assert.Len(t, n.GetSchema().Value.(*base.SchemaProxy).Schema().Properties.Value, 3) assert.Equal(t, 3, n.GetSchema().Value.(*base.SchemaProxy).Schema().Properties.Value.Len())
assert.Equal(t, "beautiful", n.GetStyle().Value) assert.Equal(t, "beautiful", n.GetStyle().Value)
assert.True(t, n.GetAllowReserved().Value) assert.True(t, n.GetAllowReserved().Value)
assert.True(t, n.GetExplode().Value) assert.True(t, n.GetExplode().Value)
assert.NotNil(t, n.GetExample().Value) assert.NotNil(t, n.GetExample().Value)
assert.Len(t, n.GetExamples().Value.(map[low.KeyReference[string]]low.ValueReference[*base.Example]), 2) assert.Equal(t, 2, orderedmap.Cast[low.KeyReference[string], low.ValueReference[*base.Example]](n.GetExamples().Value).Len())
assert.Len(t, n.GetContent().Value.(map[low.KeyReference[string]]low.ValueReference[*MediaType]), 1) assert.Equal(t, 1, orderedmap.Cast[low.KeyReference[string], low.ValueReference[*MediaType]](n.GetContent().Value).Len())
} }

View File

@@ -5,12 +5,13 @@ package v3
import ( import (
"context" "context"
"testing"
"github.com/pb33f/libopenapi/datamodel/low" "github.com/pb33f/libopenapi/datamodel/low"
"github.com/pb33f/libopenapi/datamodel/low/base" "github.com/pb33f/libopenapi/datamodel/low/base"
"github.com/pb33f/libopenapi/index" "github.com/pb33f/libopenapi/index"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
"testing"
) )
func TestSecurityRequirement_Build(t *testing.T) { func TestSecurityRequirement_Build(t *testing.T) {
@@ -29,7 +30,7 @@ func TestSecurityRequirement_Build(t *testing.T) {
err = n.Build(context.Background(), nil, idxNode.Content[0], idx) err = n.Build(context.Background(), nil, idxNode.Content[0], idx)
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, n.Requirements.Value, 1) assert.Equal(t, 1, n.Requirements.Value.Len())
assert.Equal(t, "read:me", n.FindRequirement("something")[0].Value) assert.Equal(t, "read:me", n.FindRequirement("something")[0].Value)
assert.Equal(t, "write:me", n.FindRequirement("something")[1].Value) assert.Equal(t, "write:me", n.FindRequirement("something")[1].Value)
assert.Nil(t, n.FindRequirement("none")) assert.Nil(t, n.FindRequirement("none"))
@@ -72,7 +73,6 @@ x-milk: please`
assert.Equal(t, "please", n.FindExtension("x-milk").Value) assert.Equal(t, "please", n.FindExtension("x-milk").Value)
assert.Equal(t, "https://pb33f.io", n.Flows.Value.Implicit.Value.TokenUrl.Value) assert.Equal(t, "https://pb33f.io", n.Flows.Value.Implicit.Value.TokenUrl.Value)
assert.Len(t, n.GetExtensions(), 1) assert.Len(t, n.GetExtensions(), 1)
} }
func TestSecurityScheme_Build_Fail(t *testing.T) { func TestSecurityScheme_Build_Fail(t *testing.T) {

View File

@@ -5,15 +5,16 @@ package v3
import ( import (
"context" "context"
"testing"
"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/orderedmap"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
"testing"
) )
func TestServer_Build(t *testing.T) { func TestServer_Build(t *testing.T) {
yml := `x-coffee: hot yml := `x-coffee: hot
url: https://pb33f.io url: https://pb33f.io
description: high quality software for developers. description: high quality software for developers.
@@ -48,11 +49,9 @@ variables:
low.GenerateHashString(s.Value)) low.GenerateHashString(s.Value))
assert.Len(t, n.GetExtensions(), 1) assert.Len(t, n.GetExtensions(), 1)
} }
func TestServer_Build_NoVars(t *testing.T) { func TestServer_Build_NoVars(t *testing.T) {
yml := `url: https://pb33f.io yml := `url: https://pb33f.io
description: high quality software for developers.` description: high quality software for developers.`
@@ -68,6 +67,5 @@ description: high quality software for developers.`
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, "https://pb33f.io", n.URL.Value) assert.Equal(t, "https://pb33f.io", n.URL.Value)
assert.Equal(t, "high quality software for developers.", n.Description.Value) assert.Equal(t, "high quality software for developers.", n.Description.Value)
assert.Len(t, n.Variables.Value, 0) assert.Equal(t, 0, orderedmap.Len(n.Variables.Value))
} }

View File

@@ -42,9 +42,11 @@ type wrapPair[K comparable, V any] struct {
*wk8orderedmap.Pair[K, V] *wk8orderedmap.Pair[K, V]
} }
type ActionFunc[K comparable, V any] func(Pair[K, V]) error type (
type TranslateFunc[IN any, OUT any] func(IN) (OUT, error) ActionFunc[K comparable, V any] func(Pair[K, V]) error
type ResultFunc[V any] func(V) error TranslateFunc[IN any, OUT any] func(IN) (OUT, error)
ResultFunc[V any] func(V) error
)
// New creates an ordered map generic object. // New creates an ordered map generic object.
func New[K comparable, V any]() Map[K, V] { func New[K comparable, V any]() Map[K, V] {
@@ -63,6 +65,10 @@ func (o *wrapOrderedMap[K, V]) GetOrZero(k K) V {
} }
func (o *wrapOrderedMap[K, V]) First() Pair[K, V] { func (o *wrapOrderedMap[K, V]) First() Pair[K, V] {
if o == nil {
return nil
}
pair := o.OrderedMap.Oldest() pair := o.OrderedMap.Oldest()
if pair == nil { if pair == nil {
return nil return nil
@@ -76,7 +82,7 @@ func (o *wrapOrderedMap[K, V]) First() Pair[K, V] {
func NewPair[K comparable, V any](key K, value V) Pair[K, V] { func NewPair[K comparable, V any](key K, value V) Pair[K, V] {
return &wrapPair[K, V]{ return &wrapPair[K, V]{
Pair: &wk8orderedmap.Pair[K, V]{ Pair: &wk8orderedmap.Pair[K, V]{
Key: key, Key: key,
Value: value, Value: value,
}, },
} }
@@ -174,6 +180,20 @@ func First[K comparable, V any](m Map[K, V]) Pair[K, V] {
return m.First() return m.First()
} }
// Cast converts `any` to `Map`.
func Cast[K comparable, V any](v any) Map[K, V] {
if v == nil {
return nil
}
m, ok := v.(*wrapOrderedMap[K, V])
if !ok {
return nil
}
return m
}
type jobStatus[T any] struct { type jobStatus[T any] struct {
done chan struct{} done chan struct{}
result T result T

View File

@@ -26,8 +26,8 @@ var changeMutex sync.Mutex
// CreateChange is a generic function that will create a Change of type T, populate all properties if set, and then // CreateChange is a generic function that will create a Change of type T, populate all properties if set, and then
// add a pointer to Change[T] in the slice of Change pointers provided // add a pointer to Change[T] in the slice of Change pointers provided
func CreateChange(changes *[]*Change, changeType int, property string, leftValueNode, rightValueNode *yaml.Node, func CreateChange(changes *[]*Change, changeType int, property string, leftValueNode, rightValueNode *yaml.Node,
breaking bool, originalObject, newObject any) *[]*Change { breaking bool, originalObject, newObject any,
) *[]*Change {
// create a new context for the left and right nodes. // create a new context for the left and right nodes.
ctx := CreateContext(leftValueNode, rightValueNode) ctx := CreateContext(leftValueNode, rightValueNode)
c := &Change{ c := &Change{
@@ -71,7 +71,8 @@ func CreateContext(l, r *yaml.Node) *ChangeContext {
} }
func FlattenLowLevelMap[T any]( func FlattenLowLevelMap[T any](
lowMap map[low.KeyReference[string]]low.ValueReference[T]) map[string]*low.ValueReference[T] { lowMap map[low.KeyReference[string]]low.ValueReference[T],
) map[string]*low.ValueReference[T] {
flat := make(map[string]*low.ValueReference[T]) flat := make(map[string]*low.ValueReference[T])
for i := range lowMap { for i := range lowMap {
l := lowMap[i] l := lowMap[i]
@@ -80,6 +81,19 @@ func FlattenLowLevelMap[T any](
return flat return flat
} }
func FlattenLowLevelOrderedMap[T any](
lowMap orderedmap.Map[low.KeyReference[string], low.ValueReference[T]],
) map[string]*low.ValueReference[T] {
flat := make(map[string]*low.ValueReference[T])
for pair := orderedmap.First(lowMap); pair != nil; pair = pair.Next() {
k := pair.Key()
l := pair.Value()
flat[k.Value] = &l
}
return flat
}
// CountBreakingChanges counts the number of changes in a slice that are breaking // CountBreakingChanges counts the number of changes in a slice that are breaking
func CountBreakingChanges(changes []*Change) int { func CountBreakingChanges(changes []*Change) int {
b := 0 b := 0
@@ -99,7 +113,8 @@ func CountBreakingChanges(changes []*Change) int {
// properties like descriptions, summaries and other non-binding values, so a breakingRemove value can be tuned for // properties like descriptions, summaries and other non-binding values, so a breakingRemove value can be tuned for
// these circumstances. // these circumstances.
func CheckForObjectAdditionOrRemoval[T any](l, r map[string]*low.ValueReference[T], label string, changes *[]*Change, func CheckForObjectAdditionOrRemoval[T any](l, r map[string]*low.ValueReference[T], label string, changes *[]*Change,
breakingAdd, breakingRemove bool) { breakingAdd, breakingRemove bool,
) {
var left, right T var left, right T
if CheckSpecificObjectRemoved(l, r, label) { if CheckSpecificObjectRemoved(l, r, label) {
left = l[label].GetValue() left = l[label].GetValue()
@@ -129,7 +144,6 @@ func CheckSpecificObjectAdded[T any](l, r map[string]*T, label string) bool {
// CheckPropertyAdditionOrRemoval // CheckPropertyAdditionOrRemoval
// CheckForModification // CheckForModification
func CheckProperties(properties []*PropertyCheck) { func CheckProperties(properties []*PropertyCheck) {
// todo: make this async to really speed things up. // todo: make this async to really speed things up.
for _, n := range properties { for _, n := range properties {
CheckPropertyAdditionOrRemoval(n.LeftNode, n.RightNode, n.Label, n.Changes, n.Breaking, n.Original, n.New) CheckPropertyAdditionOrRemoval(n.LeftNode, n.RightNode, n.Label, n.Changes, n.Breaking, n.Original, n.New)
@@ -139,7 +153,8 @@ func CheckProperties(properties []*PropertyCheck) {
// CheckPropertyAdditionOrRemoval will run both CheckForRemoval (first) and CheckForAddition (second) // CheckPropertyAdditionOrRemoval will run both CheckForRemoval (first) and CheckForAddition (second)
func CheckPropertyAdditionOrRemoval[T any](l, r *yaml.Node, func CheckPropertyAdditionOrRemoval[T any](l, r *yaml.Node,
label string, changes *[]*Change, breaking bool, orig, new T) { label string, changes *[]*Change, breaking bool, orig, new T,
) {
CheckForRemoval[T](l, r, label, changes, breaking, orig, new) CheckForRemoval[T](l, r, label, changes, breaking, orig, new)
CheckForAddition[T](l, r, label, changes, breaking, orig, new) CheckForAddition[T](l, r, label, changes, breaking, orig, new)
} }
@@ -238,12 +253,14 @@ func CheckForModification[T any](l, r *yaml.Node, label string, changes *[]*Chan
// CheckMapForChanges checks a left and right low level map for any additions, subtractions or modifications to // CheckMapForChanges checks a left and right low level map for any additions, subtractions or modifications to
// values. The compareFunc argument should reference the correct comparison function for the generic type. // values. The compareFunc argument should reference the correct comparison function for the generic type.
func CheckMapForChanges[T any, R any](expLeft, expRight orderedmap.Map[low.KeyReference[string], low.ValueReference[T]], func CheckMapForChanges[T any, R any](expLeft, expRight orderedmap.Map[low.KeyReference[string], low.ValueReference[T]],
changes *[]*Change, label string, compareFunc func(l, r T) R) map[string]R { changes *[]*Change, label string, compareFunc func(l, r T) R,
) map[string]R {
return CheckMapForChangesWithComp(expLeft, expRight, changes, label, compareFunc, true) return CheckMapForChangesWithComp(expLeft, expRight, changes, label, compareFunc, true)
} }
func CheckMapForAdditionRemoval[T any](expLeft, expRight orderedmap.Map[low.KeyReference[string], low.ValueReference[T]], func CheckMapForAdditionRemoval[T any](expLeft, expRight orderedmap.Map[low.KeyReference[string], low.ValueReference[T]],
changes *[]*Change, label string) any { changes *[]*Change, label string,
) any {
// do nothing // do nothing
doNothing := func(l, r T) any { doNothing := func(l, r T) any {
return nil return nil
@@ -266,8 +283,8 @@ func CheckMapForAdditionRemoval[T any](expLeft, expRight orderedmap.Map[low.KeyR
// values. The compareFunc argument should reference the correct comparison function for the generic type. The compare // values. The compareFunc argument should reference the correct comparison function for the generic type. The compare
// bit determines if the comparison should be run or not. // bit determines if the comparison should be run or not.
func CheckMapForChangesWithComp[T any, R any](expLeft, expRight orderedmap.Map[low.KeyReference[string], low.ValueReference[T]], func CheckMapForChangesWithComp[T any, R any](expLeft, expRight orderedmap.Map[low.KeyReference[string], low.ValueReference[T]],
changes *[]*Change, label string, compareFunc func(l, r T) R, compare bool) map[string]R { changes *[]*Change, label string, compareFunc func(l, r T) R, compare bool,
) map[string]R {
// stop concurrent threads screwing up changes. // stop concurrent threads screwing up changes.
var chLock sync.Mutex var chLock sync.Mutex
@@ -331,7 +348,7 @@ func CheckMapForChangesWithComp[T any, R any](expLeft, expRight orderedmap.Map[l
go checkLeft(k, doneChan, lHashes, rHashes, lValues, rValues) go checkLeft(k, doneChan, lHashes, rHashes, lValues, rValues)
} }
//check right example hashes // check right example hashes
for k := range rHashes { for k := range rHashes {
count++ count++
go checkRightValue(k, doneChan, lHashes, rValues, changes, label, &chLock) go checkRightValue(k, doneChan, lHashes, rValues, changes, label, &chLock)
@@ -349,8 +366,8 @@ func CheckMapForChangesWithComp[T any, R any](expLeft, expRight orderedmap.Map[l
} }
func checkRightValue[T any](k string, doneChan chan bool, f map[string]string, p map[string]low.ValueReference[T], 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) { changes *[]*Change, label string, lock *sync.Mutex,
) {
lhash := f[k] lhash := f[k]
if lhash == "" { if lhash == "" {
lock.Lock() lock.Lock()
@@ -367,7 +384,8 @@ func checkRightValue[T any](k string, doneChan chan bool, f map[string]string, p
// ExtractStringValueSliceChanges will compare two low level string slices for changes. // ExtractStringValueSliceChanges will compare two low level string slices for changes.
func ExtractStringValueSliceChanges(lParam, rParam []low.ValueReference[string], func ExtractStringValueSliceChanges(lParam, rParam []low.ValueReference[string],
changes *[]*Change, label string, breaking bool) { changes *[]*Change, label string, breaking bool,
) {
lKeys := make([]string, len(lParam)) lKeys := make([]string, len(lParam))
rKeys := make([]string, len(rParam)) rKeys := make([]string, len(rParam))
lValues := make(map[string]low.ValueReference[string]) lValues := make(map[string]low.ValueReference[string])
@@ -404,7 +422,8 @@ func ExtractStringValueSliceChanges(lParam, rParam []low.ValueReference[string],
// ExtractRawValueSliceChanges will compare two low level interface{} slices for changes. // ExtractRawValueSliceChanges will compare two low level interface{} slices for changes.
func ExtractRawValueSliceChanges(lParam, rParam []low.ValueReference[any], func ExtractRawValueSliceChanges(lParam, rParam []low.ValueReference[any],
changes *[]*Change, label string, breaking bool) { changes *[]*Change, label string, breaking bool,
) {
lKeys := make([]string, len(lParam)) lKeys := make([]string, len(lParam))
rKeys := make([]string, len(rParam)) rKeys := make([]string, len(rParam))
lValues := make(map[string]low.ValueReference[any]) lValues := make(map[string]low.ValueReference[any])

View File

@@ -64,8 +64,8 @@ func CompareDiscriminator(l, r *base.Discriminator) *DiscriminatorChanges {
CheckProperties(props) CheckProperties(props)
// flatten maps // flatten maps
lMap := FlattenLowLevelMap[string](l.Mapping.Value) lMap := FlattenLowLevelOrderedMap[string](l.Mapping.Value)
rMap := FlattenLowLevelMap[string](r.Mapping.Value) rMap := FlattenLowLevelOrderedMap[string](r.Mapping.Value)
// check for removals, modifications and moves // check for removals, modifications and moves
for i := range lMap { for i := range lMap {
@@ -92,5 +92,4 @@ func CompareDiscriminator(l, r *base.Discriminator) *DiscriminatorChanges {
return nil return nil
} }
return dc return dc
} }

View File

@@ -6,6 +6,7 @@ package model
import ( import (
"github.com/pb33f/libopenapi/datamodel/low" "github.com/pb33f/libopenapi/datamodel/low"
v3 "github.com/pb33f/libopenapi/datamodel/low/v3" v3 "github.com/pb33f/libopenapi/datamodel/low/v3"
"github.com/pb33f/libopenapi/orderedmap"
) )
// OAuthFlowsChanges represents changes found between two OpenAPI OAuthFlows objects. // OAuthFlowsChanges represents changes found between two OpenAPI OAuthFlows objects.
@@ -228,26 +229,26 @@ func CompareOAuthFlow(l, r *v3.OAuthFlow) *OAuthFlowChanges {
CheckProperties(props) CheckProperties(props)
for k, v := range l.Scopes.Value { for pair := orderedmap.First(l.Scopes.Value); pair != nil; pair = pair.Next() {
if r != nil && r.FindScope(k.Value) == nil { if r != nil && r.FindScope(pair.Key().Value) == nil {
CreateChange(&changes, ObjectRemoved, v3.Scopes, CreateChange(&changes, ObjectRemoved, v3.Scopes,
v.ValueNode, nil, true, pair.Value().ValueNode, nil, true,
k.Value, nil) pair.Key().Value, nil)
continue continue
} }
if r != nil && r.FindScope(k.Value) != nil { if r != nil && r.FindScope(pair.Key().Value) != nil {
if v.Value != r.FindScope(k.Value).Value { if pair.Value().Value != r.FindScope(pair.Key().Value).Value {
CreateChange(&changes, Modified, v3.Scopes, CreateChange(&changes, Modified, v3.Scopes,
v.ValueNode, r.FindScope(k.Value).ValueNode, true, pair.Value().ValueNode, r.FindScope(pair.Key().Value).ValueNode, true,
v.Value, r.FindScope(k.Value).Value) pair.Value().Value, r.FindScope(pair.Key().Value).Value)
} }
} }
} }
for k, v := range r.Scopes.Value { for pair := orderedmap.First(r.Scopes.Value); pair != nil; pair = pair.Next() {
if l != nil && l.FindScope(k.Value) == nil { if l != nil && l.FindScope(pair.Key().Value) == nil {
CreateChange(&changes, ObjectAdded, v3.Scopes, CreateChange(&changes, ObjectAdded, v3.Scopes,
nil, v.ValueNode, false, nil, pair.Value().ValueNode, false,
nil, k.Value) nil, pair.Key().Value)
} }
} }
oa := new(OAuthFlowChanges) oa := new(OAuthFlowChanges)