Skip to content

Commit 0f6d2d9

Browse files
committed
test op
Signed-off-by: dmitriy kalinin <[email protected]>
1 parent 4924067 commit 0f6d2d9

File tree

4 files changed

+130
-18
lines changed

4 files changed

+130
-18
lines changed

patch/diff.go

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -42,17 +42,23 @@ func (d Diff) calculate(left, right interface{}, tokens []Token) []Op {
4242
newTokens = append(newTokens, KeyToken{Key: fmt.Sprintf("%s", k)})
4343
if rightVal, found := typedRight[k]; found {
4444
ops = append(ops, d.calculate(leftVal, rightVal, newTokens)...)
45-
} else {
46-
ops = append(ops, RemoveOp{Path: NewPointer(newTokens)})
45+
} else { // remove existing
46+
ops = append(ops,
47+
TestOp{Path: NewPointer(newTokens), Value: leftVal},
48+
RemoveOp{Path: NewPointer(newTokens)},
49+
)
4750
}
48-
} else {
51+
} else { // add new
4952
newTokens = append(newTokens, KeyToken{Key: fmt.Sprintf("%s", k), Optional: true})
5053
ops = append(ops, ReplaceOp{Path: NewPointer(newTokens), Value: typedRight[k]})
5154
}
5255
}
5356
return ops
5457
}
55-
return []Op{ReplaceOp{Path: NewPointer(tokens), Value: right}}
58+
return []Op{
59+
TestOp{Path: NewPointer(tokens), Value: left},
60+
ReplaceOp{Path: NewPointer(tokens), Value: right},
61+
}
5662

