1 package jsonpath
2
3 import (
4 "bytes"
5 "fmt"
6 "io"
7 "testing"
8
9 "github.com/stretchr/testify/assert"
10 "github.com/stretchr/testify/require"
11 )
12
13 func TestPathActionSingleMatch(t *testing.T) {
14
15 j := []byte(`
16 {
17 "foo": 1,
18 "bar": 2,
19 "test": "Hello, world!",
20 "baz": 123.1,
21 "array": [
22 {"foo": 1},
23 {"bar": 2},
24 {"baz": 3}
25 ],
26 "subobj": {
27 "foo": 1,
28 "subarray": [1,2,3],
29 "subsubobj": {
30 "bar": 2,
31 "baz": 3,
32 "array": ["hello", "world"]
33 }
34 },
35 "bool": true
36 }`)
37
38 decodeCount := 0
39 decode := func(d *Decoder) interface{} {
40 decodeCount++
41 var v interface{}
42 err := d.Decode(&v)
43 assert.NoError(t, err)
44 return v
45 }
46
47 dc := NewDecoder(bytes.NewBuffer(j))
48 actions := &PathActions{}
49
50 actions.Add(func(d *Decoder) error {
51 assert.Equal(t, float64(2), decode(d))
52 return nil
53 }, "array", 1, "bar")
54
55 actions.Add(func(d *Decoder) error {
56 assert.Equal(t, "Hello, world!", decode(d))
57 return nil
58 }, "test")
59
60 actions.Add(func(d *Decoder) error {
61 assert.Equal(t, []interface{}{float64(1), float64(2), float64(3)}, decode(d))
62 return nil
63 }, "subobj", "subarray")
64
65 actions.Add(func(d *Decoder) error {
66 assert.Equal(t, float64(1), decode(d))
67 return nil
68 }, "foo")
69
70 actions.Add(func(d *Decoder) error {
71 assert.Equal(t, float64(2), decode(d))
72 return nil
73 }, "bar")
74
75 dc.Scan(actions)
76
77 assert.Equal(t, 5, decodeCount)
78 }
79
80 func TestPathActionAnyIndex(t *testing.T) {
81
82 j := []byte(`
83 {
84 "foo": 1,
85 "bar": 2,
86 "test": "Hello, world!",
87 "baz": 123.1,
88 "array": [
89 {"num": 1},
90 {"num": 2},
91 {"num": 3}
92 ],
93 "subobj": {
94 "foo": 1,
95 "subarray": [1,2,3],
96 "subsubobj": {
97 "bar": 2,
98 "baz": 3,
99 "array": ["hello", "world"]
100 }
101 },
102 "bool": true
103 }`)
104
105 dc := NewDecoder(bytes.NewBuffer(j))
106 actions := &PathActions{}
107
108 numbers := []int{}
109 actions.Add(func(d *Decoder) (err error) {
110 var v int
111 err = d.Decode(&v)
112 require.NoError(t, err)
113 numbers = append(numbers, v)
114 return
115 }, "array", AnyIndex, "num")
116
117 numbers2 := []int{}
118 actions.Add(func(d *Decoder) (err error) {
119 var v int
120 err = d.Decode(&v)
121 require.NoError(t, err)
122 numbers2 = append(numbers2, v)
123 return
124 }, "subobj", "subarray", AnyIndex)
125
126 strings := []string{}
127 actions.Add(func(d *Decoder) (err error) {
128 var v string
129 err = d.Decode(&v)
130 require.NoError(t, err)
131 strings = append(strings, v)
132 return
133 }, "subobj", "subsubobj", "array", AnyIndex)
134
135 dc.Scan(actions)
136
137 assert.Equal(t, []int{1, 2, 3}, numbers)
138 assert.Equal(t, []int{1, 2, 3}, numbers2)
139 assert.Equal(t, []string{"hello", "world"}, strings)
140 }
141
142 func TestPathActionJsonStream(t *testing.T) {
143
144 j := []byte(`
145 {
146 "make": "Porsche",
147 "model": "356 Coupé",
148 "years": { "from": 1948, "to": 1965}
149 }
150 {
151 "years": { "from": 1964, "to": 1969},
152 "make": "Ford",
153 "model": "GT40"
154 }
155 {
156 "make": "Ferrari",
157 "model": "308 GTB",
158 "years": { "to": 1985, "from": 1975}
159 }
160 `)
161
162 dc := NewDecoder(bytes.NewBuffer(j))
163
164 var from, to []int
165 actions := &PathActions{}
166 actions.Add(func(d *Decoder) (err error) {
167 var v int
168 err = d.Decode(&v)
169 require.NoError(t, err)
170 from = append(from, v)
171 return
172 }, "years", "from")
173 actions.Add(func(d *Decoder) (err error) {
174 var v int
175 err = d.Decode(&v)
176 require.NoError(t, err)
177 to = append(to, v)
178 return
179 }, "years", "to")
180
181 var err error
182 var ok = true
183 for ok && err == nil {
184 ok, err = dc.Scan(actions)
185 if err != io.EOF {
186 require.NoError(t, err)
187 }
188 }
189
190 assert.Equal(t, []int{1948, 1964, 1975}, from)
191 assert.Equal(t, []int{1965, 1969, 1985}, to)
192 }
193
194 func TestPathActionJsonSubObjects(t *testing.T) {
195
196 j := []byte(`
197 {
198 "set": "cars",
199 "data": [
200 {
201 "make": "Porsche",
202 "model": "356 Coupé",
203 "years": { "from": 1948, "to": 1965}
204 },
205 {
206 "years": { "from": 1964, "to": 1969},
207 "make": "Ford",
208 "model": "GT40"
209 },
210 {
211 "make": "Ferrari",
212 "model": "308 GTB",
213 "years": { "to": 1985, "from": 1975}
214 }
215 ],
216 "more": true
217 }
218 `)
219
220 dc := NewDecoder(bytes.NewBuffer(j))
221
222 var from, to []int
223 actions := &PathActions{}
224 actions.Add(func(d *Decoder) (err error) {
225 var v int
226 err = d.Decode(&v)
227 require.NoError(t, err)
228 from = append(from, v)
229 return
230 }, "data", AnyIndex, "years", "from")
231 actions.Add(func(d *Decoder) (err error) {
232 var v int
233 err = d.Decode(&v)
234 require.NoError(t, err)
235 to = append(to, v)
236 return
237 }, "data", AnyIndex, "years", "to")
238
239 var err error
240 var ok = true
241 for ok && err == nil {
242 _, err = dc.Scan(actions)
243 if err != io.EOF {
244 require.NoError(t, err)
245 }
246 }
247
248 assert.Equal(t, []int{1948, 1964, 1975}, from)
249 assert.Equal(t, []int{1965, 1969, 1985}, to)
250 }
251
252 func TestPathActionSeekThenScan(t *testing.T) {
253
254 j := []byte(`
255 {
256 "set": "cars",
257 "data": [
258 {
259 "make": "Porsche",
260 "model": "356 Coupé",
261 "years": { "from": 1948, "to": 1965}
262 },
263 {
264 "years": { "from": 1964, "to": 1969},
265 "make": "Ford",
266 "model": "GT40"
267 },
268 {
269 "make": "Ferrari",
270 "model": "308 GTB",
271 "years": { "to": 1985, "from": 1975}
272 }
273 ],
274 "more": true
275 }
276 `)
277
278 dc := NewDecoder(bytes.NewBuffer(j))
279 ok, err := dc.SeekTo("data", 0)
280 require.NoError(t, err)
281 require.True(t, ok)
282
283 var from, to int
284 actions := &PathActions{}
285 actions.Add(func(d *Decoder) (err error) {
286 err = d.Decode(&from)
287 require.NoError(t, err)
288 return
289 }, "years", "from")
290 actions.Add(func(d *Decoder) (err error) {
291 err = d.Decode(&to)
292 require.NoError(t, err)
293 return
294 }, "years", "to")
295
296 outs := []string{}
297 for ok && err == nil {
298 ok, err = dc.Scan(actions)
299 if err != io.EOF {
300 require.NoError(t, err)
301 }
302 if err == nil || err == io.EOF {
303 outs = append(outs, fmt.Sprintf("%v-%v", from, to))
304 }
305 }
306
307 assert.Equal(t, []string{"1948-1965", "1964-1969", "1975-1985"}, outs)
308 }
309
310 func TestPathActionSeekOffsetThenScan(t *testing.T) {
311
312 j := []byte(`
313 {
314 "set": "cars",
315 "data": [
316 {
317 "make": "Porsche",
318 "model": "356 Coupé",
319 "years": { "from": 1948, "to": 1965}
320 },
321 {
322 "years": { "from": 1964, "to": 1969},
323 "make": "Ford",
324 "model": "GT40"
325 },
326 {
327 "make": "Ferrari",
328 "model": "308 GTB",
329 "years": { "to": 1985, "from": 1975}
330 }
331 ],
332 "more": true
333 }
334 `)
335
336 dc := NewDecoder(bytes.NewBuffer(j))
337 ok, err := dc.SeekTo("data", 1)
338 require.NoError(t, err)
339 require.True(t, ok)
340
341 var from, to int
342 actions := &PathActions{}
343 actions.Add(func(d *Decoder) (err error) {
344 err = d.Decode(&from)
345 require.NoError(t, err)
346 return
347 }, "years", "from")
348 actions.Add(func(d *Decoder) (err error) {
349 err = d.Decode(&to)
350 require.NoError(t, err)
351 return
352 }, "years", "to")
353
354 outs := []string{}
355 for ok && err == nil {
356 ok, err = dc.Scan(actions)
357 if err != io.EOF {
358 require.NoError(t, err)
359 }
360 if err == nil || err == io.EOF {
361 outs = append(outs, fmt.Sprintf("%v-%v", from, to))
362 }
363 }
364
365 assert.Equal(t, []string{"1964-1969", "1975-1985"}, outs)
366 }
367
368 func TestPathActionSeekThenScanThenScan(t *testing.T) {
369
370 j := []byte(`
371 {
372 "set": "cars",
373 "data": [
374 {
375 "make": "Porsche",
376 "model": "356 Coupé",
377 "years": { "from": 1948, "to": 1965}
378 },
379 {
380 "years": { "from": 1964, "to": 1969},
381 "make": "Ford",
382 "model": "GT40"
383 }
384 ],
385 "more": [
386 {
387 "make": "Ferrari",
388 "model": "308 GTB",
389 "years": { "to": 1985, "from": 1975}
390 }
391 ]
392 }
393 `)
394
395 dc := NewDecoder(bytes.NewBuffer(j))
396 ok, err := dc.SeekTo("data", 0)
397 require.NoError(t, err)
398 require.True(t, ok)
399
400 var from, to int
401 actions := &PathActions{}
402 actions.Add(func(d *Decoder) (err error) {
403 err = d.Decode(&from)
404 require.NoError(t, err)
405 return
406 }, "years", "from")
407 actions.Add(func(d *Decoder) (err error) {
408 err = d.Decode(&to)
409 require.NoError(t, err)
410 return
411 }, "years", "to")
412
413 outs := []string{}
414 for ok && err == nil {
415 ok, err = dc.Scan(actions)
416 if err != io.EOF {
417 require.NoError(t, err)
418 }
419 if err == nil || err == io.EOF {
420 outs = append(outs, fmt.Sprintf("%v-%v", from, to))
421 }
422 }
423
424 assert.Equal(t, []string{"1948-1965", "1964-1969"}, outs)
425
426 ok, err = dc.SeekTo("more", 0)
427 require.NoError(t, err)
428 require.True(t, ok)
429 outs = []string{}
430 for ok && err == nil {
431 ok, err = dc.Scan(actions)
432 if err != io.EOF {
433 require.NoError(t, err)
434 }
435 if err == nil || err == io.EOF {
436 outs = append(outs, fmt.Sprintf("%v-%v", from, to))
437 }
438 }
439
440 assert.Equal(t, []string{"1975-1985"}, outs)
441 }
442
443 func TestPathActionSeekThenScanHetero(t *testing.T) {
444
445 j := []byte(`
446 {
447 "set": "cars",
448 "data": [
449 {
450 "make": "Porsche",
451 "model": "356 Coupé",
452 "years": { "from": 1948, "to": 1965}
453 },
454 ["other","random","stuff"],
455 {
456 "years": { "from": 1964, "to": 1969},
457 "make": "Ford",
458 "model": "GT40"
459 },
460 {},
461 "str",
462 {
463 "make": "Ferrari",
464 "model": "308 GTB",
465 "years": { "to": 1985, "from": 1975}
466 }
467 ],
468 "more": true
469 }
470 `)
471
472 dc := NewDecoder(bytes.NewBuffer(j))
473 ok, err := dc.SeekTo("data", 0)
474 require.NoError(t, err)
475 require.True(t, ok)
476
477 var from, to int
478 actions := &PathActions{}
479 actions.Add(func(d *Decoder) (err error) {
480 err = d.Decode(&from)
481 require.NoError(t, err)
482 return
483 }, "years", "from")
484 actions.Add(func(d *Decoder) (err error) {
485 err = d.Decode(&to)
486 require.NoError(t, err)
487 return
488 }, "years", "to")
489
490 outs := []string{}
491 for ok && err == nil {
492 ok, err = dc.Scan(actions)
493 if err != io.EOF {
494 require.NoError(t, err)
495 }
496 if (err == nil || err == io.EOF) && (from != 0 && to != 0) {
497 outs = append(outs, fmt.Sprintf("%v-%v", from, to))
498 from, to = 0, 0
499 }
500 }
501
502 assert.Equal(t, []string{"1948-1965", "1964-1969", "1975-1985"}, outs)
503 }
504
505 func TestPathActionNested(t *testing.T) {
506
507 j := []byte(`
508 {
509 "set": "cars",
510 "data": [
511 {
512 "make": "Porsche",
513 "model": "356 Coupé",
514 "years": { "from": 1948, "to": 1965}
515 },
516 {
517 "years": { "from": 1964, "to": 1969},
518 "make": "Ford",
519 "model": "GT40"
520 },
521 {
522 "make": "Ferrari",
523 "model": "308 GTB",
524 "years": { "to": 1985, "from": 1975}
525 }
526 ],
527 "more": true
528 }
529 `)
530
531 var from, to int
532 caractions := &PathActions{}
533 caractions.Add(func(d *Decoder) (err error) {
534 err = d.Decode(&from)
535 require.NoError(t, err)
536 return
537 }, "years", "from")
538 caractions.Add(func(d *Decoder) (err error) {
539 err = d.Decode(&to)
540 require.NoError(t, err)
541 return
542 }, "years", "to")
543
544 outs := []string{}
545
546 actions := &PathActions{}
547 actions.Add(func(d *Decoder) error {
548
549 _, err := d.Scan(caractions)
550 if err != nil {
551 return err
552 }
553 outs = append(outs, fmt.Sprintf("%v-%v", from, to))
554 return nil
555
556 }, "data", AnyIndex)
557
558 ok, err := NewDecoder(bytes.NewBuffer(j)).Scan(actions)
559 assert.NoError(t, err)
560 assert.False(t, ok)
561
562 assert.Equal(t, []string{"1948-1965", "1964-1969", "1975-1985"}, outs)
563 }
564
View as plain text