Schemas now working, still need to check polymorphic work

However the painbarrier seems to have been smashed, now all polymorphic references can be tracked to circular references. confidence is now up 100%.
This commit is contained in:
Dave Shanley
2022-08-22 11:13:43 -04:00
parent 1a71f449ff
commit 108c3a93f3
7 changed files with 95 additions and 23 deletions

View File

@@ -121,13 +121,50 @@ func TestNewDocument_Tags(t *testing.T) {
assert.Equal(t, 20, wentLower.Description.ValueNode.Column)
}
func TestNewDocument_Components(t *testing.T) {
func TestNewDocument_Components_Links(t *testing.T) {
h := NewDocument(doc)
assert.Len(t, h.Components.Links, 2)
assert.Equal(t, "locateBurger", h.Components.Links["LocateBurger"].OperationId)
assert.Equal(t, "$response.body#/id", h.Components.Links["LocateBurger"].Parameters["burgerId"])
}
func TestNewDocument_Components_Callbacks(t *testing.T) {
h := NewDocument(doc)
assert.Len(t, h.Components.Callbacks, 1)
assert.Equal(t, "Callback payload",
h.Components.Callbacks["BurgerCallback"].Expression["{$request.query.queryUrl}"].Post.RequestBody.Description)
}
func TestNewDocument_Components_Schemas(t *testing.T) {
h := NewDocument(doc)
assert.Len(t, h.Components.Schemas, 6)
a := h.Components.Schemas["Error"]
assert.Equal(t, "No such burger as 'Big-Whopper'", a.Properties["message"].Example)
b := h.Components.Schemas["Burger"]
assert.Len(t, b.Required, 2)
assert.Equal(t, "golden slices of happy fun joy", b.Properties["fries"].Description)
assert.Equal(t, int64(2), b.Properties["numPatties"].Example)
f := h.Components.Schemas["Fries"]
assert.Equal(t, "salt", f.Properties["seasoning"].Items.Example)
assert.Len(t, f.Properties["favoriteDrink"].Properties["drinkType"].Enum, 2)
d := h.Components.Schemas["Drink"]
assert.Len(t, d.Required, 2)
assert.True(t, d.AdditionalProperties.(bool))
assert.Equal(t, "drinkType", d.Discriminator.PropertyName)
assert.Equal(t, "some value", d.Discriminator.Mapping["drink"])
ext := h.Components.Extensions
assert.Equal(t, "loud", ext["x-screaming-baby"])
}
func TestNewDocument_Components_Headers(t *testing.T) {
h := NewDocument(doc)
assert.Len(t, h.Components.Headers, 1)
assert.Equal(t, "this is a header", h.Components.Headers["UseOil"].Description)
}

View File

@@ -33,7 +33,7 @@ type Schema struct {
OneOf []*Schema
AnyOf []*Schema
Not []*Schema
Items []*Schema
Items *Schema
Properties map[string]*Schema
AdditionalProperties any
Description string
@@ -94,7 +94,7 @@ func NewSchema(schema *low.Schema) *Schema {
var enum []string
for i := range schema.Enum.Value {
enum = append(req, schema.Enum.Value[i].Value)
enum = append(enum, schema.Enum.Value[i].Value)
}
s.Enum = enum
@@ -111,7 +111,7 @@ func NewSchema(schema *low.Schema) *Schema {
bChan := make(chan *Schema)
// for every item, build schema async
buildSchema := func(sch lowmodel.NodeReference[*low.Schema], bChan chan *Schema) {
buildSchemaChild := func(sch lowmodel.NodeReference[*low.Schema], bChan chan *Schema) {
if ss := getSeenSchema(sch.GenerateMapKey()); ss != nil {
bChan <- ss
return
@@ -122,7 +122,7 @@ func NewSchema(schema *low.Schema) *Schema {
}
totalSchemas := len(schemas)
for v := range schemas {
go buildSchema(schemas[v], bChan)
go buildSchemaChild(schemas[v], bChan)
}
j := 0
for j < totalSchemas {
@@ -178,15 +178,23 @@ func NewSchema(schema *low.Schema) *Schema {
go buildOutSchema(schema.Not.Value, &not, polyCompletedChan)
}
if !schema.Items.IsEmpty() {
go buildOutSchema(schema.Items.Value, &items, polyCompletedChan)
// items is only a single prop, however the method uses an array, so pack it up in one.
var itms []lowmodel.NodeReference[*low.Schema]
itms = append(itms, lowmodel.NodeReference[*low.Schema]{
Value: schema.Items.Value,
KeyNode: schema.Items.KeyNode,
ValueNode: schema.Items.ValueNode,
})
go buildOutSchema(itms, &items, polyCompletedChan)
}
completePoly := 0
completedProps := 0
totalProps := len(schema.Properties.Value)
totalPoly := len(schema.AllOf.Value) + len(schema.OneOf.Value) + len(schema.AnyOf.Value) + len(schema.Not.Value) +
len(schema.Items.Value)
totalPoly := len(schema.AllOf.Value) + len(schema.OneOf.Value) + len(schema.AnyOf.Value) + len(schema.Not.Value)
if !schema.Items.IsEmpty() {
totalPoly++ // only a single item can be present.
}
if totalProps+totalPoly > 0 {
allDone:
for true {
@@ -208,10 +216,13 @@ func NewSchema(schema *low.Schema) *Schema {
s.AnyOf = anyOf
s.AllOf = allOf
s.Not = not
s.Items = items
if len(items) > 0 {
s.Items = items[0] // there will only ever be one.
}
return s
}
func (s *Schema) GoLow() *low.Schema {
return s.low
}
}

View File

@@ -9,6 +9,7 @@ import (
"github.com/pb33f/libopenapi/index"
"github.com/pb33f/libopenapi/utils"
"gopkg.in/yaml.v3"
"strings"
"sync"
)
@@ -205,16 +206,20 @@ func extractComponentValues[T low.Buildable[N], N any](label string, root *yaml.
},
}
}
totalComponents := 0
for i, v := range nodeValue.Content {
// always ignore extensions
if i%2 == 0 {
currentLabel = v
continue
}
if strings.HasPrefix(strings.ToLower(currentLabel.Value), "x-") {
continue
}
totalComponents++
go buildComponent(currentLabel, v, bChan, errorChan)
}
totalComponents := len(nodeValue.Content) / 2
completedComponents := 0
for completedComponents < totalComponents {
select {

View File

@@ -8,6 +8,7 @@ import (
"github.com/pb33f/libopenapi/index"
"github.com/pb33f/libopenapi/utils"
"gopkg.in/yaml.v3"
"strconv"
)
const (
@@ -67,3 +68,19 @@ func (ex *Example) Build(root *yaml.Node, idx *index.SpecIndex) error {
}
return nil
}
func ExtractExampleValue(exp *yaml.Node) any {
if utils.IsNodeBoolValue(exp) {
v, _ := strconv.ParseBool(exp.Value)
return v
}
if utils.IsNodeIntValue(exp) {
v, _ := strconv.ParseInt(exp.Value, 10, 64)
return v
}
if utils.IsNodeFloatValue(exp) {
v, _ := strconv.ParseFloat(exp.Value, 64)
return v
}
return exp.Value
}

View File

@@ -44,7 +44,7 @@ type Schema struct {
OneOf low.NodeReference[[]low.NodeReference[*Schema]]
AnyOf low.NodeReference[[]low.NodeReference[*Schema]]
Not low.NodeReference[[]low.NodeReference[*Schema]]
Items low.NodeReference[[]low.NodeReference[*Schema]]
Items low.NodeReference[*Schema]
Properties low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*Schema]]
AdditionalProperties low.NodeReference[any]
Description low.NodeReference[string]
@@ -93,7 +93,7 @@ func (s *Schema) BuildLevel(root *yaml.Node, idx *index.SpecIndex, level int) er
// handle example if set.
_, expLabel, expNode := utils.FindKeyNodeFull(ExampleLabel, root.Content)
if expNode != nil {
s.Example = low.NodeReference[any]{Value: expNode.Value, KeyNode: expLabel, ValueNode: expNode}
s.Example = low.NodeReference[any]{Value: ExtractExampleValue(expNode), KeyNode: expLabel, ValueNode: expNode}
}
_, addPLabel, addPNode := utils.FindKeyNodeFull(AdditionalPropertiesLabel, root.Content)
@@ -265,8 +265,9 @@ func (s *Schema) BuildLevel(root *yaml.Node, idx *index.SpecIndex, level int) er
}
}
if len(items) > 0 {
s.Items = low.NodeReference[[]low.NodeReference[*Schema]]{
Value: items,
// items can only be a single def, so only extract a single value
s.Items = low.NodeReference[*Schema]{
Value: items[0].Value,
KeyNode: itemsLabel,
ValueNode: itemsValue,
}

View File

@@ -197,15 +197,15 @@ additionalProperties: true `
assert.Equal(t, "notBExp", v.Value.Example.Value)
// check values Items
assert.Equal(t, "an items thing", sch.Items.Value[0].Value.Description.Value)
assert.Len(t, sch.Items.Value[0].Value.Properties.Value, 2)
assert.Equal(t, "an items thing", sch.Items.Value.Description.Value)
assert.Len(t, sch.Items.Value.Properties.Value, 2)
v = sch.Items.Value[0].Value.FindProperty("itemsA")
v = sch.Items.Value.FindProperty("itemsA")
assert.NotNil(t, v)
assert.Equal(t, "itemsA description", v.Value.Description.Value)
assert.Equal(t, "itemsAExp", v.Value.Example.Value)
v = sch.Items.Value[0].Value.FindProperty("itemsB")
v = sch.Items.Value.FindProperty("itemsB")
assert.NotNil(t, v)
assert.Equal(t, "itemsB description", v.Value.Description.Value)
assert.Equal(t, "itemsBExp", v.Value.Example.Value)
@@ -456,7 +456,7 @@ items:
assert.Equal(t, desc, sch.AnyOf.Value[0].Value.Description.Value)
assert.Equal(t, desc, sch.AllOf.Value[0].Value.Description.Value)
assert.Equal(t, desc, sch.Not.Value[0].Value.Description.Value)
assert.Equal(t, desc, sch.Items.Value[0].Value.Description.Value)
assert.Equal(t, desc, sch.Items.Value.Description.Value)
}
func Test_Schema_Polymorphism_Array_Ref_Fail(t *testing.T) {
@@ -546,7 +546,7 @@ items:
assert.Equal(t, desc, sch.AnyOf.Value[0].Value.Description.Value)
assert.Equal(t, desc, sch.AllOf.Value[0].Value.Description.Value)
assert.Equal(t, desc, sch.Not.Value[0].Value.Description.Value)
assert.Equal(t, desc, sch.Items.Value[0].Value.Description.Value)
assert.Equal(t, desc, sch.Items.Value.Description.Value)
}
func Test_Schema_Polymorphism_Map_Ref_Fail(t *testing.T) {

View File

@@ -511,6 +511,7 @@ components:
SomePayload:
type: string
description: some kind of payload for something.
x-screaming-baby: loud
x-something-something: darkside
externalDocs:
description: "Find out more information about our products)"