5763
case []interface{}:
5864
if typedRight, ok := right.([]interface{}); ok {
@@ -61,11 +67,14 @@ func (d Diff) calculate(left, right interface{}, tokens []Token) []Op {
6167
for i := 0; i < max(len(typedLeft), len(typedRight)); i++ {
6268
newTokens := append([]Token{}, tokens...)
6369
switch {
64-
case i >= len(typedRight):
70+
case i >= len(typedRight): // remove existing
6571
newTokens = append(newTokens, IndexToken{Index: actualIndex})
66-
ops = append(ops, RemoveOp{Path: NewPointer(newTokens)})
72+
ops = append(ops,
73+
TestOp{Path: NewPointer(newTokens), Value: typedLeft[i]}, // capture actual value at index
74+
RemoveOp{Path: NewPointer(newTokens)},
75+
)
6776
// keep actualIndex the same
68-
case i >= len(typedLeft):
77+
case i >= len(typedLeft): // add new
6978
newTokens = append(newTokens, AfterLastIndexToken{})
7079
ops = append(ops, ReplaceOp{Path: NewPointer(newTokens), Value: typedRight[i]})
7180
actualIndex++
@@ -77,11 +86,17 @@ func (d Diff) calculate(left, right interface{}, tokens []Token) []Op {
7786
}
7887
return ops
7988
}
80-
return []Op{ReplaceOp{Path: NewPointer(tokens), Value: right}}
89+
return []Op{
90+
TestOp{Path: NewPointer(tokens), Value: left},
91+
ReplaceOp{Path: NewPointer(tokens), Value: right},
92+
}
8193

8294
default:
8395
if !reflect.DeepEqual(left, right) {
84-
return []Op{ReplaceOp{Path: NewPointer(tokens), Value: right}}
96+
return []Op{
97+
TestOp{Path: NewPointer(tokens), Value: left},
98+
ReplaceOp{Path: NewPointer(tokens), Value: right},
99+
}
85100
}
86101
}
87102

patch/diff_test.go

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,10 @@ import (
99

1010
var _ = Describe("Diff.Calculate", func() {
1111
testDiff := func(left, right interface{}, expectedOps []Op) {
12-
Expect(Diff{Left: left, Right: right}.Calculate()).To(Equal(Ops(expectedOps)))
12+
diffOps := Diff{Left: left, Right: right}.Calculate()
13+
Expect(diffOps).To(Equal(Ops(expectedOps)))
1314

14-
result, err := Ops(expectedOps).Apply(left)
15+
result, err := Ops(diffOps).Apply(left)
1516
Expect(err).ToNot(HaveOccurred())
1617

1718
if right == nil { // gomega does not allow nil==nil comparison
@@ -38,18 +39,25 @@ var _ = Describe("Diff.Calculate", func() {
3839
})
3940

4041
It("can replace doc root", func() {
41-
testDiff(nil, "a", []Op{ReplaceOp{Path: MustNewPointerFromString(""), Value: "a"}})
42+
testDiff(nil, "a", []Op{
43+
TestOp{Path: MustNewPointerFromString(""), Value: nil},
44+
ReplaceOp{Path: MustNewPointerFromString(""), Value: "a"},
45+
})
4246
})
4347

4448
It("can replace doc root with nil", func() {
45-
testDiff("a", nil, []Op{ReplaceOp{Path: MustNewPointerFromString(""), Value: nil}})
49+
testDiff("a", nil, []Op{
50+
TestOp{Path: MustNewPointerFromString(""), Value: "a"},
51+
ReplaceOp{Path: MustNewPointerFromString(""), Value: nil},
52+
})
4653
})
4754

4855
It("can diff maps", func() {
4956
testDiff(
5057
map[interface{}]interface{}{"a": 123},
5158
map[interface{}]interface{}{"a": 124},
5259
[]Op{
60+
TestOp{Path: MustNewPointerFromString("/a"), Value: 123},
5361
ReplaceOp{Path: MustNewPointerFromString("/a"), Value: 124},
5462
},
5563
)
@@ -58,7 +66,9 @@ var _ = Describe("Diff.Calculate", func() {
5866
map[interface{}]interface{}{"a": 123, "b": 456},
5967
map[interface{}]interface{}{"a": 124, "c": 456},
6068
[]Op{
69+
TestOp{Path: MustNewPointerFromString("/a"), Value: 123},
6170
ReplaceOp{Path: MustNewPointerFromString("/a"), Value: 124},
71+
TestOp{Path: MustNewPointerFromString("/b"), Value: 456},
6272
RemoveOp{Path: MustNewPointerFromString("/b")},
6373
ReplaceOp{Path: MustNewPointerFromString("/c?"), Value: 456},
6474
},
@@ -68,7 +78,9 @@ var _ = Describe("Diff.Calculate", func() {
6878
map[interface{}]interface{}{"a": 123, "b": 456},
6979
map[interface{}]interface{}{"a": 124},
7080
[]Op{
81+
TestOp{Path: MustNewPointerFromString("/a"), Value: 123},
7182
ReplaceOp{Path: MustNewPointerFromString("/a"), Value: 124},
83+
TestOp{Path: MustNewPointerFromString("/b"), Value: 456},
7284
RemoveOp{Path: MustNewPointerFromString("/b")},
7385
},
7486
)
@@ -77,7 +89,9 @@ var _ = Describe("Diff.Calculate", func() {
7789
map[interface{}]interface{}{"a": 123, "b": 456},
7890
map[interface{}]interface{}{},
7991
[]Op{
92+
TestOp{Path: MustNewPointerFromString("/a"), Value: 123},
8093
RemoveOp{Path: MustNewPointerFromString("/a")},
94+
TestOp{Path: MustNewPointerFromString("/b"), Value: 456},
8195
RemoveOp{Path: MustNewPointerFromString("/b")},
8296
},
8397
)
@@ -86,6 +100,7 @@ var _ = Describe("Diff.Calculate", func() {
86100
map[interface{}]interface{}{"a": 123},
87101
map[interface{}]interface{}{"a": nil},
88102
[]Op{
103+
TestOp{Path: MustNewPointerFromString("/a"), Value: 123},
89104
ReplaceOp{Path: MustNewPointerFromString("/a"), Value: nil},
90105
},
91106
)
@@ -94,7 +109,9 @@ var _ = Describe("Diff.Calculate", func() {
94109
map[interface{}]interface{}{"a": 123, "b": map[interface{}]interface{}{"a": 1024, "b": 4056}},
95110
map[interface{}]interface{}{"a": 124, "b": map[interface{}]interface{}{"a": 1024, "c": 4056}},
96111
[]Op{
112+
TestOp{Path: MustNewPointerFromString("/a"), Value: 123},
97113
ReplaceOp{Path: MustNewPointerFromString("/a"), Value: 124},
114+
TestOp{Path: MustNewPointerFromString("/b/b"), Value: 4056},
98115
RemoveOp{Path: MustNewPointerFromString("/b/b")},
99116
ReplaceOp{Path: MustNewPointerFromString("/b/c?"), Value: 4056},
100117
},
@@ -104,6 +121,7 @@ var _ = Describe("Diff.Calculate", func() {
104121
map[interface{}]interface{}{"a": 123},
105122
"a",
106123
[]Op{
124+
TestOp{Path: MustNewPointerFromString(""), Value: map[interface{}]interface{}{"a": 123}},
107125
ReplaceOp{Path: MustNewPointerFromString(""), Value: "a"},
108126
},
109127
)
@@ -112,6 +130,7 @@ var _ = Describe("Diff.Calculate", func() {
112130
"a",
113131
map[interface{}]interface{}{"a": 123},
114132
[]Op{
133+
TestOp{Path: MustNewPointerFromString(""), Value: "a"},
115134
ReplaceOp{Path: MustNewPointerFromString(""), Value: map[interface{}]interface{}{"a": 123}},
116135
},
117136
)
@@ -122,6 +141,7 @@ var _ = Describe("Diff.Calculate", func() {
122141
[]interface{}{"a", 123},
123142
[]interface{}{"b", 123},
124143
[]Op{
144+
TestOp{Path: MustNewPointerFromString("/0"), Value: "a"},
125145
ReplaceOp{Path: MustNewPointerFromString("/0"), Value: "b"},
126146
},
127147
)
@@ -130,6 +150,7 @@ var _ = Describe("Diff.Calculate", func() {
130150
[]interface{}{"a"},
131151
[]interface{}{"b", 123, 456},
132152
[]Op{
153+
TestOp{Path: MustNewPointerFromString("/0"), Value: "a"},
133154
ReplaceOp{Path: MustNewPointerFromString("/0"), Value: "b"},
134155
ReplaceOp{Path: MustNewPointerFromString("/-"), Value: 123},
135156
ReplaceOp{Path: MustNewPointerFromString("/-"), Value: 456},
@@ -140,8 +161,11 @@ var _ = Describe("Diff.Calculate", func() {
140161
[]interface{}{"a", 123, 456},
141162
[]interface{}{"b"},
142163
[]Op{
164+
TestOp{Path: MustNewPointerFromString("/0"), Value: "a"},
143165
ReplaceOp{Path: MustNewPointerFromString("/0"), Value: "b"},
166+
TestOp{Path: MustNewPointerFromString("/1"), Value: 123},
144167
RemoveOp{Path: MustNewPointerFromString("/1")},
168+
TestOp{Path: MustNewPointerFromString("/1"), Value: 456},
145169
RemoveOp{Path: MustNewPointerFromString("/1")},
146170
},
147171
)
@@ -150,7 +174,9 @@ var _ = Describe("Diff.Calculate", func() {
150174
[]interface{}{123, 456},
151175
[]interface{}{},
152176
[]Op{
177+
TestOp{Path: MustNewPointerFromString("/0"), Value: 123},
153178
RemoveOp{Path: MustNewPointerFromString("/0")},
179+
TestOp{Path: MustNewPointerFromString("/0"), Value: 456},
154180
RemoveOp{Path: MustNewPointerFromString("/0")},
155181
},
156182
)
@@ -159,16 +185,19 @@ var _ = Describe("Diff.Calculate", func() {
159185
[]interface{}{123, 456},
160186
[]interface{}{123, "a", 456}, // TODO unoptimized insertion
161187
[]Op{
188+
TestOp{Path: MustNewPointerFromString("/1"), Value: 456},
162189
ReplaceOp{Path: MustNewPointerFromString("/1"), Value: "a"},
163190
ReplaceOp{Path: MustNewPointerFromString("/-"), Value: 456},
164191
},
165192
)
166193

167194
testDiff(
168195
[]interface{}{[]interface{}{456, 789}},
169-
[]interface{}{[]interface{}{789}},
196+
[]interface{}{[]interface{}{789}}, // TODO unoptimized deletion
170197
[]Op{
198+
TestOp{Path: MustNewPointerFromString("/0/0"), Value: 456},
171199
ReplaceOp{Path: MustNewPointerFromString("/0/0"), Value: 789},
200+
TestOp{Path: MustNewPointerFromString("/0/1"), Value: 789},
172201
RemoveOp{Path: MustNewPointerFromString("/0/1")},
173202
},
174203
)
@@ -177,6 +206,7 @@ var _ = Describe("Diff.Calculate", func() {
177206
[]interface{}{"a", 123},
178207
"a",
179208
[]Op{
209+
TestOp{Path: MustNewPointerFromString(""), Value: []interface{}{"a", 123}},
180210
ReplaceOp{Path: MustNewPointerFromString(""), Value: "a"},
181211
},
182212
)
@@ -185,6 +215,7 @@ var _ = Describe("Diff.Calculate", func() {
185215
"a",
186216
[]interface{}{"a", 123},
187217
[]Op{
218+
TestOp{Path: MustNewPointerFromString(""), Value: "a"},
188219
ReplaceOp{Path: MustNewPointerFromString(""), Value: []interface{}{"a", 123}},
189220
},
190221
)

patch/op_definition.go

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@ import (
88

99
// OpDefinition struct is useful for JSON and YAML unmarshaling
1010
type OpDefinition struct {
11-
Type string `json:",omitempty"`
12-
Path *string `json:",omitempty"`
13-
Value *interface{} `json:",omitempty"`
11+
Type string `json:",omitempty" yaml:",omitempty"`
12+
Path *string `json:",omitempty" yaml:",omitempty"`
13+
Value *interface{} `json:",omitempty" yaml:",omitempty"`
1414

15-
Error *string `json:",omitempty"`
15+
Error *string `json:",omitempty" yaml:",omitempty"`
1616
}
1717

1818
type parser struct{}
@@ -106,3 +106,44 @@ func (parser) fmtOpDef(opDef OpDefinition) string {
106106

107107
return htmlDecoder.Replace(string(bytes))
108108
}
109+
110+
func NewOpDefinitionsFromOps(ops Ops) ([]OpDefinition, error) {
111+
opDefs := []OpDefinition{}
112+
113+
for i, op := range ops {
114+
switch typedOp := op.(type) {
115+
case ReplaceOp:
116+
path := typedOp.Path.String()
117+
val := typedOp.Value
118+
119+
opDefs = append(opDefs, OpDefinition{
120+
Type: "replace",
121+
Path: &path,
122+
Value: &val,
123+
})
124+
125+
case RemoveOp:
126+
path := typedOp.Path.String()
127+
128+
opDefs = append(opDefs, OpDefinition{
129+
Type: "remove",
130+
Path: &path,
131+
})
132+
133+
case TestOp:
134+
path := typedOp.Path.String()
135+
val := typedOp.Value
136+
137+
opDefs = append(opDefs, OpDefinition{
138+
Type: "test",
139+
Path: &path,
140+
Value: &val,
141+
})
142+
143+
default:
144+
return nil, fmt.Errorf("Unknown operation [%d] with type '%t'", i, op)
145+
}
146+
}
147+
148+
return opDefs, nil
149+
}

patch/test_op.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package patch
2+
3+
import (
4+
"fmt"
5+
"reflect"
6+
)
7+
8+
type TestOp struct {
9+
Path Pointer
10+
Value interface{}
11+
}
12+
13+
func (op TestOp) Apply(doc interface{}) (interface{}, error) {
14+
foundVal, err := FindOp{Path: op.Path}.Apply(doc)
15+
if err != nil {
16+
return nil, err
17+
}
18+
19+
if !reflect.DeepEqual(foundVal, op.Value) {
20+
return nil, fmt.Errorf("Found value does not match expected value")
21+
}
22+
23+
// Return same input document
24+
return doc, nil
25+
}

0 commit comments

Comments
 (0)