mirror of
https://github.com/LukeHagar/libopenapi.git
synced 2025-12-08 20:47:43 +00:00
Paths test coverage is completed.
Found some good gaps a holes in existing overage.
This commit is contained in:
@@ -111,54 +111,3 @@ func TestCallback_Build_Using_InlineRef(t *testing.T) {
|
|||||||
assert.Equal(t, "this is something", exp.Value.Post.Value.RequestBody.Value.Description.Value)
|
assert.Equal(t, "this is something", exp.Value.Post.Value.RequestBody.Value.Description.Value)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCallback_Build_Using_Ref(t *testing.T) {
|
|
||||||
|
|
||||||
// first we need an index.
|
|
||||||
doc := `paths:
|
|
||||||
'/something/here':
|
|
||||||
post:
|
|
||||||
requestBody:
|
|
||||||
$ref: '#/components/requestBodies/rbOne'
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
$ref: '#/components/schemas/AThing'
|
|
||||||
components:
|
|
||||||
schemas:
|
|
||||||
AThing:
|
|
||||||
description: a thing.
|
|
||||||
type: string
|
|
||||||
requestBodies:
|
|
||||||
rbOne:
|
|
||||||
description: a request body.
|
|
||||||
type: string`
|
|
||||||
|
|
||||||
var idxNode yaml.Node
|
|
||||||
mErr := yaml.Unmarshal([]byte(doc), &idxNode)
|
|
||||||
assert.NoError(t, mErr)
|
|
||||||
idx := index.NewSpecIndex(&idxNode)
|
|
||||||
|
|
||||||
yml := `'{$request.query.queryUrl}':
|
|
||||||
$ref: '#/paths/~1something~1here'`
|
|
||||||
|
|
||||||
var rootNode yaml.Node
|
|
||||||
mErr = yaml.Unmarshal([]byte(yml), &rootNode)
|
|
||||||
assert.NoError(t, mErr)
|
|
||||||
|
|
||||||
var n Callback
|
|
||||||
err := low.BuildModel(rootNode.Content[0], &n)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
err = n.Build(rootNode.Content[0], idx)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Len(t, n.Expression.Value, 1)
|
|
||||||
|
|
||||||
exp := n.FindExpression("{$request.query.queryUrl}")
|
|
||||||
assert.NotNil(t, exp.Value)
|
|
||||||
assert.NotNil(t, exp.Value.Post.Value)
|
|
||||||
assert.Equal(t, "a request body.", exp.Value.Post.Value.RequestBody.Value.Description.Value)
|
|
||||||
|
|
||||||
okCode := exp.Value.Post.Value.Responses.Value.FindResponseByCode("200")
|
|
||||||
assert.Equal(t, "a thing.", okCode.Value.Description.Value)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ package v3
|
|||||||
import (
|
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/utils"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -53,6 +54,12 @@ func (h *Header) FindContent(ext string) *low.ValueReference[*MediaType] {
|
|||||||
func (h *Header) Build(root *yaml.Node, idx *index.SpecIndex) error {
|
func (h *Header) Build(root *yaml.Node, idx *index.SpecIndex) error {
|
||||||
h.Extensions = low.ExtractExtensions(root)
|
h.Extensions = low.ExtractExtensions(root)
|
||||||
|
|
||||||
|
// handle example if set.
|
||||||
|
_, expLabel, expNode := utils.FindKeyNodeFull(ExampleLabel, root.Content)
|
||||||
|
if expNode != nil {
|
||||||
|
h.Example = low.ExtractExample(expNode, expLabel)
|
||||||
|
}
|
||||||
|
|
||||||
// handle examples if set.
|
// handle examples if set.
|
||||||
exps, eErr := low.ExtractMap[*Example](ExamplesLabel, root, idx)
|
exps, eErr := low.ExtractMap[*Example](ExamplesLabel, root, idx)
|
||||||
if eErr != nil {
|
if eErr != nil {
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestMediaType_Build(t *testing.T) {
|
func TestMediaType_Build(t *testing.T) {
|
||||||
|
|
||||||
yml := `schema:
|
yml := `schema:
|
||||||
type: string
|
type: string
|
||||||
example: hello
|
example: hello
|
||||||
@@ -46,7 +45,6 @@ x-rock: and roll`
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestMediaType_Build_Fail_Schema(t *testing.T) {
|
func TestMediaType_Build_Fail_Schema(t *testing.T) {
|
||||||
|
|
||||||
yml := `schema:
|
yml := `schema:
|
||||||
$ref: #bork`
|
$ref: #bork`
|
||||||
|
|
||||||
@@ -60,11 +58,9 @@ func TestMediaType_Build_Fail_Schema(t *testing.T) {
|
|||||||
|
|
||||||
err = n.Build(idxNode.Content[0], idx)
|
err = n.Build(idxNode.Content[0], idx)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMediaType_Build_Fail_Examples(t *testing.T) {
|
func TestMediaType_Build_Fail_Examples(t *testing.T) {
|
||||||
|
|
||||||
yml := `examples:
|
yml := `examples:
|
||||||
waff:
|
waff:
|
||||||
$ref: #bork`
|
$ref: #bork`
|
||||||
@@ -83,7 +79,6 @@ func TestMediaType_Build_Fail_Examples(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestMediaType_Build_Fail_Encoding(t *testing.T) {
|
func TestMediaType_Build_Fail_Encoding(t *testing.T) {
|
||||||
|
|
||||||
yml := `encoding:
|
yml := `encoding:
|
||||||
wiff:
|
wiff:
|
||||||
$ref: #bork`
|
$ref: #bork`
|
||||||
@@ -98,5 +93,4 @@ func TestMediaType_Build_Fail_Encoding(t *testing.T) {
|
|||||||
|
|
||||||
err = n.Build(idxNode.Content[0], idx)
|
err = n.Build(idxNode.Content[0], idx)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
package v3
|
package v3
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -15,7 +18,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Operation struct {
|
type Operation struct {
|
||||||
Tags low.NodeReference[low.NodeReference[string]]
|
Tags low.NodeReference[[]low.ValueReference[string]]
|
||||||
Summary low.NodeReference[string]
|
Summary low.NodeReference[string]
|
||||||
Description low.NodeReference[string]
|
Description low.NodeReference[string]
|
||||||
ExternalDocs low.NodeReference[*ExternalDoc]
|
ExternalDocs low.NodeReference[*ExternalDoc]
|
||||||
@@ -30,6 +33,10 @@ type Operation struct {
|
|||||||
Extensions map[low.KeyReference[string]]low.ValueReference[any]
|
Extensions map[low.KeyReference[string]]low.ValueReference[any]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (o *Operation) FindCallback(callback string) *low.ValueReference[*Callback] {
|
||||||
|
return low.FindItemInMap[*Callback](callback, o.Callbacks.Value)
|
||||||
|
}
|
||||||
|
|
||||||
func (o *Operation) Build(root *yaml.Node, idx *index.SpecIndex) error {
|
func (o *Operation) Build(root *yaml.Node, idx *index.SpecIndex) error {
|
||||||
o.Extensions = low.ExtractExtensions(root)
|
o.Extensions = low.ExtractExtensions(root)
|
||||||
|
|
||||||
@@ -63,7 +70,7 @@ func (o *Operation) Build(root *yaml.Node, idx *index.SpecIndex) error {
|
|||||||
// extract responses
|
// extract responses
|
||||||
respBody, respErr := low.ExtractObject[*Responses](ResponsesLabel, root, idx)
|
respBody, respErr := low.ExtractObject[*Responses](ResponsesLabel, root, idx)
|
||||||
if respErr != nil {
|
if respErr != nil {
|
||||||
return rErr
|
return respErr
|
||||||
}
|
}
|
||||||
o.Responses = respBody
|
o.Responses = respBody
|
||||||
|
|
||||||
|
|||||||
193
datamodel/low/3.0/operation_test.go
Normal file
193
datamodel/low/3.0/operation_test.go
Normal file
@@ -0,0 +1,193 @@
|
|||||||
|
// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package v3
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/pb33f/libopenapi/datamodel/low"
|
||||||
|
"github.com/pb33f/libopenapi/index"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestOperation_Build(t *testing.T) {
|
||||||
|
|
||||||
|
yml := `tags:
|
||||||
|
- meddy
|
||||||
|
- maddy
|
||||||
|
summary: building a business
|
||||||
|
description: takes hard work
|
||||||
|
externalDocs:
|
||||||
|
description: some docs
|
||||||
|
operationId: beefyBeef
|
||||||
|
parameters:
|
||||||
|
- name: pizza
|
||||||
|
- name: cake
|
||||||
|
requestBody:
|
||||||
|
description: a requestBody
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: an OK response
|
||||||
|
callbacks:
|
||||||
|
niceCallback:
|
||||||
|
ohISee:
|
||||||
|
description: a nice callback
|
||||||
|
deprecated: true
|
||||||
|
security:
|
||||||
|
- books:
|
||||||
|
- read:books
|
||||||
|
- write:books
|
||||||
|
servers:
|
||||||
|
- url: https://pb33f.io`
|
||||||
|
|
||||||
|
var idxNode yaml.Node
|
||||||
|
_ = yaml.Unmarshal([]byte(yml), &idxNode)
|
||||||
|
idx := index.NewSpecIndex(&idxNode)
|
||||||
|
|
||||||
|
var n Operation
|
||||||
|
err := low.BuildModel(&idxNode, &n)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
err = n.Build(idxNode.Content[0], idx)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
assert.Len(t, n.Tags.Value, 2)
|
||||||
|
assert.Equal(t, "building a business", n.Summary.Value)
|
||||||
|
assert.Equal(t, "takes hard work", n.Description.Value)
|
||||||
|
assert.Equal(t, "some docs", n.ExternalDocs.Value.Description.Value)
|
||||||
|
assert.Equal(t, "beefyBeef", n.OperationId.Value)
|
||||||
|
assert.Len(t, n.Parameters.Value, 2)
|
||||||
|
assert.Equal(t, "a requestBody", n.RequestBody.Value.Description.Value)
|
||||||
|
assert.Len(t, n.Responses.Value.Codes, 1)
|
||||||
|
assert.Equal(t, "an OK response", n.Responses.Value.FindResponseByCode("200").Value.Description.Value)
|
||||||
|
assert.Len(t, n.Callbacks.Value, 1)
|
||||||
|
assert.Equal(t, "a nice callback",
|
||||||
|
n.FindCallback("niceCallback").Value.FindExpression("ohISee").Value.Description.Value)
|
||||||
|
assert.True(t, n.Deprecated.Value)
|
||||||
|
assert.Len(t, n.Security.Value.ValueRequirements, 1)
|
||||||
|
assert.Len(t, n.Security.Value.FindRequirement("books"), 2)
|
||||||
|
assert.Equal(t, "read:books", n.Security.Value.FindRequirement("books")[0].Value)
|
||||||
|
assert.Equal(t, "write:books", n.Security.Value.FindRequirement("books")[1].Value)
|
||||||
|
assert.Len(t, n.Servers.Value, 1)
|
||||||
|
assert.Equal(t, "https://pb33f.io", n.Servers.Value[0].Value.URL.Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestOperation_Build_FailDocs(t *testing.T) {
|
||||||
|
|
||||||
|
yml := `externalDocs:
|
||||||
|
$ref: #borked`
|
||||||
|
|
||||||
|
var idxNode yaml.Node
|
||||||
|
_ = yaml.Unmarshal([]byte(yml), &idxNode)
|
||||||
|
idx := index.NewSpecIndex(&idxNode)
|
||||||
|
|
||||||
|
var n Operation
|
||||||
|
err := low.BuildModel(&idxNode, &n)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
err = n.Build(idxNode.Content[0], idx)
|
||||||
|
assert.Error(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestOperation_Build_FailParams(t *testing.T) {
|
||||||
|
|
||||||
|
yml := `parameters:
|
||||||
|
$ref: #borked`
|
||||||
|
|
||||||
|
var idxNode yaml.Node
|
||||||
|
_ = yaml.Unmarshal([]byte(yml), &idxNode)
|
||||||
|
idx := index.NewSpecIndex(&idxNode)
|
||||||
|
|
||||||
|
var n Operation
|
||||||
|
err := low.BuildModel(&idxNode, &n)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
err = n.Build(idxNode.Content[0], idx)
|
||||||
|
assert.Error(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestOperation_Build_FailRequestBody(t *testing.T) {
|
||||||
|
|
||||||
|
yml := `requestBody:
|
||||||
|
$ref: #borked`
|
||||||
|
|
||||||
|
var idxNode yaml.Node
|
||||||
|
_ = yaml.Unmarshal([]byte(yml), &idxNode)
|
||||||
|
idx := index.NewSpecIndex(&idxNode)
|
||||||
|
|
||||||
|
var n Operation
|
||||||
|
err := low.BuildModel(&idxNode, &n)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
err = n.Build(idxNode.Content[0], idx)
|
||||||
|
assert.Error(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestOperation_Build_FailResponses(t *testing.T) {
|
||||||
|
|
||||||
|
yml := `responses:
|
||||||
|
$ref: #borked`
|
||||||
|
|
||||||
|
var idxNode yaml.Node
|
||||||
|
_ = yaml.Unmarshal([]byte(yml), &idxNode)
|
||||||
|
idx := index.NewSpecIndex(&idxNode)
|
||||||
|
|
||||||
|
var n Operation
|
||||||
|
err := low.BuildModel(&idxNode, &n)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
err = n.Build(idxNode.Content[0], idx)
|
||||||
|
assert.Error(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestOperation_Build_FailCallbacks(t *testing.T) {
|
||||||
|
|
||||||
|
yml := `callbacks:
|
||||||
|
$ref: #borked`
|
||||||
|
|
||||||
|
var idxNode yaml.Node
|
||||||
|
_ = yaml.Unmarshal([]byte(yml), &idxNode)
|
||||||
|
idx := index.NewSpecIndex(&idxNode)
|
||||||
|
|
||||||
|
var n Operation
|
||||||
|
err := low.BuildModel(&idxNode, &n)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
err = n.Build(idxNode.Content[0], idx)
|
||||||
|
assert.Error(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestOperation_Build_FailSecurity(t *testing.T) {
|
||||||
|
|
||||||
|
yml := `security:
|
||||||
|
$ref: #borked`
|
||||||
|
|
||||||
|
var idxNode yaml.Node
|
||||||
|
_ = yaml.Unmarshal([]byte(yml), &idxNode)
|
||||||
|
idx := index.NewSpecIndex(&idxNode)
|
||||||
|
|
||||||
|
var n Operation
|
||||||
|
err := low.BuildModel(&idxNode, &n)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
err = n.Build(idxNode.Content[0], idx)
|
||||||
|
assert.Error(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestOperation_Build_FailServers(t *testing.T) {
|
||||||
|
|
||||||
|
yml := `servers:
|
||||||
|
$ref: #borked`
|
||||||
|
|
||||||
|
var idxNode yaml.Node
|
||||||
|
_ = yaml.Unmarshal([]byte(yml), &idxNode)
|
||||||
|
idx := index.NewSpecIndex(&idxNode)
|
||||||
|
|
||||||
|
var n Operation
|
||||||
|
err := low.BuildModel(&idxNode, &n)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
err = n.Build(idxNode.Content[0], idx)
|
||||||
|
assert.Error(t, err)
|
||||||
|
}
|
||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
package v3
|
package v3
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -37,13 +40,17 @@ func (p *Parameter) FindExample(eType string) *low.ValueReference[*Example] {
|
|||||||
return low.FindItemInMap[*Example](eType, p.Examples.Value)
|
return low.FindItemInMap[*Example](eType, p.Examples.Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *Parameter) FindExtension(ext string) *low.ValueReference[any] {
|
||||||
|
return low.FindItemInMap[any](ext, p.Extensions)
|
||||||
|
}
|
||||||
|
|
||||||
func (p *Parameter) Build(root *yaml.Node, idx *index.SpecIndex) error {
|
func (p *Parameter) Build(root *yaml.Node, idx *index.SpecIndex) error {
|
||||||
p.Extensions = low.ExtractExtensions(root)
|
p.Extensions = low.ExtractExtensions(root)
|
||||||
|
|
||||||
// handle example if set.
|
// handle example if set.
|
||||||
_, expLabel, expNode := utils.FindKeyNodeFull(ExampleLabel, root.Content)
|
_, expLabel, expNode := utils.FindKeyNodeFull(ExampleLabel, root.Content)
|
||||||
if expNode != nil {
|
if expNode != nil {
|
||||||
p.Example = low.NodeReference[any]{Value: expNode.Value, KeyNode: expLabel, ValueNode: expNode}
|
p.Example = low.ExtractExample(expNode, expLabel)
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle schema
|
// handle schema
|
||||||
|
|||||||
169
datamodel/low/3.0/parameter_test.go
Normal file
169
datamodel/low/3.0/parameter_test.go
Normal file
@@ -0,0 +1,169 @@
|
|||||||
|
// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package v3
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/pb33f/libopenapi/datamodel/low"
|
||||||
|
"github.com/pb33f/libopenapi/index"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestParameter_Build(t *testing.T) {
|
||||||
|
yml := `description: michelle, meddy and maddy
|
||||||
|
required: true
|
||||||
|
deprecated: false
|
||||||
|
name: happy
|
||||||
|
in: path
|
||||||
|
allowEmptyValue: false
|
||||||
|
style: beautiful
|
||||||
|
explode: true
|
||||||
|
allowReserved: true
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
description: my triple M, my loves
|
||||||
|
properties:
|
||||||
|
michelle:
|
||||||
|
type: string
|
||||||
|
description: she is my heart.
|
||||||
|
meddy:
|
||||||
|
type: string
|
||||||
|
description: she is my song.
|
||||||
|
maddy:
|
||||||
|
type: string
|
||||||
|
description: he is my champion.
|
||||||
|
x-family-love: strong
|
||||||
|
example:
|
||||||
|
michelle: my love.
|
||||||
|
maddy: my champion.
|
||||||
|
meddy: my song.
|
||||||
|
content:
|
||||||
|
family/love:
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
description: family love.`
|
||||||
|
|
||||||
|
var idxNode yaml.Node
|
||||||
|
mErr := yaml.Unmarshal([]byte(yml), &idxNode)
|
||||||
|
assert.NoError(t, mErr)
|
||||||
|
idx := index.NewSpecIndex(&idxNode)
|
||||||
|
|
||||||
|
var n Parameter
|
||||||
|
err := low.BuildModel(&idxNode, &n)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
err = n.Build(idxNode.Content[0], idx)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, "michelle, meddy and maddy", n.Description.Value)
|
||||||
|
assert.True(t, n.AllowReserved.Value)
|
||||||
|
assert.True(t, n.Explode.Value)
|
||||||
|
assert.True(t, n.Required.Value)
|
||||||
|
assert.False(t, n.Deprecated.Value)
|
||||||
|
assert.Equal(t, "happy", n.Name.Value)
|
||||||
|
assert.Equal(t, "path", n.In.Value)
|
||||||
|
assert.NotNil(t, n.Schema.Value)
|
||||||
|
assert.Equal(t, "my triple M, my loves", n.Schema.Value.Description.Value)
|
||||||
|
assert.NotNil(t, n.Schema.Value.Properties.Value)
|
||||||
|
assert.Equal(t, "she is my heart.", n.Schema.Value.FindProperty("michelle").Value.Description.Value)
|
||||||
|
assert.Equal(t, "she is my song.", n.Schema.Value.FindProperty("meddy").Value.Description.Value)
|
||||||
|
assert.Equal(t, "he is my champion.", n.Schema.Value.FindProperty("maddy").Value.Description.Value)
|
||||||
|
|
||||||
|
if v, ok := n.Example.Value.(map[string]interface{}); ok {
|
||||||
|
assert.Equal(t, "my love.", v["michelle"])
|
||||||
|
assert.Equal(t, "my song.", v["meddy"])
|
||||||
|
assert.Equal(t, "my champion.", v["maddy"])
|
||||||
|
} else {
|
||||||
|
assert.Fail(t, "should not fail")
|
||||||
|
}
|
||||||
|
|
||||||
|
con := n.FindContent("family/love").Value
|
||||||
|
assert.NotNil(t, con)
|
||||||
|
assert.Equal(t, "family love.", con.Schema.Value.Description.Value)
|
||||||
|
assert.Nil(t, n.FindContent("unknown"))
|
||||||
|
|
||||||
|
ext := n.FindExtension("x-family-love").Value
|
||||||
|
assert.Equal(t, "strong", ext)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParameter_Build_Success_Examples(t *testing.T) {
|
||||||
|
yml := `examples:
|
||||||
|
family:
|
||||||
|
value:
|
||||||
|
michelle: my love.
|
||||||
|
maddy: my champion.
|
||||||
|
meddy: my song.`
|
||||||
|
|
||||||
|
var idxNode yaml.Node
|
||||||
|
_ = yaml.Unmarshal([]byte(yml), &idxNode)
|
||||||
|
idx := index.NewSpecIndex(&idxNode)
|
||||||
|
|
||||||
|
var n Parameter
|
||||||
|
err := low.BuildModel(&idxNode, &n)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
err = n.Build(idxNode.Content[0], idx)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
exp := n.FindExample("family").Value
|
||||||
|
assert.NotNil(t, exp)
|
||||||
|
|
||||||
|
if v, ok := exp.Value.Value.(map[string]interface{}); ok {
|
||||||
|
assert.Equal(t, "my love.", v["michelle"])
|
||||||
|
assert.Equal(t, "my song.", v["meddy"])
|
||||||
|
assert.Equal(t, "my champion.", v["maddy"])
|
||||||
|
} else {
|
||||||
|
assert.Fail(t, "should not fail")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParameter_Build_Fail_Examples(t *testing.T) {
|
||||||
|
yml := `examples:
|
||||||
|
family:
|
||||||
|
$ref: I AM BORKED`
|
||||||
|
|
||||||
|
var idxNode yaml.Node
|
||||||
|
_ = yaml.Unmarshal([]byte(yml), &idxNode)
|
||||||
|
idx := index.NewSpecIndex(&idxNode)
|
||||||
|
|
||||||
|
var n Parameter
|
||||||
|
err := low.BuildModel(&idxNode, &n)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
err = n.Build(idxNode.Content[0], idx)
|
||||||
|
assert.Error(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParameter_Build_Fail_Schema(t *testing.T) {
|
||||||
|
yml := `schema:
|
||||||
|
$ref: I will fail.`
|
||||||
|
|
||||||
|
var idxNode yaml.Node
|
||||||
|
_ = yaml.Unmarshal([]byte(yml), &idxNode)
|
||||||
|
idx := index.NewSpecIndex(&idxNode)
|
||||||
|
|
||||||
|
var n Parameter
|
||||||
|
err := low.BuildModel(&idxNode, &n)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
err = n.Build(idxNode.Content[0], idx)
|
||||||
|
assert.Error(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParameter_Build_Fail_Content(t *testing.T) {
|
||||||
|
yml := `content:
|
||||||
|
ohMyStars:
|
||||||
|
$ref: fail!`
|
||||||
|
|
||||||
|
var idxNode yaml.Node
|
||||||
|
_ = yaml.Unmarshal([]byte(yml), &idxNode)
|
||||||
|
idx := index.NewSpecIndex(&idxNode)
|
||||||
|
|
||||||
|
var n Parameter
|
||||||
|
err := low.BuildModel(&idxNode, &n)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
err = n.Build(idxNode.Content[0], idx)
|
||||||
|
assert.Error(t, err)
|
||||||
|
}
|
||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
package v3
|
package v3
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -36,6 +39,10 @@ func (p *Paths) FindPath(path string) *low.ValueReference[*PathItem] {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *Paths) FindExtension(ext string) *low.ValueReference[any] {
|
||||||
|
return low.FindItemInMap[any](ext, p.Extensions)
|
||||||
|
}
|
||||||
|
|
||||||
func (p *Paths) Build(root *yaml.Node, idx *index.SpecIndex) error {
|
func (p *Paths) Build(root *yaml.Node, idx *index.SpecIndex) error {
|
||||||
p.Extensions = low.ExtractExtensions(root)
|
p.Extensions = low.ExtractExtensions(root)
|
||||||
skip := false
|
skip := false
|
||||||
@@ -56,12 +63,20 @@ func (p *Paths) Build(root *yaml.Node, idx *index.SpecIndex) error {
|
|||||||
currentNode = pathNode
|
currentNode = pathNode
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
var path = PathItem{}
|
|
||||||
err := low.BuildModel(pathNode, &path)
|
|
||||||
if err != nil {
|
|
||||||
|
|
||||||
|
if ok, _, _ := utils.IsNodeRefValue(pathNode); ok {
|
||||||
|
r := low.LocateRefNode(pathNode, idx)
|
||||||
|
if r != nil {
|
||||||
|
pathNode = r
|
||||||
|
} else {
|
||||||
|
return fmt.Errorf("path item build failed: cannot find reference: %s at line %d, col %d",
|
||||||
|
pathNode.Content[1].Value, pathNode.Content[1].Line, pathNode.Content[1].Column)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
err = path.Build(pathNode, idx)
|
|
||||||
|
var path = PathItem{}
|
||||||
|
_ = low.BuildModel(pathNode, &path)
|
||||||
|
err := path.Build(pathNode, idx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -92,11 +107,15 @@ type PathItem struct {
|
|||||||
Head low.NodeReference[*Operation]
|
Head low.NodeReference[*Operation]
|
||||||
Patch low.NodeReference[*Operation]
|
Patch low.NodeReference[*Operation]
|
||||||
Trace low.NodeReference[*Operation]
|
Trace low.NodeReference[*Operation]
|
||||||
Servers []low.NodeReference[*Server]
|
Servers low.NodeReference[[]low.ValueReference[*Server]]
|
||||||
Parameters []low.NodeReference[*Parameter]
|
Parameters low.NodeReference[[]low.ValueReference[*Parameter]]
|
||||||
Extensions map[low.KeyReference[string]]low.ValueReference[any]
|
Extensions map[low.KeyReference[string]]low.ValueReference[any]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *PathItem) FindExtension(ext string) *low.ValueReference[any] {
|
||||||
|
return low.FindItemInMap[any](ext, p.Extensions)
|
||||||
|
}
|
||||||
|
|
||||||
func (p *PathItem) Build(root *yaml.Node, idx *index.SpecIndex) error {
|
func (p *PathItem) Build(root *yaml.Node, idx *index.SpecIndex) error {
|
||||||
p.Extensions = low.ExtractExtensions(root)
|
p.Extensions = low.ExtractExtensions(root)
|
||||||
skip := false
|
skip := false
|
||||||
@@ -107,12 +126,16 @@ func (p *PathItem) Build(root *yaml.Node, idx *index.SpecIndex) error {
|
|||||||
|
|
||||||
var ops []low.NodeReference[*Operation]
|
var ops []low.NodeReference[*Operation]
|
||||||
|
|
||||||
if ok, _, _ := utils.IsNodeRefValue(root); ok {
|
// extract parameters
|
||||||
r := low.LocateRefNode(root, idx)
|
params, ln, vn, pErr := low.ExtractArray[*Parameter](ParametersLabel, root, idx)
|
||||||
if r != nil {
|
if pErr != nil {
|
||||||
root = r
|
return pErr
|
||||||
} else {
|
}
|
||||||
return nil
|
if params != nil {
|
||||||
|
p.Parameters = low.NodeReference[[]low.ValueReference[*Parameter]]{
|
||||||
|
Value: params,
|
||||||
|
KeyNode: ln,
|
||||||
|
ValueNode: vn,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,6 +144,10 @@ func (p *PathItem) Build(root *yaml.Node, idx *index.SpecIndex) error {
|
|||||||
skip = true
|
skip = true
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if strings.HasPrefix(strings.ToLower(pathNode.Value), "parameters") {
|
||||||
|
skip = true
|
||||||
|
continue
|
||||||
|
}
|
||||||
if skip {
|
if skip {
|
||||||
skip = false
|
skip = false
|
||||||
continue
|
continue
|
||||||
@@ -130,9 +157,42 @@ func (p *PathItem) Build(root *yaml.Node, idx *index.SpecIndex) error {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// the only thing we now care about is handling operations, filter out anything that's not a verb.
|
||||||
|
switch currentNode.Value {
|
||||||
|
case GetLabel:
|
||||||
|
break
|
||||||
|
case PostLabel:
|
||||||
|
break
|
||||||
|
case PutLabel:
|
||||||
|
break
|
||||||
|
case PatchLabel:
|
||||||
|
break
|
||||||
|
case DeleteLabel:
|
||||||
|
break
|
||||||
|
case HeadLabel:
|
||||||
|
break
|
||||||
|
case OptionsLabel:
|
||||||
|
break
|
||||||
|
case TraceLabel:
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
continue // ignore everything else.
|
||||||
|
}
|
||||||
|
|
||||||
var op Operation
|
var op Operation
|
||||||
|
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
|
|
||||||
|
if ok, _, _ := utils.IsNodeRefValue(pathNode); ok {
|
||||||
|
r := low.LocateRefNode(pathNode, idx)
|
||||||
|
if r != nil {
|
||||||
|
pathNode = r
|
||||||
|
} else {
|
||||||
|
return fmt.Errorf("path item build failed: cannot find reference: %s at line %d, col %d",
|
||||||
|
pathNode.Content[1].Value, pathNode.Content[1].Line, pathNode.Content[1].Column)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
go low.BuildModelAsync(pathNode, &op, &wg, &errors)
|
go low.BuildModelAsync(pathNode, &op, &wg, &errors)
|
||||||
|
|
||||||
opRef := low.NodeReference[*Operation]{
|
opRef := low.NodeReference[*Operation]{
|
||||||
@@ -163,10 +223,6 @@ func (p *PathItem) Build(root *yaml.Node, idx *index.SpecIndex) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(ops) > 0 {
|
|
||||||
//wg.Wait()
|
|
||||||
}
|
|
||||||
|
|
||||||
//all operations have been superficially built,
|
//all operations have been superficially built,
|
||||||
//now we need to build out the operation, we will do this asynchronously for speed.
|
//now we need to build out the operation, we will do this asynchronously for speed.
|
||||||
opBuildChan := make(chan bool)
|
opBuildChan := make(chan bool)
|
||||||
@@ -215,5 +271,10 @@ allDone:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// make sure we don't exit before the path is finished building.
|
||||||
|
if len(ops) > 0 {
|
||||||
|
wg.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
338
datamodel/low/3.0/path_test.go
Normal file
338
datamodel/low/3.0/path_test.go
Normal file
@@ -0,0 +1,338 @@
|
|||||||
|
// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package v3
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/pb33f/libopenapi/datamodel/low"
|
||||||
|
"github.com/pb33f/libopenapi/index"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestPaths_Build(t *testing.T) {
|
||||||
|
|
||||||
|
yml := `"/some/path":
|
||||||
|
get:
|
||||||
|
description: get method
|
||||||
|
post:
|
||||||
|
description: post method
|
||||||
|
put:
|
||||||
|
description: put method
|
||||||
|
delete:
|
||||||
|
description: delete method
|
||||||
|
options:
|
||||||
|
description: options method
|
||||||
|
patch:
|
||||||
|
description: patch method
|
||||||
|
head:
|
||||||
|
description: head method
|
||||||
|
trace:
|
||||||
|
description: trace method
|
||||||
|
servers:
|
||||||
|
url: https://pb33f.io
|
||||||
|
parameters:
|
||||||
|
- name: hello
|
||||||
|
x-cake: yummy
|
||||||
|
x-milk: cold`
|
||||||
|
|
||||||
|
var idxNode yaml.Node
|
||||||
|
_ = yaml.Unmarshal([]byte(yml), &idxNode)
|
||||||
|
idx := index.NewSpecIndex(&idxNode)
|
||||||
|
|
||||||
|
var n Paths
|
||||||
|
err := low.BuildModel(&idxNode, &n)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
err = n.Build(idxNode.Content[0], idx)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
path := n.FindPath("/some/path").Value
|
||||||
|
assert.NotNil(t, path)
|
||||||
|
assert.Equal(t, "get method", path.Get.Value.Description.Value)
|
||||||
|
assert.Equal(t, "yummy", path.FindExtension("x-cake").Value)
|
||||||
|
assert.Equal(t, "post method", path.Post.Value.Description.Value)
|
||||||
|
assert.Equal(t, "put method", path.Put.Value.Description.Value)
|
||||||
|
assert.Equal(t, "patch method", path.Patch.Value.Description.Value)
|
||||||
|
assert.Equal(t, "delete method", path.Delete.Value.Description.Value)
|
||||||
|
assert.Equal(t, "head method", path.Head.Value.Description.Value)
|
||||||
|
assert.Equal(t, "trace method", path.Trace.Value.Description.Value)
|
||||||
|
assert.Len(t, path.Parameters.Value, 1)
|
||||||
|
assert.Equal(t, "cold", n.FindExtension("x-milk").Value)
|
||||||
|
assert.Equal(t, "hello", path.Parameters.Value[0].Value.Name.Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPaths_Build_Fail(t *testing.T) {
|
||||||
|
|
||||||
|
yml := `"/some/path":
|
||||||
|
$ref: $bork`
|
||||||
|
|
||||||
|
var idxNode yaml.Node
|
||||||
|
_ = yaml.Unmarshal([]byte(yml), &idxNode)
|
||||||
|
idx := index.NewSpecIndex(&idxNode)
|
||||||
|
|
||||||
|
var n Paths
|
||||||
|
err := low.BuildModel(&idxNode, &n)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
err = n.Build(idxNode.Content[0], idx)
|
||||||
|
assert.Error(t, err)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPaths_Build_FailRef(t *testing.T) {
|
||||||
|
|
||||||
|
// this is kinda nuts, and, it's completely illegal, but you never know!
|
||||||
|
yml := `"/some/path":
|
||||||
|
description: this is some path
|
||||||
|
get:
|
||||||
|
description: bloody dog ate my biscuit.
|
||||||
|
post:
|
||||||
|
description: post method
|
||||||
|
"/another/path":
|
||||||
|
$ref: '#/~1some~1path'`
|
||||||
|
|
||||||
|
var idxNode yaml.Node
|
||||||
|
_ = yaml.Unmarshal([]byte(yml), &idxNode)
|
||||||
|
idx := index.NewSpecIndex(&idxNode)
|
||||||
|
|
||||||
|
var n Paths
|
||||||
|
err := low.BuildModel(idxNode.Content[0], &n)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
err = n.Build(idxNode.Content[0], idx)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
somePath := n.FindPath("/some/path").Value
|
||||||
|
anotherPath := n.FindPath("/another/path").Value
|
||||||
|
badPath := n.FindPath("/does/not/exist")
|
||||||
|
assert.NotNil(t, somePath)
|
||||||
|
assert.NotNil(t, anotherPath)
|
||||||
|
assert.Nil(t, badPath)
|
||||||
|
assert.Equal(t, "this is some path", somePath.Description.Value)
|
||||||
|
assert.Equal(t, "bloody dog ate my biscuit.", somePath.Get.Value.Description.Value)
|
||||||
|
assert.Equal(t, "post method", somePath.Post.Value.Description.Value)
|
||||||
|
assert.Equal(t, "bloody dog ate my biscuit.", anotherPath.Get.Value.Description.Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPaths_Build_FailRefDeadEnd(t *testing.T) {
|
||||||
|
|
||||||
|
// this is nuts.
|
||||||
|
yml := `"/no/path":
|
||||||
|
get:
|
||||||
|
$ref: '#/nowhere'
|
||||||
|
"/some/path":
|
||||||
|
get:
|
||||||
|
$ref: '#/~1some~1path/get'
|
||||||
|
"/another/path":
|
||||||
|
$ref: '#/~1some~1path'`
|
||||||
|
|
||||||
|
var idxNode yaml.Node
|
||||||
|
_ = yaml.Unmarshal([]byte(yml), &idxNode)
|
||||||
|
idx := index.NewSpecIndex(&idxNode)
|
||||||
|
|
||||||
|
var n Paths
|
||||||
|
err := low.BuildModel(idxNode.Content[0], &n)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
err = n.Build(idxNode.Content[0], idx)
|
||||||
|
assert.Error(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPaths_Build_SuccessRef(t *testing.T) {
|
||||||
|
|
||||||
|
// this is kinda nuts, it's also not illegal, however the mechanics still need to work.
|
||||||
|
yml := `"/some/path":
|
||||||
|
description: this is some path
|
||||||
|
get:
|
||||||
|
$ref: '#/~1another~1path/get'
|
||||||
|
post:
|
||||||
|
description: post method
|
||||||
|
"/another/path":
|
||||||
|
description: this is another path of some kind.
|
||||||
|
get:
|
||||||
|
description: get method from /another/path`
|
||||||
|
|
||||||
|
var idxNode yaml.Node
|
||||||
|
_ = yaml.Unmarshal([]byte(yml), &idxNode)
|
||||||
|
idx := index.NewSpecIndex(&idxNode)
|
||||||
|
|
||||||
|
var n Paths
|
||||||
|
err := low.BuildModel(idxNode.Content[0], &n)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
err = n.Build(idxNode.Content[0], idx)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
somePath := n.FindPath("/some/path").Value
|
||||||
|
anotherPath := n.FindPath("/another/path").Value
|
||||||
|
badPath := n.FindPath("/does/not/exist")
|
||||||
|
assert.NotNil(t, somePath)
|
||||||
|
assert.NotNil(t, anotherPath)
|
||||||
|
assert.Nil(t, badPath)
|
||||||
|
assert.Equal(t, "this is some path", somePath.Description.Value)
|
||||||
|
assert.Equal(t, "get method from /another/path", somePath.Get.Value.Description.Value)
|
||||||
|
assert.Equal(t, "post method", somePath.Post.Value.Description.Value)
|
||||||
|
assert.Equal(t, "get method from /another/path", anotherPath.Get.Value.Description.Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPaths_Build_BadParams(t *testing.T) {
|
||||||
|
|
||||||
|
yml := `"/some/path":
|
||||||
|
parameters:
|
||||||
|
this: shouldFail`
|
||||||
|
|
||||||
|
var idxNode yaml.Node
|
||||||
|
_ = yaml.Unmarshal([]byte(yml), &idxNode)
|
||||||
|
idx := index.NewSpecIndex(&idxNode)
|
||||||
|
|
||||||
|
var n Paths
|
||||||
|
err := low.BuildModel(idxNode.Content[0], &n)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
err = n.Build(idxNode.Content[0], idx)
|
||||||
|
assert.Error(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPaths_Build_BadRef(t *testing.T) {
|
||||||
|
|
||||||
|
// this is kinda nuts, it's also not illegal, however the mechanics still need to work.
|
||||||
|
yml := `"/some/path":
|
||||||
|
description: this is some path
|
||||||
|
get:
|
||||||
|
$ref: '#/no-where'
|
||||||
|
post:
|
||||||
|
description: post method
|
||||||
|
"/another/path":
|
||||||
|
description: this is another path of some kind.
|
||||||
|
get:
|
||||||
|
description: get method from /another/path`
|
||||||
|
|
||||||
|
var idxNode yaml.Node
|
||||||
|
_ = yaml.Unmarshal([]byte(yml), &idxNode)
|
||||||
|
idx := index.NewSpecIndex(&idxNode)
|
||||||
|
|
||||||
|
var n Paths
|
||||||
|
err := low.BuildModel(idxNode.Content[0], &n)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
err = n.Build(idxNode.Content[0], idx)
|
||||||
|
assert.Error(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPathItem_Build_GoodRef(t *testing.T) {
|
||||||
|
|
||||||
|
// this is kinda nuts, it's also not illegal, however the mechanics still need to work.
|
||||||
|
yml := `"/some/path":
|
||||||
|
description: this is some path
|
||||||
|
get:
|
||||||
|
$ref: '#/~1another~1path/get'
|
||||||
|
post:
|
||||||
|
description: post method
|
||||||
|
"/another/path":
|
||||||
|
description: this is another path of some kind.
|
||||||
|
get:
|
||||||
|
$ref: '#/~1cakes/get'
|
||||||
|
"/cakes":
|
||||||
|
description: cakes are awesome
|
||||||
|
get:
|
||||||
|
description: get method from /cakes`
|
||||||
|
|
||||||
|
var idxNode yaml.Node
|
||||||
|
_ = yaml.Unmarshal([]byte(yml), &idxNode)
|
||||||
|
idx := index.NewSpecIndex(&idxNode)
|
||||||
|
|
||||||
|
var n Paths
|
||||||
|
err := low.BuildModel(idxNode.Content[0], &n)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
err = n.Build(idxNode.Content[0], idx)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPathItem_Build_BadRef(t *testing.T) {
|
||||||
|
|
||||||
|
// this is kinda nuts, it's also not illegal, however the mechanics still need to work.
|
||||||
|
yml := `"/some/path":
|
||||||
|
description: this is some path
|
||||||
|
get:
|
||||||
|
$ref: '#/~1another~1path/get'
|
||||||
|
post:
|
||||||
|
description: post method
|
||||||
|
"/another/path":
|
||||||
|
description: this is another path of some kind.
|
||||||
|
get:
|
||||||
|
$ref: '#/~1cakes/NotFound'
|
||||||
|
"/cakes":
|
||||||
|
description: cakes are awesome
|
||||||
|
get:
|
||||||
|
description: get method from /cakes`
|
||||||
|
|
||||||
|
var idxNode yaml.Node
|
||||||
|
_ = yaml.Unmarshal([]byte(yml), &idxNode)
|
||||||
|
idx := index.NewSpecIndex(&idxNode)
|
||||||
|
|
||||||
|
var n Paths
|
||||||
|
err := low.BuildModel(idxNode.Content[0], &n)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
err = n.Build(idxNode.Content[0], idx)
|
||||||
|
assert.Error(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPathNoOps(t *testing.T) {
|
||||||
|
|
||||||
|
// this is kinda nuts, it's also not illegal, however the mechanics still need to work.
|
||||||
|
yml := `"/some/path":
|
||||||
|
"/cakes":`
|
||||||
|
|
||||||
|
var idxNode yaml.Node
|
||||||
|
_ = yaml.Unmarshal([]byte(yml), &idxNode)
|
||||||
|
idx := index.NewSpecIndex(&idxNode)
|
||||||
|
|
||||||
|
var n Paths
|
||||||
|
err := low.BuildModel(idxNode.Content[0], &n)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
err = n.Build(idxNode.Content[0], idx)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPathItem_Build_Using_Ref(t *testing.T) {
|
||||||
|
|
||||||
|
// first we need an index.
|
||||||
|
doc := `paths:
|
||||||
|
'/something/here':
|
||||||
|
post:
|
||||||
|
description: there is something here!`
|
||||||
|
|
||||||
|
var idxNode yaml.Node
|
||||||
|
mErr := yaml.Unmarshal([]byte(doc), &idxNode)
|
||||||
|
assert.NoError(t, mErr)
|
||||||
|
idx := index.NewSpecIndex(&idxNode)
|
||||||
|
|
||||||
|
yml := `"/some/path":
|
||||||
|
description: this is some path
|
||||||
|
get:
|
||||||
|
$ref: '#/paths/~1something~1here/post'`
|
||||||
|
|
||||||
|
var rootNode yaml.Node
|
||||||
|
mErr = yaml.Unmarshal([]byte(yml), &rootNode)
|
||||||
|
assert.NoError(t, mErr)
|
||||||
|
|
||||||
|
var n Paths
|
||||||
|
err := low.BuildModel(rootNode.Content[0], &n)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
err = n.Build(rootNode.Content[0], idx)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
somePath := n.FindPath("/a/path")
|
||||||
|
assert.Nil(t, somePath)
|
||||||
|
|
||||||
|
somePath = n.FindPath("/some/path")
|
||||||
|
assert.NotNil(t, somePath.Value)
|
||||||
|
assert.Equal(t, "this is some path", somePath.Value.Description.Value)
|
||||||
|
assert.Equal(t, "there is something here!", somePath.Value.Get.Value.Description.Value)
|
||||||
|
}
|
||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
package v3
|
package v3
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
package v3
|
package v3
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -26,7 +29,7 @@ type SecurityScheme struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type SecurityRequirement struct {
|
type SecurityRequirement struct {
|
||||||
Value []low.ValueReference[map[low.KeyReference[string]][]low.ValueReference[string]]
|
ValueRequirements []low.ValueReference[map[low.KeyReference[string]][]low.ValueReference[string]]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ss *SecurityScheme) Build(root *yaml.Node, idx *index.SpecIndex) error {
|
func (ss *SecurityScheme) Build(root *yaml.Node, idx *index.SpecIndex) error {
|
||||||
@@ -44,7 +47,7 @@ func (ss *SecurityScheme) Build(root *yaml.Node, idx *index.SpecIndex) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (sr *SecurityRequirement) FindRequirement(name string) []low.ValueReference[string] {
|
func (sr *SecurityRequirement) FindRequirement(name string) []low.ValueReference[string] {
|
||||||
for _, r := range sr.Value {
|
for _, r := range sr.ValueRequirements {
|
||||||
for k, v := range r.Value {
|
for k, v := range r.Value {
|
||||||
if k.Value == name {
|
if k.Value == name {
|
||||||
return v
|
return v
|
||||||
@@ -89,7 +92,7 @@ func (sr *SecurityRequirement) Build(root *yaml.Node, idx *index.SpecIndex) erro
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sr.Value = requirements
|
sr.ValueRequirements = requirements
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
package v3
|
package v3
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
package low
|
package low
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -49,8 +52,9 @@ func LocateRefNode(root *yaml.Node, idx *index.SpecIndex) *yaml.Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// cant be found? last resort is to try a path lookup
|
// cant be found? last resort is to try a path lookup
|
||||||
cleaned := strings.ReplaceAll(rv, "~1", "/")
|
cleaned := strings.ReplaceAll(rv, "#/paths/", "")
|
||||||
cleaned = strings.ReplaceAll(cleaned, "#/paths/", "")
|
cleaned = strings.ReplaceAll(cleaned, "/", ".")
|
||||||
|
cleaned = strings.ReplaceAll(cleaned, "~1", "/")
|
||||||
path, err := yamlpath.NewPath(fmt.Sprintf("$.paths.%s", cleaned))
|
path, err := yamlpath.NewPath(fmt.Sprintf("$.paths.%s", cleaned))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
nodes, fErr := path.Find(idx.GetRootNode())
|
nodes, fErr := path.Find(idx.GetRootNode())
|
||||||
@@ -151,6 +155,9 @@ func ExtractArray[T Buildable[N], N any](label string, root *yaml.Node, idx *ind
|
|||||||
}
|
}
|
||||||
var items []ValueReference[T]
|
var items []ValueReference[T]
|
||||||
if vn != nil && ln != nil {
|
if vn != nil && ln != nil {
|
||||||
|
if !utils.IsNodeArray(vn) {
|
||||||
|
return []ValueReference[T]{}, nil, nil, fmt.Errorf("array build failed, input is not an array, line %d, column %d", vn.Line, vn.Column)
|
||||||
|
}
|
||||||
for _, node := range vn.Content {
|
for _, node := range vn.Content {
|
||||||
if rf, _, _ := utils.IsNodeRefValue(node); rf {
|
if rf, _, _ := utils.IsNodeRefValue(node); rf {
|
||||||
ref := LocateRefNode(node, idx)
|
ref := LocateRefNode(node, idx)
|
||||||
@@ -179,16 +186,39 @@ func ExtractArray[T Buildable[N], N any](label string, root *yaml.Node, idx *ind
|
|||||||
return items, ln, vn, nil
|
return items, ln, vn, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ExtractExample(expNode, expLabel *yaml.Node) NodeReference[any] {
|
||||||
|
ref := NodeReference[any]{Value: expNode.Value, KeyNode: expLabel, ValueNode: expNode}
|
||||||
|
if utils.IsNodeMap(expNode) {
|
||||||
|
var decoded map[string]interface{}
|
||||||
|
_ = expNode.Decode(&decoded)
|
||||||
|
ref.Value = decoded
|
||||||
|
}
|
||||||
|
if utils.IsNodeArray(expNode) {
|
||||||
|
var decoded []interface{}
|
||||||
|
_ = expNode.Decode(&decoded)
|
||||||
|
ref.Value = decoded
|
||||||
|
}
|
||||||
|
return ref
|
||||||
|
}
|
||||||
|
|
||||||
func ExtractMapFlatNoLookup[PT Buildable[N], N any](root *yaml.Node, idx *index.SpecIndex) (map[KeyReference[string]]ValueReference[PT], error) {
|
func ExtractMapFlatNoLookup[PT Buildable[N], N any](root *yaml.Node, idx *index.SpecIndex) (map[KeyReference[string]]ValueReference[PT], error) {
|
||||||
valueMap := make(map[KeyReference[string]]ValueReference[PT])
|
valueMap := make(map[KeyReference[string]]ValueReference[PT])
|
||||||
if utils.IsNodeMap(root) {
|
if utils.IsNodeMap(root) {
|
||||||
var currentKey *yaml.Node
|
var currentKey *yaml.Node
|
||||||
|
skip := false
|
||||||
for i, node := range root.Content {
|
for i, node := range root.Content {
|
||||||
|
if strings.HasPrefix(strings.ToLower(node.Value), "x-") {
|
||||||
|
skip = true
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if skip {
|
||||||
|
skip = false
|
||||||
|
continue
|
||||||
|
}
|
||||||
if i%2 == 0 {
|
if i%2 == 0 {
|
||||||
currentKey = node
|
currentKey = node
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// if value is a reference, we have to look it up in the index!
|
// if value is a reference, we have to look it up in the index!
|
||||||
if h, _, _ := utils.IsNodeRefValue(node); h {
|
if h, _, _ := utils.IsNodeRefValue(node); h {
|
||||||
ref := LocateRefNode(node, idx)
|
ref := LocateRefNode(node, idx)
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
package low
|
package low
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -23,6 +26,14 @@ func BuildModel(node *yaml.Node, model interface{}) error {
|
|||||||
|
|
||||||
fName := v.Type().Field(i).Name
|
fName := v.Type().Field(i).Name
|
||||||
|
|
||||||
|
if fName == "Extensions" {
|
||||||
|
continue // internal construct
|
||||||
|
}
|
||||||
|
|
||||||
|
if fName == "PathItems" {
|
||||||
|
continue // internal construct
|
||||||
|
}
|
||||||
|
|
||||||
// we need to find a matching field in the YAML, the cases may be off, so take no chances.
|
// we need to find a matching field in the YAML, the cases may be off, so take no chances.
|
||||||
cases := []utils.Case{utils.PascalCase, utils.CamelCase, utils.ScreamingSnakeCase,
|
cases := []utils.Case{utils.PascalCase, utils.CamelCase, utils.ScreamingSnakeCase,
|
||||||
utils.SnakeCase, utils.KebabCase, utils.RegularCase}
|
utils.SnakeCase, utils.KebabCase, utils.RegularCase}
|
||||||
|
|||||||
@@ -1722,7 +1722,7 @@ func (index *SpecIndex) performExternalLookup(uri []string, componentId string,
|
|||||||
func (index *SpecIndex) FindComponentInRoot(componentId string) *Reference {
|
func (index *SpecIndex) FindComponentInRoot(componentId string) *Reference {
|
||||||
|
|
||||||
name, friendlySearch := utils.ConvertComponentIdIntoFriendlyPathSearch(componentId)
|
name, friendlySearch := utils.ConvertComponentIdIntoFriendlyPathSearch(componentId)
|
||||||
|
friendlySearch = strings.ReplaceAll(friendlySearch, "~1", "/")
|
||||||
path, _ := yamlpath.NewPath(friendlySearch)
|
path, _ := yamlpath.NewPath(friendlySearch)
|
||||||
res, _ := path.Find(index.root)
|
res, _ := path.Find(index.root)
|
||||||
|
|
||||||
|
|||||||
@@ -131,6 +131,7 @@ func TestCreateDocument_Tags(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestCreateDocument_Paths(t *testing.T) {
|
func TestCreateDocument_Paths(t *testing.T) {
|
||||||
|
doc := doc
|
||||||
assert.Len(t, doc.Paths.Value.PathItems, 6)
|
assert.Len(t, doc.Paths.Value.PathItems, 6)
|
||||||
burgerId := doc.Paths.Value.FindPath("/burgers/{burgerId}")
|
burgerId := doc.Paths.Value.FindPath("/burgers/{burgerId}")
|
||||||
assert.NotNil(t, burgerId)
|
assert.NotNil(t, burgerId)
|
||||||
@@ -245,7 +246,7 @@ func TestCreateDocument_Paths(t *testing.T) {
|
|||||||
// check security requirements
|
// check security requirements
|
||||||
security := burgersPost.Security.Value
|
security := burgersPost.Security.Value
|
||||||
assert.NotNil(t, security)
|
assert.NotNil(t, security)
|
||||||
assert.Len(t, security.Value, 1)
|
assert.Len(t, security.ValueRequirements, 1)
|
||||||
|
|
||||||
oAuthReq := security.FindRequirement("OAuthScheme")
|
oAuthReq := security.FindRequirement("OAuthScheme")
|
||||||
assert.Len(t, oAuthReq, 2)
|
assert.Len(t, oAuthReq, 2)
|
||||||
@@ -372,7 +373,7 @@ func TestCreateDocument_Components_Links(t *testing.T) {
|
|||||||
func TestCreateDocument_Doc_Security(t *testing.T) {
|
func TestCreateDocument_Doc_Security(t *testing.T) {
|
||||||
security := doc.Security.Value
|
security := doc.Security.Value
|
||||||
assert.NotNil(t, security)
|
assert.NotNil(t, security)
|
||||||
assert.Len(t, security.Value, 1)
|
assert.Len(t, security.ValueRequirements, 1)
|
||||||
|
|
||||||
oAuth := security.FindRequirement("OAuthScheme")
|
oAuth := security.FindRequirement("OAuthScheme")
|
||||||
assert.Len(t, oAuth, 2)
|
assert.Len(t, oAuth, 2)
|
||||||
|
|||||||
Reference in New Issue
Block a user