Skip to content

Commit

Permalink
added depth setting for control (#61)
Browse files Browse the repository at this point in the history
  • Loading branch information
unai-programmfabrik authored Aug 20, 2021
1 parent e3a2288 commit 7775886
Show file tree
Hide file tree
Showing 5 changed files with 373 additions and 48 deletions.
49 changes: 47 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -808,6 +808,51 @@ E.g. the following response would **fail** as the order in the actual response
}
```

### `depth`

This setting defines the depth that the `no_extra` and `order_matters` should consider when matching arrays.

`depth` is available only for arrays.

The possible values of `depth` are:
```
-1 -> full depth
0 -> top element only (default)
N -> N elements deep
```

The following response would **fail** as their are too many entries in the actual response inner array.

#### expected response defined with no_extra and depth

```yaml
{
"body": {
"testArray": [
[1, 3, 5],
[2, 4, 6]
],
"testObject:control": {
"no_extra": true,
"depth": 1
}
}
}
```

#### actual response

```yaml
{
"body": {
"testArray": [
[1, 3, 5],
[2, 4, 6, 8]
]
}
}
```

### `must_exist`

Check if a certain value does exist in the reponse (no matter what its content is)
Expand Down Expand Up @@ -870,11 +915,11 @@ E.g. the following response would **fail** as `"count"` is has the wrong length

Passes the no extra to the underlying structure in an array

`must_exist` is available only for arrays
`element_no_extra` is available only for arrays

This control can be used without a "real" key. So only the `:control` key is present.

E.g. the following response would **fail** as `"hasExtra"` is has extras
E.g. the following response would **fail** as `"extra"` is an extra element

#### expected response defined with must_exist

Expand Down
85 changes: 43 additions & 42 deletions pkg/lib/compare/comparison_functions.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
)

type ComparisonContext struct {
depth int64
orderMatters bool
noExtra bool
elementNoExtra bool
Expand All @@ -37,6 +38,13 @@ func fillComparisonContext(in util.JsonObject) (out *ComparisonContext, err erro

for k, v := range in {
switch k {
case "depth":
tV, err := getAsInt64(v)
if err != nil {
return out, fmt.Errorf("depth is no int64: %s", err)

}
out.depth = tV
case "order_matters":
tV, ok := v.(bool)
if !ok {
Expand Down Expand Up @@ -206,8 +214,8 @@ func objectComparison(left, right util.JsonObject, noExtra bool) (res CompareRes
res.Equal = true
keyRegex := regexp.MustCompile(`(?P<Key>.*?):control`)

takenInRight := make(map[string]bool, 0)
takenInLeft := make(map[string]bool, 0)
takenInRight := make(map[string]bool)
takenInLeft := make(map[string]bool)

// Iterate over normal fields
for ck, cv := range left {
Expand Down Expand Up @@ -322,12 +330,12 @@ func objectComparison(left, right util.JsonObject, noExtra bool) (res CompareRes
// ArrayComparison offerst the compare feature to other packages, with the standard behavior
// noExtra=false, orderMatter=false
func ArrayComparison(left, right util.JsonArray) (res CompareResult, err error) {
return arrayComparison(left, right, false, false, ComparisonContext{})
return arrayComparison(left, right, ComparisonContext{}, ComparisonContext{})
}

// arrayComparison makes a simple array comparison by either running trough both arrays with the same key (orderMaters)
// or taking a value from the left array and search it in the right one
func arrayComparison(left, right util.JsonArray, noExtra, orderMaters bool, control ComparisonContext) (res CompareResult, err error) {
func arrayComparison(left, right util.JsonArray, currControl ComparisonContext, nextControl ComparisonContext) (res CompareResult, err error) {
res.Equal = true

if len(left) > len(right) {
Expand All @@ -346,20 +354,20 @@ func arrayComparison(left, right util.JsonArray, noExtra, orderMaters bool, cont
return res, nil
}

takenInRight := make(map[int]bool, 0)
takenInRight := make(map[int]bool)
var lastPositionFromLeftInRight int = -1

for lk, lv := range left {
if orderMaters {
if currControl.orderMatters {
for rk, rv := range right {
if rk <= lastPositionFromLeftInRight {
continue
}
tmp, err := JsonEqual(lv, rv, control)
tmp, err := JsonEqual(lv, rv, nextControl)
if err != nil {
return CompareResult{}, err
}
if tmp.Equal == true {
if tmp.Equal {
takenInRight[lk] = true
lastPositionFromLeftInRight = rk
break
Expand Down Expand Up @@ -396,16 +404,16 @@ func arrayComparison(left, right util.JsonArray, noExtra, orderMaters bool, cont
for k, v := range jo {
lvv[k] = v
}
tmp, err = JsonEqual(lvv, rv, control)
tmp, err = JsonEqual(lvv, rv, nextControl)
default:
tmp, err = JsonEqual(lv, rv, control)
tmp, err = JsonEqual(lv, rv, nextControl)
}

if err != nil {
return CompareResult{}, err
}

if tmp.Equal == true {
if tmp.Equal {
// Found an element fitting
found = true
takenInRight[rk] = true
Expand All @@ -416,21 +424,21 @@ func arrayComparison(left, right util.JsonArray, noExtra, orderMaters bool, cont
allTmpFailures = append(allTmpFailures, tmp.Failures...)
}

if found != true {
if !found {
for _, v := range allTmpFailures {
key := fmt.Sprintf("[%d].%s", lk, v.Key)
if v.Key == "" {
key = fmt.Sprintf("[%d]", lk)
}
res.Failures = append(res.Failures, CompareFailure{key, fmt.Sprintf("%s", v.Message)})
res.Failures = append(res.Failures, CompareFailure{key, v.Message})
}
res.Equal = false
}
}

}

if noExtra {
if currControl.noExtra {
for k := range right {
if !takenInRight[k] {
res.Failures = append(res.Failures, CompareFailure{Key: "", Message: "extra elements found in array"})
Expand All @@ -444,7 +452,7 @@ func arrayComparison(left, right util.JsonArray, noExtra, orderMaters bool, cont
}

func ObjectEqualWithControl(left, right util.JsonObject, control ComparisonContext) (res CompareResult, err error) {
if control.noExtra == true {
if control.noExtra {
return objectComparison(left, right, true)
}

Expand All @@ -453,65 +461,58 @@ func ObjectEqualWithControl(left, right util.JsonObject, control ComparisonConte
}

func ArrayEqualWithControl(left, right util.JsonArray, control ComparisonContext) (res CompareResult, err error) {
emptyControl := ComparisonContext{}

if control.elementNoExtra == true {
emptyControl.noExtra = true
nextControl := ComparisonContext{
noExtra: control.elementNoExtra,
depth: -9999,
}

if control.orderMatters == true {
if control.noExtra == true {
// No extra with order
return arrayComparison(left, right, true, true, emptyControl)
} else {
// with extra with order
return arrayComparison(left, right, false, true, emptyControl)
}
} else {
if control.noExtra == true {
// No extra, no order
return arrayComparison(left, right, true, false, emptyControl)
} else {
// with extra, no order
return arrayComparison(left, right, false, false, emptyControl)
if control.depth >= -1 {
if control.depth > 0 {
nextControl.depth = control.depth - 1
} else if control.depth < 0 {
nextControl.depth = control.depth
}
}
if nextControl.depth >= -1 {
nextControl.noExtra = nextControl.noExtra || control.noExtra
nextControl.orderMatters = control.orderMatters
}
return arrayComparison(left, right, control, nextControl)
}

func keyChecks(lk string, right interface{}, rOK bool, control ComparisonContext) (err error) {
if control.isString == true {
if control.isString {
if right == nil {
return fmt.Errorf("== nil but should exist")
}
jsonType := getJsonType(right)
if jsonType != "String" {
return fmt.Errorf("should be 'String' but is '%s'", jsonType)
}
} else if control.isNumber == true {
} else if control.isNumber {
if right == nil {
return fmt.Errorf("== nil but should exist")
}
jsonType := getJsonType(right)
if jsonType != "Number" {
return fmt.Errorf("should be 'Number' but is '%s'", jsonType)
}
} else if control.isBool == true {
} else if control.isBool {
if right == nil {
return fmt.Errorf("== nil but should exist")
}
jsonType := getJsonType(right)
if jsonType != "Bool" {
return fmt.Errorf("should be 'Bool' but is '%s'", jsonType)
}
} else if control.isArray == true {
} else if control.isArray {
if right == nil {
return fmt.Errorf("== nil but should exist")
}
jsonType := getJsonType(right)
if jsonType != "Array" {
return fmt.Errorf("should be 'Array' but is '%s'", jsonType)
}
} else if control.isObject == true {
} else if control.isObject {
if right == nil {
return fmt.Errorf("== nil but should exist")
}
Expand All @@ -522,11 +523,11 @@ func keyChecks(lk string, right interface{}, rOK bool, control ComparisonContext
}

// Check if exists
if rOK == false && control.mustExist == true {
if !rOK && control.mustExist {
return fmt.Errorf("was not found, but should exist")
}

if rOK == true && control.mustNotExist == true {
if rOK && control.mustNotExist {
return fmt.Errorf("was found, but should NOT exist")
}

Expand Down
7 changes: 4 additions & 3 deletions test/control/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
},
"name": "check control structures in array",
"tests": [
"@match.json",
"@starts_ends_with.json",
"@order_matters.json"
"@match.json"
,"@no_extra.json"
,"@starts_ends_with.json"
,"@order_matters.json"
]
}
Loading

0 comments on commit 7775886

Please sign in to comment.