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.
Calvin Lobo authored and daveshanley committed Jan 9, 2025
1 parent 10bbe26 commit 041c2f0
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
@@ -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)),
42 changes: 35 additions & 7 deletions functions/core/defined_test.go
Original file line number Diff line number Diff line change
@@ -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) {
11 changes: 8 additions & 3 deletions functions/core/truthy.go
Original file line number Diff line number Diff line change
@@ -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)
}
}
}
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"
@@ -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) {
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"
@@ -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)
@@ -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)

0 comments on commit 041c2f0

Please sign in to comment.