Skip to content

Commit 8f82a93

Browse files
committed
support absence check via testop
1 parent 960a5c9 commit 8f82a93

12 files changed

+242
-103
lines changed

patch/array_index.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ type ArrayIndex struct {
88
Index int
99
Modifiers []Modifier
1010
Array []interface{}
11+
Path Pointer
1112
}
1213

1314
func (i ArrayIndex) Concrete() (int, error) {
@@ -25,7 +26,7 @@ func (i ArrayIndex) Concrete() (int, error) {
2526
}
2627

2728
if result >= len(i.Array) || (-result)-1 >= len(i.Array) {
28-
return 0, OpMissingIndexErr{result, i.Array}
29+
return 0, OpMissingIndexErr{result, i.Array, i.Path}
2930
}
3031

3132
if result < 0 {

patch/array_index_test.go

Lines changed: 36 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -8,118 +8,120 @@ import (
88
)
99

1010
var _ = Describe("ArrayIndex", func() {
11+
dummyPath := MustNewPointerFromString("")
12+
1113
Describe("Concrete", func() {
1214
It("returns positive index", func() {
13-
idx := ArrayIndex{Index: 0, Modifiers: nil, Array: []interface{}{1, 2, 3}}
15+
idx := ArrayIndex{Index: 0, Modifiers: nil, Array: []interface{}{1, 2, 3}, Path: dummyPath}
1416
Expect(idx.Concrete()).To(Equal(0))
1517

16-
idx = ArrayIndex{Index: 1, Modifiers: nil, Array: []interface{}{1, 2, 3}}
18+
idx = ArrayIndex{Index: 1, Modifiers: nil, Array: []interface{}{1, 2, 3}, Path: dummyPath}
1719
Expect(idx.Concrete()).To(Equal(1))
1820

19-
idx = ArrayIndex{Index: 2, Modifiers: nil, Array: []interface{}{1, 2, 3}}
21+
idx = ArrayIndex{Index: 2, Modifiers: nil, Array: []interface{}{1, 2, 3}, Path: dummyPath}
2022
Expect(idx.Concrete()).To(Equal(2))
2123
})
2224

2325
It("wraps around negative index one time", func() {
24-
idx := ArrayIndex{Index: -0, Modifiers: nil, Array: []interface{}{1, 2, 3}}
26+
idx := ArrayIndex{Index: -0, Modifiers: nil, Array: []interface{}{1, 2, 3}, Path: dummyPath}
2527
Expect(idx.Concrete()).To(Equal(0))
2628

27-
idx = ArrayIndex{Index: -1, Modifiers: nil, Array: []interface{}{1, 2, 3}}
29+
idx = ArrayIndex{Index: -1, Modifiers: nil, Array: []interface{}{1, 2, 3}, Path: dummyPath}
2830
Expect(idx.Concrete()).To(Equal(2))
2931

30-
idx = ArrayIndex{Index: -2, Modifiers: nil, Array: []interface{}{1, 2, 3}}
32+
idx = ArrayIndex{Index: -2, Modifiers: nil, Array: []interface{}{1, 2, 3}, Path: dummyPath}
3133
Expect(idx.Concrete()).To(Equal(1))
3234

33-
idx = ArrayIndex{Index: -3, Modifiers: nil, Array: []interface{}{1, 2, 3}}
35+
idx = ArrayIndex{Index: -3, Modifiers: nil, Array: []interface{}{1, 2, 3}, Path: dummyPath}
3436
Expect(idx.Concrete()).To(Equal(0))
3537
})
3638

3739
It("does not work with empty arrays", func() {
38-
idx := ArrayIndex{Index: 0, Modifiers: nil, Array: []interface{}{}}
40+
idx := ArrayIndex{Index: 0, Modifiers: nil, Array: []interface{}{}, Path: dummyPath}
3941
_, err := idx.Concrete()
40-
Expect(err).To(Equal(OpMissingIndexErr{0, []interface{}{}}))
42+
Expect(err).To(Equal(OpMissingIndexErr{0, []interface{}{}, dummyPath}))
4143

4244
p := PrevModifier{}
4345
n := NextModifier{}
4446

45-
idx = ArrayIndex{Index: 0, Modifiers: []Modifier{p, n}, Array: []interface{}{}}
47+
idx = ArrayIndex{Index: 0, Modifiers: []Modifier{p, n}, Array: []interface{}{}, Path: dummyPath}
4648
_, err = idx.Concrete()
47-
Expect(err).To(Equal(OpMissingIndexErr{0, []interface{}{}}))
49+
Expect(err).To(Equal(OpMissingIndexErr{0, []interface{}{}, dummyPath}))
4850
})
4951

5052
It("does not work with index out of bounds", func() {
51-
idx := ArrayIndex{Index: 3, Modifiers: nil, Array: []interface{}{1, 2, 3}}
53+
idx := ArrayIndex{Index: 3, Modifiers: nil, Array: []interface{}{1, 2, 3}, Path: dummyPath}
5254
_, err := idx.Concrete()
53-
Expect(err).To(Equal(OpMissingIndexErr{3, []interface{}{1, 2, 3}}))
55+
Expect(err).To(Equal(OpMissingIndexErr{3, []interface{}{1, 2, 3}, dummyPath}))
5456

55-
idx = ArrayIndex{Index: -4, Modifiers: nil, Array: []interface{}{1, 2, 3}}
57+
idx = ArrayIndex{Index: -4, Modifiers: nil, Array: []interface{}{1, 2, 3}, Path: dummyPath}
5658
_, err = idx.Concrete()
57-
Expect(err).To(Equal(OpMissingIndexErr{-4, []interface{}{1, 2, 3}}))
59+
Expect(err).To(Equal(OpMissingIndexErr{-4, []interface{}{1, 2, 3}, dummyPath}))
5860
})
5961

6062
It("returns previous item when previous modifier is used", func() {
6163
p := PrevModifier{}
6264

63-
idx := ArrayIndex{Index: 0, Modifiers: []Modifier{p}, Array: []interface{}{1, 2, 3}}
65+
idx := ArrayIndex{Index: 0, Modifiers: []Modifier{p}, Array: []interface{}{1, 2, 3}, Path: dummyPath}
6466
Expect(idx.Concrete()).To(Equal(2))
6567

66-
idx = ArrayIndex{Index: 0, Modifiers: []Modifier{p, p}, Array: []interface{}{1, 2, 3}}
68+
idx = ArrayIndex{Index: 0, Modifiers: []Modifier{p, p}, Array: []interface{}{1, 2, 3}, Path: dummyPath}
6769
Expect(idx.Concrete()).To(Equal(1))
6870

69-
idx = ArrayIndex{Index: 0, Modifiers: []Modifier{p, p, p}, Array: []interface{}{1, 2, 3}}
71+
idx = ArrayIndex{Index: 0, Modifiers: []Modifier{p, p, p}, Array: []interface{}{1, 2, 3}, Path: dummyPath}
7072
Expect(idx.Concrete()).To(Equal(0))
7173

72-
idx = ArrayIndex{Index: 0, Modifiers: []Modifier{p, p, p, p}, Array: []interface{}{1, 2, 3}}
74+
idx = ArrayIndex{Index: 0, Modifiers: []Modifier{p, p, p, p}, Array: []interface{}{1, 2, 3}, Path: dummyPath}
7375
_, err := idx.Concrete()
74-
Expect(err).To(Equal(OpMissingIndexErr{-4, []interface{}{1, 2, 3}}))
76+
Expect(err).To(Equal(OpMissingIndexErr{-4, []interface{}{1, 2, 3}, dummyPath}))
7577

76-
idx = ArrayIndex{Index: 0, Modifiers: []Modifier{p, p, p, p, p}, Array: []interface{}{1, 2, 3}}
78+
idx = ArrayIndex{Index: 0, Modifiers: []Modifier{p, p, p, p, p}, Array: []interface{}{1, 2, 3}, Path: dummyPath}
7779
_, err = idx.Concrete()
78-
Expect(err).To(Equal(OpMissingIndexErr{-5, []interface{}{1, 2, 3}}))
80+
Expect(err).To(Equal(OpMissingIndexErr{-5, []interface{}{1, 2, 3}, dummyPath}))
7981

80-
idx = ArrayIndex{Index: 2, Modifiers: []Modifier{p, p}, Array: []interface{}{1, 2, 3}}
82+
idx = ArrayIndex{Index: 2, Modifiers: []Modifier{p, p}, Array: []interface{}{1, 2, 3}, Path: dummyPath}
8183
Expect(idx.Concrete()).To(Equal(0))
8284
})
8385

8486
It("returns next item when next modifier is used", func() {
8587
n := NextModifier{}
8688

87-
idx := ArrayIndex{Index: 0, Modifiers: []Modifier{n}, Array: []interface{}{1, 2, 3}}
89+
idx := ArrayIndex{Index: 0, Modifiers: []Modifier{n}, Array: []interface{}{1, 2, 3}, Path: dummyPath}
8890
Expect(idx.Concrete()).To(Equal(1))
8991

90-
idx = ArrayIndex{Index: 0, Modifiers: []Modifier{n, n}, Array: []interface{}{1, 2, 3}}
92+
idx = ArrayIndex{Index: 0, Modifiers: []Modifier{n, n}, Array: []interface{}{1, 2, 3}, Path: dummyPath}
9193
Expect(idx.Concrete()).To(Equal(2))
9294

93-
idx = ArrayIndex{Index: 0, Modifiers: []Modifier{n, n, n}, Array: []interface{}{1, 2, 3}}
95+
idx = ArrayIndex{Index: 0, Modifiers: []Modifier{n, n, n}, Array: []interface{}{1, 2, 3}, Path: dummyPath}
9496
_, err := idx.Concrete()
95-
Expect(err).To(Equal(OpMissingIndexErr{3, []interface{}{1, 2, 3}}))
97+
Expect(err).To(Equal(OpMissingIndexErr{3, []interface{}{1, 2, 3}, dummyPath}))
9698

97-
idx = ArrayIndex{Index: 0, Modifiers: []Modifier{n, n, n, n}, Array: []interface{}{1, 2, 3}}
99+
idx = ArrayIndex{Index: 0, Modifiers: []Modifier{n, n, n, n}, Array: []interface{}{1, 2, 3}, Path: dummyPath}
98100
_, err = idx.Concrete()
99-
Expect(err).To(Equal(OpMissingIndexErr{4, []interface{}{1, 2, 3}}))
101+
Expect(err).To(Equal(OpMissingIndexErr{4, []interface{}{1, 2, 3}, dummyPath}))
100102
})
101103

102104
It("works with multiple previous and next modifiers", func() {
103105
p := PrevModifier{}
104106
n := NextModifier{}
105107

106-
idx := ArrayIndex{Index: 0, Modifiers: []Modifier{p, n}, Array: []interface{}{1, 2, 3}}
108+
idx := ArrayIndex{Index: 0, Modifiers: []Modifier{p, n}, Array: []interface{}{1, 2, 3}, Path: dummyPath}
107109
Expect(idx.Concrete()).To(Equal(0))
108110

109-
idx = ArrayIndex{Index: 0, Modifiers: []Modifier{n, p}, Array: []interface{}{1, 2, 3}}
111+
idx = ArrayIndex{Index: 0, Modifiers: []Modifier{n, p}, Array: []interface{}{1, 2, 3}, Path: dummyPath}
110112
Expect(idx.Concrete()).To(Equal(0))
111113

112-
idx = ArrayIndex{Index: 0, Modifiers: []Modifier{n, n, p}, Array: []interface{}{1, 2, 3}}
114+
idx = ArrayIndex{Index: 0, Modifiers: []Modifier{n, n, p}, Array: []interface{}{1, 2, 3}, Path: dummyPath}
113115
Expect(idx.Concrete()).To(Equal(1))
114116

115-
idx = ArrayIndex{Index: 0, Modifiers: []Modifier{n, n, n, p}, Array: []interface{}{1, 2, 3}}
117+
idx = ArrayIndex{Index: 0, Modifiers: []Modifier{n, n, n, p}, Array: []interface{}{1, 2, 3}, Path: dummyPath}
116118
Expect(idx.Concrete()).To(Equal(2))
117119
})
118120

119121
It("does not support any other modifier except previous and next", func() {
120122
b := BeforeModifier{}
121123

122-
idx := ArrayIndex{Index: 0, Modifiers: []Modifier{b}, Array: []interface{}{1, 2, 3}}
124+
idx := ArrayIndex{Index: 0, Modifiers: []Modifier{b}, Array: []interface{}{1, 2, 3}, Path: dummyPath}
123125
_, err := idx.Concrete()
124126
Expect(err.Error()).To(Equal("Expected to find one of the following modifiers: 'prev', 'next', but found modifier 'patch.BeforeModifier'"))
125127
})

patch/array_insertion.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ type ArrayInsertion struct {
88
Index int
99
Modifiers []Modifier
1010
Array []interface{}
11+
Path Pointer
1112
}
1213

1314
type ArrayInsertionIndex struct {
@@ -41,7 +42,7 @@ func (i ArrayInsertion) Concrete() (ArrayInsertionIndex, error) {
4142
}
4243
}
4344

44-
idx := ArrayIndex{Index: i.Index, Modifiers: mods, Array: i.Array}
45+
idx := ArrayIndex{Index: i.Index, Modifiers: mods, Array: i.Array, Path: i.Path}
4546

4647
num, err := idx.Concrete()
4748
if err != nil {

patch/errs.go

Lines changed: 33 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -6,42 +6,42 @@ import (
66
"strings"
77
)
88

9-
type opMismatchTypeErr struct {
10-
type_ string
11-
path Pointer
12-
obj interface{}
9+
type OpMismatchTypeErr struct {
10+
Type_ string
11+
Path Pointer
12+
Obj interface{}
1313
}
1414

15-
func newOpArrayMismatchTypeErr(tokens []Token, obj interface{}) opMismatchTypeErr {
16-
return opMismatchTypeErr{"an array", NewPointer(tokens), obj}
15+
func NewOpArrayMismatchTypeErr(path Pointer, obj interface{}) OpMismatchTypeErr {
16+
return OpMismatchTypeErr{"an array", path, obj}
1717
}
1818

19-
func newOpMapMismatchTypeErr(tokens []Token, obj interface{}) opMismatchTypeErr {
20-
return opMismatchTypeErr{"a map", NewPointer(tokens), obj}
19+
func NewOpMapMismatchTypeErr(path Pointer, obj interface{}) OpMismatchTypeErr {
20+
return OpMismatchTypeErr{"a map", path, obj}
2121
}
2222

23-
func (e opMismatchTypeErr) Error() string {
23+
func (e OpMismatchTypeErr) Error() string {
2424
errMsg := "Expected to find %s at path '%s' but found '%T'"
25-
return fmt.Sprintf(errMsg, e.type_, e.path, e.obj)
25+
return fmt.Sprintf(errMsg, e.Type_, e.Path, e.Obj)
2626
}
2727

28-
type opMissingMapKeyErr struct {
29-
key string
30-
path Pointer
31-
obj map[interface{}]interface{}
28+
type OpMissingMapKeyErr struct {
29+
Key string
30+
Path Pointer
31+
Obj map[interface{}]interface{}
3232
}
3333

34-
func (e opMissingMapKeyErr) Error() string {
34+
func (e OpMissingMapKeyErr) Error() string {
3535
errMsg := "Expected to find a map key '%s' for path '%s' (%s)"
36-
return fmt.Sprintf(errMsg, e.key, e.path, e.siblingKeysErrStr())
36+
return fmt.Sprintf(errMsg, e.Key, e.Path, e.siblingKeysErrStr())
3737
}
3838

39-
func (e opMissingMapKeyErr) siblingKeysErrStr() string {
40-
if len(e.obj) == 0 {
39+
func (e OpMissingMapKeyErr) siblingKeysErrStr() string {
40+
if len(e.Obj) == 0 {
4141
return "found no other map keys"
4242
}
4343
var keys []string
44-
for key, _ := range e.obj {
44+
for key, _ := range e.Obj {
4545
if keyStr, ok := key.(string); ok {
4646
keys = append(keys, keyStr)
4747
}
@@ -51,28 +51,29 @@ func (e opMissingMapKeyErr) siblingKeysErrStr() string {
5151
}
5252

5353
type OpMissingIndexErr struct {
54-
Idx int
55-
Obj []interface{}
54+
Idx int
55+
Obj []interface{}
56+
Path Pointer
5657
}
5758

5859
func (e OpMissingIndexErr) Error() string {
59-
return fmt.Sprintf("Expected to find array index '%d' but found array of length '%d'", e.Idx, len(e.Obj))
60+
return fmt.Sprintf("Expected to find array index '%d' but found array of length '%d' for path '%s'", e.Idx, len(e.Obj), e.Path)
6061
}
6162

62-
type opMultipleMatchingIndexErr struct {
63-
path Pointer
64-
idxs []int
63+
type OpMultipleMatchingIndexErr struct {
64+
Path Pointer
65+
Idxs []int
6566
}
6667

67-
func (e opMultipleMatchingIndexErr) Error() string {
68-
return fmt.Sprintf("Expected to find exactly one matching array item for path '%s' but found %d", e.path, len(e.idxs))
68+
func (e OpMultipleMatchingIndexErr) Error() string {
69+
return fmt.Sprintf("Expected to find exactly one matching array item for path '%s' but found %d", e.Path, len(e.Idxs))
6970
}
7071

71-
type opUnexpectedTokenErr struct {
72-
token Token
73-
path Pointer
72+
type OpUnexpectedTokenErr struct {
73+
Token Token
74+
Path Pointer
7475
}
7576

76-
func (e opUnexpectedTokenErr) Error() string {
77-
return fmt.Sprintf("Expected to not find token '%T' at path '%s'", e.token, e.path)
77+
func (e OpUnexpectedTokenErr) Error() string {
78+
return fmt.Sprintf("Expected to not find token '%T' at path '%s'", e.Token, e.Path)
7879
}

patch/find_op.go

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,16 @@ func (op FindOp) Apply(doc interface{}) (interface{}, error) {
1919

2020
for i, token := range tokens[1:] {
2121
isLast := i == len(tokens)-2
22+
currPath := NewPointer(tokens[:i+2])
2223

2324
switch typedToken := token.(type) {
2425
case IndexToken:
2526
typedObj, ok := obj.([]interface{})
2627
if !ok {
27-
return nil, newOpArrayMismatchTypeErr(tokens[:i+2], obj)
28+
return nil, NewOpArrayMismatchTypeErr(currPath, obj)
2829
}
2930

30-
idx, err := ArrayIndex{Index: typedToken.Index, Modifiers: typedToken.Modifiers, Array: typedObj}.Concrete()
31+
idx, err := ArrayIndex{Index: typedToken.Index, Modifiers: typedToken.Modifiers, Array: typedObj, Path: currPath}.Concrete()
3132
if err != nil {
3233
return nil, err
3334
}
@@ -45,7 +46,7 @@ func (op FindOp) Apply(doc interface{}) (interface{}, error) {
4546
case MatchingIndexToken:
4647
typedObj, ok := obj.([]interface{})
4748
if !ok {
48-
return nil, newOpArrayMismatchTypeErr(tokens[:i+2], obj)
49+
return nil, NewOpArrayMismatchTypeErr(currPath, obj)
4950
}
5051

5152
var idxs []int
@@ -68,10 +69,10 @@ func (op FindOp) Apply(doc interface{}) (interface{}, error) {
6869
}
6970
} else {
7071
if len(idxs) != 1 {
71-
return nil, opMultipleMatchingIndexErr{NewPointer(tokens[:i+2]), idxs}
72+
return nil, OpMultipleMatchingIndexErr{currPath, idxs}
7273
}
7374

74-
idx, err := ArrayIndex{Index: idxs[0], Modifiers: typedToken.Modifiers, Array: typedObj}.Concrete()
75+
idx, err := ArrayIndex{Index: idxs[0], Modifiers: typedToken.Modifiers, Array: typedObj, Path: currPath}.Concrete()
7576
if err != nil {
7677
return nil, err
7778
}
@@ -86,14 +87,14 @@ func (op FindOp) Apply(doc interface{}) (interface{}, error) {
8687
case KeyToken:
8788
typedObj, ok := obj.(map[interface{}]interface{})
8889
if !ok {
89-
return nil, newOpMapMismatchTypeErr(tokens[:i+2], obj)
90+
return nil, NewOpMapMismatchTypeErr(currPath, obj)
9091
}
9192

9293
var found bool
9394

9495
obj, found = typedObj[typedToken.Key]
9596
if !found && !typedToken.Optional {
96-
return nil, opMissingMapKeyErr{typedToken.Key, NewPointer(tokens[:i+2]), typedObj}
97+
return nil, OpMissingMapKeyErr{typedToken.Key, currPath, typedObj}
9798
}
9899

99100
if isLast {
@@ -114,7 +115,7 @@ func (op FindOp) Apply(doc interface{}) (interface{}, error) {
114115
}
115116

116117
default:
117-
return nil, opUnexpectedTokenErr{token, NewPointer(tokens[:i+2])}
118+
return nil, OpUnexpectedTokenErr{token, currPath}
118119
}
119120
}
120121

patch/find_op_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,12 +81,12 @@ var _ = Describe("FindOp.Apply", func() {
8181
_, err := FindOp{Path: MustNewPointerFromString("/1")}.Apply([]interface{}{})
8282
Expect(err).To(HaveOccurred())
8383
Expect(err.Error()).To(Equal(
84-
"Expected to find array index '1' but found array of length '0'"))
84+
"Expected to find array index '1' but found array of length '0' for path '/1'"))
8585

8686
_, err = FindOp{Path: MustNewPointerFromString("/1/1")}.Apply([]interface{}{})
8787
Expect(err).To(HaveOccurred())
8888
Expect(err.Error()).To(Equal(
89-
"Expected to find array index '1' but found array of length '0'"))
89+
"Expected to find array index '1' but found array of length '0' for path '/1'"))
9090
})
9191
})
9292

0 commit comments

Comments
 (0)