Skip to content

Commit

Permalink
truthy and defined functions were not returning the located object pa…
Browse files Browse the repository at this point in the history
…th for the infraction because it was looking for a node that did not exist.
  • Loading branch information
Calvin Lobo authored and daveshanley committed Jan 9, 2025
1 parent 10bbe26 commit 041c2f0
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 29 deletions.
26 changes: 15 additions & 11 deletions functions/core/defined.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,23 +51,27 @@ func (d Defined) RunRule(nodes []*yaml.Node, context model.RuleFunctionContext)
}

for _, node := range nodes {
fieldNode, fieldNodeValue := utils.FindKeyNode(context.RuleAction.Field, node.Content)
fieldNode, _ := utils.FindKeyNode(context.RuleAction.Field, node.Content)
var locatedObjects []base.Foundational
var allPaths []string
var err error
locatedPath := pathValue
if context.DrDocument != nil {
locatedObjects, err = context.DrDocument.LocateModelsByKeyAndValue(fieldNode, fieldNodeValue)
if err == nil && locatedObjects != nil {
for x, obj := range locatedObjects {
if x == 0 {
locatedPath = obj.GenerateJSONPath()

if fieldNode == nil {

locatedPath := pathValue
if context.DrDocument != nil {
// Since the field is undefined, locate the parent node to be the locatedPath of infraction
locatedObjects, err = context.DrDocument.LocateModel(node)
if err == nil && locatedObjects != nil {
for x, obj := range locatedObjects {
if x == 0 {
locatedPath = obj.GenerateJSONPath()
}
allPaths = append(allPaths, obj.GenerateJSONPath())
}
allPaths = append(allPaths, obj.GenerateJSONPath())
}
}
}
if fieldNode == nil {

result := model.RuleFunctionResult{
Message: vacuumUtils.SuppliedOrDefault(message,
fmt.Sprintf("%s: `%s` must be defined", ruleMessage, context.RuleAction.Field)),
Expand Down
42 changes: 35 additions & 7 deletions functions/core/defined_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,24 +45,52 @@ func TestDefined_RunRule_Success(t *testing.T) {

func TestDefined_RunRule_Fail(t *testing.T) {

sampleYaml := `openapi: 3.0.0
pizza:
noCake: "noFun"`

path := "$.pizza"
sampleYaml :=
`openapi: 3.0.0
paths:
/v1/cake:
get:
responses:
'200':
content:
application/xml:
schema:
type: object
post:
responses:
'200':
content:
application/json:
schema:
type: object
`

path := "$.paths.*.*.responses[*].content"

nodes, _ := utils.FindNodes([]byte(sampleYaml), path)
assert.Len(t, nodes, 1)
assert.Len(t, nodes, 2)

rule := buildCoreTestRule(path, model.SeverityError, "defined", "cake", nil)
document, err := libopenapi.NewDocument([]byte(sampleYaml))
if err != nil {
panic(fmt.Sprintf("cannot create new document: %e", err))
}

m, _ := document.BuildV3Model()

drDocument := drModel.NewDrDocument(m)

rule := buildCoreTestRule(path, model.SeverityError, "defined", "application/json", nil)
ctx := buildCoreTestContext(model.CastToRuleAction(rule.Then), nil)
ctx.Given = path
ctx.Rule = &rule
ctx.Document = document
ctx.DrDocument = drDocument

def := Defined{}
res := def.RunRule(nodes, ctx)

assert.Len(t, res, 1)
assert.Equal(t, res[0].Path, "$.paths['/v1/cake'].get.responses['200'].content['application/xml']")
}

func TestDefined_RunRule_DrNodeLookup(t *testing.T) {
Expand Down
11 changes: 8 additions & 3 deletions functions/core/truthy.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,13 +92,18 @@ func (t *Truthy) RunRule(nodes []*yaml.Node, context model.RuleFunctionContext)
var err error
locatedPath := pathValue
if context.DrDocument != nil {
locatedObjects, err = context.DrDocument.LocateModelsByKeyAndValue(fieldNode, fieldNodeValue)
if fieldNode == nil {
locatedObjects, err = context.DrDocument.LocateModel(node)
} else {
locatedObjects, err = context.DrDocument.LocateModelsByKeyAndValue(fieldNode, fieldNodeValue)
}
if err == nil && locatedObjects != nil {
for x, obj := range locatedObjects {
p := fmt.Sprintf("%s.%s", obj.GenerateJSONPath(), context.RuleAction.Field)
if x == 0 {
locatedPath = obj.GenerateJSONPath()
locatedPath = p
}
allPaths = append(allPaths, obj.GenerateJSONPath())
allPaths = append(allPaths, p)
}
}
}
Expand Down
43 changes: 37 additions & 6 deletions functions/core/truthy_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package core

import (
"fmt"
"github.com/daveshanley/vacuum/model"
drModel "github.com/pb33f/doctor/model"
"github.com/pb33f/libopenapi"
"github.com/pb33f/libopenapi/utils"
"github.com/stretchr/testify/assert"
"testing"
Expand Down Expand Up @@ -105,22 +108,50 @@ tags:

func TestTruthy_RunRule_NoContent(t *testing.T) {

sampleYaml := `info: test`

path := "$.info"
sampleYaml :=
`openapi: 3.0.0
paths:
/v1/cake:
get:
parameters:
- in: query
name: type
required: true
- in: query
name: flavor
required: false
- in: query
name: weight
`

path := "$.paths.*.*.parameters[*]"

nodes, _ := utils.FindNodes([]byte(sampleYaml), path)
assert.Len(t, nodes, 1)
assert.Len(t, nodes, 3)

document, err := libopenapi.NewDocument([]byte(sampleYaml))
if err != nil {
panic(fmt.Sprintf("cannot create new document: %e", err))
}

m, _ := document.BuildV3Model()

rule := buildCoreTestRule(path, model.SeverityError, "truthy", "info", nil)
drDocument := drModel.NewDrDocument(m)

rule := buildCoreTestRule(path, model.SeverityError, "truthy", "required", nil)
ctx := buildCoreTestContext(model.CastToRuleAction(rule.Then), nil)
ctx.Given = path
ctx.Rule = &rule
ctx.Document = document
ctx.DrDocument = drDocument

tru := Truthy{}
res := tru.RunRule(nodes, ctx)

assert.Len(t, res, 1)
// Two of the three nodes should match because one has a truthy value
assert.Len(t, res, 2)
assert.Equal(t, res[0].Path, "$.paths['/v1/cake'].get.parameters[1].required")
assert.Equal(t, res[1].Path, "$.paths['/v1/cake'].get.parameters[2].required")
}

func TestTruthy_RunRule_ArrayTest(t *testing.T) {
Expand Down
33 changes: 31 additions & 2 deletions functions/core/undefined_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package core

import (
"fmt"
"github.com/daveshanley/vacuum/model"
drModel "github.com/pb33f/doctor/model"
"github.com/pb33f/libopenapi"
"github.com/pb33f/libopenapi/utils"
"github.com/stretchr/testify/assert"
"testing"
Expand All @@ -20,18 +23,31 @@ func TestUndefined_RunRule(t *testing.T) {

func TestUndefined_RunRule_Success(t *testing.T) {

sampleYaml := `pizza:
sampleYaml :=
`openapi: 3.0.0
pizza:
cake: "fridge"`

path := "$.pizza"

document, err := libopenapi.NewDocument([]byte(sampleYaml))
if err != nil {
panic(fmt.Sprintf("cannot create new document: %e", err))
}

m, _ := document.BuildV3Model()

drDocument := drModel.NewDrDocument(m)

nodes, _ := utils.FindNodes([]byte(sampleYaml), path)
assert.Len(t, nodes, 1)

rule := buildCoreTestRule(path, model.SeverityError, "undefined", "cake", nil)
ctx := buildCoreTestContext(model.CastToRuleAction(rule.Then), nil)
ctx.Given = path
ctx.Rule = &rule
ctx.Document = document
ctx.DrDocument = drDocument

def := Undefined{}
res := def.RunRule(nodes, ctx)
Expand All @@ -41,18 +57,31 @@ func TestUndefined_RunRule_Success(t *testing.T) {

func TestUndefined_RunRule_Fail(t *testing.T) {

sampleYaml := `pizza:
sampleYaml :=
`openapi: 3.0.0
pizza:
noCake: "noFun"`

path := "$.pizza"

document, err := libopenapi.NewDocument([]byte(sampleYaml))
if err != nil {
panic(fmt.Sprintf("cannot create new document: %e", err))
}

m, _ := document.BuildV3Model()

drDocument := drModel.NewDrDocument(m)

nodes, _ := utils.FindNodes([]byte(sampleYaml), path)
assert.Len(t, nodes, 1)

rule := buildCoreTestRule(path, model.SeverityError, "undefined", "cake", nil)
ctx := buildCoreTestContext(model.CastToRuleAction(rule.Then), nil)
ctx.Given = path
ctx.Rule = &rule
ctx.Document = document
ctx.DrDocument = drDocument

def := Undefined{}
res := def.RunRule(nodes, ctx)
Expand Down

0 comments on commit 041c2f0

Please sign in to comment.