Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed inconsistent missing_example function #569

Merged
merged 1 commit into from
Oct 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 50 additions & 25 deletions functions/openapi/examples_missing.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,16 @@
package openapi

import (
"context"
"fmt"
"github.com/daveshanley/vacuum/model"
vacuumUtils "github.com/daveshanley/vacuum/utils"
"github.com/pb33f/doctor/model/high/base"
"github.com/pb33f/libopenapi/datamodel/high"
"github.com/pb33f/libopenapi/index"
"gopkg.in/yaml.v3"
"slices"
"strings"
)

// ExamplesMissing will check anything that can have an example, has one.
Expand All @@ -34,6 +39,9 @@ func (em ExamplesMissing) RunRule(_ []*yaml.Node, context model.RuleFunctionCont
return results
}

// create a string buffer for caching seen schemas
var buf strings.Builder

buildResult := func(message, path string, node *yaml.Node, component base.AcceptsRuleResults) model.RuleFunctionResult {
result := model.RuleFunctionResult{
Message: message,
Expand All @@ -58,7 +66,7 @@ func (em ExamplesMissing) RunRule(_ []*yaml.Node, context model.RuleFunctionCont
return false
}

seen := make(map[[32]byte]bool)
seen := make(map[string]bool)

if context.DrDocument.Parameters != nil {
paramClear:
Expand All @@ -77,11 +85,12 @@ func (em ExamplesMissing) RunRule(_ []*yaml.Node, context model.RuleFunctionCont
v := con.Value()
if v.Examples != nil && (p.Examples == nil || p.Examples.Len() >= 0) {
// add to seen elements, so when checking schemas we can mark them as good.
var h [32]byte
copy(h[:], p.GenerateJSONPath())
if _, ok := seen[h]; !ok {
seen[h] = true
buf.WriteString(fmt.Sprintf("%s:%d:%d", p.Value.GoLow().GetIndex().GetSpecAbsolutePath(),
p.Value.GoLow().KeyNode.Line, p.Value.GoLow().KeyNode.Column))
if _, ok := seen[buf.String()]; !ok {
seen[buf.String()] = true
}
buf.Reset()
break paramClear
}
}
Expand All @@ -100,11 +109,12 @@ func (em ExamplesMissing) RunRule(_ []*yaml.Node, context model.RuleFunctionCont
n, p))
} else {
// add to seen elements, so when checking schemas we can mark them as good.
var h [32]byte
copy(h[:], p.GenerateJSONPath())
if _, ok := seen[h]; !ok {
seen[h] = true
buf.WriteString(fmt.Sprintf("%s:%d:%d", p.Value.GoLow().GetIndex().GetSpecAbsolutePath(),
p.Value.GoLow().KeyNode.Line, p.Value.GoLow().KeyNode.Column))
if _, ok := seen[buf.String()]; !ok {
seen[buf.String()] = true
}
buf.Reset()
}
}
}
Expand Down Expand Up @@ -133,12 +143,12 @@ func (em ExamplesMissing) RunRule(_ []*yaml.Node, context model.RuleFunctionCont
h.GenerateJSONPath(),
n, h))
} else {
// add to seen elements, so when checking schemas we can mark them as good.
var hs [32]byte
copy(hs[:], h.GenerateJSONPath())
if _, ok := seen[hs]; !ok {
seen[hs] = true
buf.WriteString(fmt.Sprintf("%s:%d:%d", h.Value.GoLow().GetIndex().GetSpecAbsolutePath(),
h.Value.GoLow().KeyNode.Line, h.Value.GoLow().KeyNode.Column))
if _, ok := seen[buf.String()]; !ok {
seen[buf.String()] = true
}
buf.Reset()
}
}
}
Expand Down Expand Up @@ -170,13 +180,12 @@ func (em ExamplesMissing) RunRule(_ []*yaml.Node, context model.RuleFunctionCont
mt.GenerateJSONPath(),
n, mt))
} else {
// add to seen elements, so when checking schemas we can mark them as good.
//h := mt.Value.GoLow().Hash()
var h [32]byte
copy(h[:], mt.GenerateJSONPath())
if _, ok := seen[h]; !ok {
seen[h] = true
buf.WriteString(fmt.Sprintf("%s:%d:%d", mt.Value.GoLow().GetIndex().GetSpecAbsolutePath(),
mt.Value.GoLow().KeyNode.Line, mt.Value.GoLow().KeyNode.Column))
if _, ok := seen[buf.String()]; !ok {
seen[buf.String()] = true
}
buf.Reset()
}
}
}
Expand All @@ -200,18 +209,34 @@ func (em ExamplesMissing) RunRule(_ []*yaml.Node, context model.RuleFunctionCont
}
}
}
seen = nil
buf.Reset()
return results
}

