From 1d7784047064864fc8b1b88312f6d39b7abd85e8 Mon Sep 17 00:00:00 2001 From: Dave Shanley Date: Sun, 14 Aug 2022 05:29:37 -0400 Subject: [PATCH] Test coverage bump --- datamodel/low/3.0/header.go | 24 +++- datamodel/low/3.0/header_test.go | 172 ++++++++++++++++++++++++++ datamodel/low/3.0/schema.go | 2 + datamodel/low/extraction_functions.go | 23 ++++ 4 files changed, 220 insertions(+), 1 deletion(-) create mode 100644 datamodel/low/3.0/header_test.go diff --git a/datamodel/low/3.0/header.go b/datamodel/low/3.0/header.go index aaa598a..8e743d3 100644 --- a/datamodel/low/3.0/header.go +++ b/datamodel/low/3.0/header.go @@ -25,6 +25,28 @@ type Header struct { Extensions map[low.KeyReference[string]]low.ValueReference[any] } +func (h *Header) FindExtension(ext string) *low.ValueReference[any] { + return low.FindItemInMap[any](ext, h.Extensions) +} + +func (h *Header) FindExample(eType string) *low.ValueReference[*Example] { + // there is only one item in here by design, so this can only ever loop once + var k *low.ValueReference[*Example] + for _, v := range h.Examples { + k = low.FindItemInMap[*Example](eType, v) + } + return k +} + +func (h *Header) FindContent(ext string) *low.ValueReference[*MediaType] { + // there is only one item in here by design, so this can only ever loop once + var k *low.ValueReference[*MediaType] + for _, v := range h.Content { + k = low.FindItemInMap[*MediaType](ext, v) + } + return k +} + func (h *Header) Build(root *yaml.Node, idx *index.SpecIndex) error { h.Extensions = low.ExtractExtensions(root) @@ -40,7 +62,7 @@ func (h *Header) Build(root *yaml.Node, idx *index.SpecIndex) error { // handle schema sch, sErr := ExtractSchema(root, idx) if sErr != nil { - return nil + return sErr } if sch != nil { h.Schema = *sch diff --git a/datamodel/low/3.0/header_test.go b/datamodel/low/3.0/header_test.go new file mode 100644 index 0000000..554b97b --- /dev/null +++ b/datamodel/low/3.0/header_test.go @@ -0,0 +1,172 @@ +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 TestHeader_Build(t *testing.T) { + + yml := `description: michelle, meddy and maddy +required: true +deprecated: false +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 Header + 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.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 TestHeader_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 Header + 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 TestHeader_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 Header + err := low.BuildModel(&idxNode, &n) + assert.NoError(t, err) + + err = n.Build(idxNode.Content[0], idx) + assert.Error(t, err) + +} + +func TestHeader_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 Header + err := low.BuildModel(&idxNode, &n) + assert.NoError(t, err) + + err = n.Build(idxNode.Content[0], idx) + assert.Error(t, err) + +} + +func TestHeader_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 Header + err := low.BuildModel(&idxNode, &n) + assert.NoError(t, err) + + err = n.Build(idxNode.Content[0], idx) + assert.Error(t, err) + +} diff --git a/datamodel/low/3.0/schema.go b/datamodel/low/3.0/schema.go index 52edea9..38d2629 100644 --- a/datamodel/low/3.0/schema.go +++ b/datamodel/low/3.0/schema.go @@ -304,6 +304,8 @@ func ExtractSchema(root *yaml.Node, idx *index.SpecIndex) (*low.NodeReference[*S ref := low.LocateRefNode(schNode, idx) if ref != nil { schNode = ref + } else { + return nil, fmt.Errorf("schema build failed: reference cannot be found: %s", root.Content[1].Value) } } } diff --git a/datamodel/low/extraction_functions.go b/datamodel/low/extraction_functions.go index c2d2b7b..03a6014 100644 --- a/datamodel/low/extraction_functions.go +++ b/datamodel/low/extraction_functions.go @@ -304,6 +304,17 @@ func ExtractMap[PT Buildable[N], N any](label string, root *yaml.Node, idx *inde } } else { _, labelNode, valueNode = utils.FindKeyNodeFull(label, root.Content) + if valueNode != nil { + if h, _, _ := utils.IsNodeRefValue(valueNode); h { + ref := LocateRefNode(valueNode, idx) + if ref != nil { + valueNode = ref + } else { + return nil, fmt.Errorf("map build failed: reference cannot be found: %s", + root.Content[1].Value) + } + } + } } if valueNode != nil { @@ -317,6 +328,18 @@ func ExtractMap[PT Buildable[N], N any](label string, root *yaml.Node, idx *inde if strings.HasPrefix(strings.ToLower(currentLabelNode.Value), "x-") { continue // yo, don't pay any attention to extensions, not here anyway. } + + // check our valueNode isn't a reference still. + if h, _, _ := utils.IsNodeRefValue(en); h { + ref := LocateRefNode(en, idx) + if ref != nil { + en = ref + } else { + return nil, fmt.Errorf("map build failed: reference cannot be found: %s", + root.Content[1].Value) + } + } + var n PT = new(N) err := BuildModel(en, n) if err != nil {