func extractHash(s *base.Schema) [32]byte {
type contextualPosition interface {
GetIndex() *index.SpecIndex
GetContext() context.Context
GetKeyNode() *yaml.Node
}

func extractHash(s *base.Schema) string {
if s != nil && s.Parent != nil {
if p := s.Parent.(base.Foundational).GetParent(); p != nil {
var arr [32]byte
copy(arr[:], p.GenerateJSONPath())
return arr
// check if p implements HasValue
if hv, ok := p.(base.HasValue); ok {
// check if hv.Value implements GoesLowUntyped
if gl, ko := hv.GetValue().(high.GoesLowUntyped); ko {
// check if gl.GoesLowUntyped() implements contextualPosition
if cp, kk := gl.GoLowUntyped().(contextualPosition); kk {
return fmt.Sprintf("%s:%d:%d", cp.GetIndex().GetSpecAbsolutePath(),
cp.GetKeyNode().Line, cp.GetKeyNode().Column)
}
}
}
}
}
return [32]byte{}
return ""
}

func isSchemaBoolean(schema *base.Schema) bool {
Expand Down
2 changes: 1 addition & 1 deletion functions/openapi/examples_missing_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ components:

assert.Len(t, res, 3)
assert.Equal(t, "schema is missing `examples` or `example`", res[0].Message)
assert.Contains(t, res[1].Path, "$.components.schemas['Pizza'].properties")
assert.Contains(t, res[1].Path, "$.components.schemas['Pizza']")
}

func TestExamplesMissing_Header(t *testing.T) {
Expand Down
2 changes: 1 addition & 1 deletion functions/openapi/examples_schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ func (es ExamplesSchema) RunRule(_ []*yaml.Node, context model.RuleFunctionConte
for _, r := range validationErrors {
for _, err := range r.SchemaValidationErrors {
result := buildResult(vacuumUtils.SuppliedOrDefault(context.Rule.Message, err.Reason),
path, keyNode, node, obj)
path, keyNode, node, s)

banned := false
for g := range bannedErrors {
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ require (
github.com/json-iterator/go v1.1.12
github.com/mitchellh/mapstructure v1.5.0
github.com/pb33f/doctor v0.0.14
github.com/pb33f/libopenapi v0.18.3
github.com/pb33f/libopenapi v0.18.4
github.com/pb33f/libopenapi-validator v0.2.0
github.com/pterm/pterm v0.12.79
github.com/santhosh-tekuri/jsonschema/v6 v6.0.1
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -160,8 +160,8 @@ github.com/onsi/gomega v1.19.0 h1:4ieX6qQjPP/BfC3mpsAtIGGlxTWPeA3Inl/7DtXw1tw=
github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro=
github.com/pb33f/doctor v0.0.14 h1:Yei7f6Ksuc9RBjN3umiCEI8zN7ti3s5aveTT3sLi8Ts=
github.com/pb33f/doctor v0.0.14/go.mod h1:1afDRJqurrftgMfRDbf1jWPoOyvdAsaK8+GHD8MiTLI=
github.com/pb33f/libopenapi v0.18.3 h1:j4lm8xMM/GYSj2M8S7qNwZ//rOtEK5ACEiuNC7mTJzE=
github.com/pb33f/libopenapi v0.18.3/go.mod h1:9ap4lXBHgxGyFwxtOfa+B1C3IQ0rvnqteqjJvJ11oiQ=
github.com/pb33f/libopenapi v0.18.4 h1:b39Spb8CY0jzormHkB2+U/UtaKegicHHJRY7c9PlTDQ=
github.com/pb33f/libopenapi v0.18.4/go.mod h1:9ap4lXBHgxGyFwxtOfa+B1C3IQ0rvnqteqjJvJ11oiQ=
github.com/pb33f/libopenapi-validator v0.2.0 h1:bixMgyHXRenN60L8927GtsWM8AE/p3fGvQdn6ZkgNHM=
github.com/pb33f/libopenapi-validator v0.2.0/go.mod h1:DpluvEfTfDwfqTN2sgvTH14dPbzKDtE/vYQgcx3iNMs=
github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
Expand Down
Loading