@@ -290,3 +290,219 @@ func TestTokenizer(t *testing.T) {
290
290
})
291
291
}
292
292
}
293
+
294
+ func TestTokenizer_NoPanic (t * testing.T ) {
295
+ testCases := []struct {
296
+ name string
297
+ path string
298
+ }{
299
+ {name : "identity" , path : "" },
300
+ {name : "root" , path : "$" },
301
+ {name : "unmatched closing parenthesis" , path : ")" },
302
+ {name : "unmatched closing square bracket" , path : "]" },
303
+ {name : "dot child" , path : "$.child" },
304
+ {name : "dot child with implicit root" , path : ".child" },
305
+ {name : "undotted child with implicit root" , path : "child" },
306
+ {name : "dot child with no name" , path : "$." },
307
+ {name : "dot child with missing dot" , path : "$a" },
308
+ {name : "dot child with trailing dot" , path : "$.child." },
309
+ {name : "dot child of dot child" , path : "$.child1.child2" },
310
+ {name : "dot child with array subscript" , path : "$.child[*]" },
311
+ {name : "dot child with malformed array subscript" , path : "$.child[1:2:3:4]" },
312
+ {name : "dot child with array subscript with zero step" , path : "$.child[1:2:0]" },
313
+ {name : "dot child with non-integer array subscript" , path : "$.child[1:2:a]" },
314
+ {name : "dot child with unclosed array subscript" , path : "$.child[*" },
315
+ {name : "dot child with missing array subscript" , path : "$.child[]" },
316
+ {name : "dot child with embedded space" , path : "$.child more" },
317
+ {name : "bracket child" , path : "$['child']" },
318
+ {name : "bracket child with double quotes" , path : `$["child"]` },
319
+ {name : "bracket child with unmatched quotes" , path : `$["child']` },
320
+ {name : "bracket child with empty name" , path : "$['']" },
321
+ {name : "bracket child of bracket child" , path : "$['child1']['child2']" },
322
+ {name : "double quoted bracket child of bracket child" , path : `$['child1']["child2"]` },
323
+ {name : "bracket child union" , path : "$['child','child2']" },
324
+ {name : "bracket child union with whitespace" , path : "$[ 'child' , 'child2' ]" },
325
+ {name : "bracket child union with mixed quotes" , path : `$[ 'child' , "child2" ]` },
326
+ {name : "bracket child quoted union literal" , path : "$[',']" },
327
+ {name : "bracket child with array subscript" , path : "$['child'][*]" },
328
+ {name : "bracket child with malformed array subscript" , path : "$['child'][1:2:3:4]" },
329
+ {name : "bracket child with non-integer array subscript" , path : "$['child'][1:2:a]" },
330
+ {name : "bracket child with unclosed array subscript" , path : "$['child'][*" },
331
+ {name : "bracket child with missing array subscript" , path : "$['child'][]" },
332
+ {name : "bracket child followed by space" , path : "$['child'] " },
333
+ {name : "bracket dotted child" , path : "$['child1.child2']" },
334
+ {name : "bracket child with array subscript" , path : "$['child'][*]" },
335
+ {name : "property name dot child" , path : "$.child~" },
336
+ {name : "property name dot child with implicit root" , path : ".child~" },
337
+ {name : "property name undotted child with implicit root" , path : "child~" },
338
+ {name : "property name dot child with no name" , path : "$.~" },
339
+ {name : "property name dot child with missing dot" , path : "$a~" },
340
+ {name : "property name dot child with trailing chars" , path : "$.child~.test" },
341
+ {name : "property name undotted child with trailing chars" , path : "child~.test" },
342
+ {name : "property name dot child with trailing dot" , path : "$.child.~" },
343
+ {name : "property name dot child of dot child" , path : "$.child1.child2~" },
344
+ {name : "property name dot child with wildcard array subscript" , path : "$.child[*]~" },
345
+ {name : "property name dot child with an array subscript" , path : "$.child[0]~" },
346
+ {name : "property name dot child with array subscript with zero step" , path : "$.child[1:2:0]~" },
347
+ {name : "property name dot child with non-integer array subscript" , path : "$.child[1:2:a]~" },
348
+ {name : "property name dot child with unclosed array subscript" , path : "$.child[*~" },
349
+ {name : "property name dot child with missing array subscript" , path : "$.child[]~" },
350
+ {name : "property name dot child with embedded space" , path : "$.child more~" },
351
+ {name : "property name bracket child" , path : "$['child']~" },
352
+ {name : "property name bracket child with double quotes" , path : `$["child"]~` },
353
+ {name : "property name bracket child with unmatched quotes" , path : `$["child']~` },
354
+ {name : "property name bracket child with empty name" , path : "$['']~" },
355
+ {name : "property name bracket child of bracket child" , path : "$['child1']['child2']~" },
356
+ {name : "property name double quoted bracket child of bracket child" , path : `$['child1']["child2"]~` },
357
+ {name : "property name bracket child union" , path : "$['child','child2']~" },
358
+ {name : "property name bracket child union with whitespace" , path : "$[ 'child' , 'child2' ]~" },
359
+ {name : "property name bracket child union with mixed quotes" , path : `$[ 'child' , "child2" ]~` },
360
+ {name : "property name bracket child quoted union literal" , path : "$[',']~" },
361
+ {name : "property name bracket child with wildcard array subscript" , path : "$['child'][*]~" },
362
+ {name : "property name bracket child with wildcard array subscript and trailing chars" , path : "$['child'][*]~.child" },
363
+ {name : "property name bracket child with ~ in name" , path : "$['child~']~" },
364
+ {name : "bracket child with array subscript" , path : "$['child'][1]~" },
365
+ {name : "property name bracket child with non-integer array subscript" , path : "$['child'][1:2:a]~" },
366
+ {name : "property name bracket child with unclosed array subscript" , path : "$['child'][*~" },
367
+ {name : "property name bracket child with missing array subscript" , path : "$['child'][]~" },
368
+ {name : "property name bracket child separated a by space" , path : "$['child'] ~" },
369
+ {name : "property name bracket child followed by space" , path : "$['child']~ " },
370
+ {name : "property name bracket dotted child" , path : "$['child1.child2']~" },
371
+ {name : "array union" , path : "$[0,1]" },
372
+ {name : "array union with whitespace" , path : "$[ 0 , 1 ]" },
373
+ {name : "bracket child with malformed array subscript" , path : "$['child'][1:2:3:4]" },
374
+ {name : "bracket child with malformed array subscript in union" , path : "$['child'][0,1:2:3:4]" },
375
+ {name : "bracket child with non-integer array subscript" , path : "$['child'][1:2:a]" },
376
+ {name : "bracket child of dot child" , path : "$.child1['child2']" },
377
+ {name : "array slice of root" , path : "$[1:3]" },
378
+ {name : "dot child of bracket child" , path : "$['child1'].child2" },
379
+ {name : "recursive descent" , path : "$..child" },
380
+ {name : "recursive descent of dot child" , path : "$.child1..child2" },
381
+ {name : "recursive descent of bracket child" , path : "$['child1']..child2" },
382
+ {name : "repeated recursive descent" , path : "$..child1..child2" },
383
+ {name : "recursive descent with dot child" , path : "$..child1.child2" },
384
+ {name : "recursive descent with bracket child" , path : "$..child1['child2']" },
385
+ {name : "recursive descent with missing name" , path : "$.." },
386
+ {name : "recursive descent with array access" , path : "$..[0]" },
387
+ {name : "recursive descent with filter" , path : "$..[?(@.child)]" },
388
+ {name : "recursive descent with bracket child" , path : "$..['child']" },
389
+ {name : "recursive descent with double quoted bracket child" , path : `$..["child"]` },
390
+ {name : "wildcarded children" , path : "$.*" },
391
+ {name : "simple filter" , path : "$[?(@.child)]" },
392
+ {name : "simple filter with leading whitespace" , path : "$[?( @.child)]" },
393
+ {name : "simple filter with trailing whitespace" , path : "$[?( @.child )]" },
394
+ {name : "simple filter with bracket" , path : "$[?((@.child))]" },
395
+ {name : "simple filter with bracket with extra whitespace" , path : "$[?( ( @.child ) )]" },
396
+ {name : "simple filter with more complex subpath" , path : "$[?((@.child[0]))]" },
397
+ {name : "missing filter " , path : "$[?()]" },
398
+ {name : "unclosed filter" , path : "$[?(" },
399
+ {name : "filter with missing operator" , path : "$[?(@.child @.other)]" },
400
+ {name : "filter with malformed term" , path : "$[?([)]" },
401
+ {name : "filter with misplaced open bracket" , path : "$[?(@.child ()]" },
402
+ {
name :
"simple negative filter" ,
path :
"$[?([email protected] )]" },
403
+ {
name :
"misplaced filter negation" ,
path :
"$[?(@.child [email protected] )]" },
404
+ {name : "simple negative filter with extra whitespace" , path : "$[?( ! @.child)]" },
405
+ {name : "simple filter with root expression" , path : "$[?($.child)]" },
406
+ {name : "filter integer equality, literal on the right" , path : "$[?(@.child==1)]" },
407
+ {name : "filter string equality, literal on the right" , path : "$[?(@.child=='x')]" },
408
+ {name : "filter string equality with apparent boolean" , path : `$[?(@.child=="true")]` },
409
+ {name : "filter string equality with apparent null" , path : `$[?(@.child=="null")]` },
410
+ {name : "filter string equality, double-quoted literal on the right" , path : `$[?(@.child=="x")]` },
411
+ {name : "filter integer equality with invalid literal" , path : "$[?(@.child==-)]" },
412
+ {name : "filter integer equality with integer literal which is too large" , path : "$[?(@.child==9223372036854775808)]" },
413
+ {name : "filter integer equality with invalid float literal" , path : "$[?(@.child==1.2.3)]" },
414
+ {name : "filter integer equality with invalid string literal" , path : "$[?(@.child=='x)]" },
415
+ {
name :
"filter integer equality, literal on the left" ,
path :
"$[?([email protected] )]" },
416
+ {
name :
"filter float equality, literal on the left" ,
path :
"$[?([email protected] )]" },
417
+ {
name :
"filter fractional float equality, literal on the left" ,
path :
"$[?([email protected] )]" },
418
+ {name : "filter fractional float equality, literal on the right" , path : "$[?(@.child== -1.5e-1 )]" },
419
+ {name : "filter boolean true equality, literal on the right" , path : "$[?(@.child== true )]" },
420
+ {name : "filter boolean false equality, literal on the right" , path : "$[?(@.child==false)]" },
421
+ {
name :
"filter boolean true equality, literal on the left" ,
path :
"$[?([email protected] )]" },
422
+ {
name :
"filter boolean false equality, literal on the left" ,
path :
"$[?( false [email protected] )]" },
423
+ {name : "filter null equality, literal on the right" , path : "$[?(@.child==null)]" },
424
+ {
name :
"filter null true equality, literal on the left" ,
path :
"$[?([email protected] )]" },
425
+ {
name :
"filter equality with missing left hand value" ,
path :
"$[?([email protected] )]" },
426
+ {
name :
"filter equality with missing left hand value inside bracket" ,
path :
"$[?(([email protected] ))]" },
427
+ {name : "filter equality with missing right hand value" , path : "$[?(@.child==)]" },
428
+ {name : "filter integer equality, root path on the right" , path : "$[?(@.child==$.x)]" },
429
+ {
name :
"filter integer equality, root path on the left" ,
path :
"$[?([email protected] )]" },
430
+ {name : "filter string equality, literal on the right" , path : "$[?(@.child=='x')]" },
431
+ {
name :
"filter string equality, literal on the left" ,
path :
"$[?('x'[email protected] )]" },
432
+ {
name :
"filter string equality, literal on the left with unmatched string delimiter" ,
path :
"$[?('[email protected] )]" },
433
+ {name : "filter string equality with unmatched string delimiter" , path : "$[?(@.child=='x)]" },
434
+ {name : "filter integer inequality, literal on the right" , path : "$[?(@.child!=1)]" },
435
+ {name : "filter inequality with missing left hand operator" , path : "$[?(!=1)]" },
436
+ {name : "filter equality with missing right hand value" , path : "$[?(@.child!=)]" },
437
+ {name : "filter greater than, integer literal on the right" , path : "$[?(@.child>1)]" },
438
+ {name : "filter greater than, decimal literal on the right" , path : "$[?(@.child> 1.5)]" },
439
+ {name : "filter greater than, path to path" , path : "$[?(@.child1>@.child2)]" },
440
+ {name : "filter greater than with left hand operand missing" , path : "$[?(>1)]" },
441
+ {name : "filter greater than with missing right hand value" , path : "$[?(@.child>)]" },
442
+ {name : "filter greater than, string on the right" , path : "$[?(@.child>'x')]" },
443
+ {name : "filter greater than, string on the left" , path : "$[?('x'>@.child)]" },
444
+ {name : "filter greater than or equal, integer literal on the right" , path : "$[?(@.child>=1)]" },
445
+ {name : "filter greater than or equal, decimal literal on the right" , path : "$[?(@.child>=1.5)]" },
446
+ {name : "filter greater than or equal with left hand operand missing" , path : "$[?(>=1)]" },
447
+ {name : "filter greater than or equal with missing right hand value" , path : "$[?(@.child>=)]" },
448
+ {name : "filter greater than or equal, string on the right" , path : "$[?(@.child>='x')]" },
449
+ {
name :
"filter greater than or equal, string on the left" ,
path :
"$[?('x'>[email protected] )]" },
450
+ {name : "filter less than, integer literal on the right" , path : "$[?(@.child<1)]" },
451
+ {name : "filter less than, decimal literal on the right" , path : "$[?(@.child< 1.5)]" },
452
+ {name : "filter less than with left hand operand missing" , path : "$[?(<1)]" },
453
+ {name : "filter less than with missing right hand value" , path : "$[?(@.child<)]" },
454
+ {name : "filter less than, string on the right" , path : "$[?(@.child<'x')]" },
455
+ {name : "filter less than, string on the left" , path : "$[?('x'<@.child)]" },
456
+ {name : "filter less than or equal, integer literal on the right" , path : "$[?(@.child<=1)]" },
457
+ {name : "filter less than or equal, decimal literal on the right" , path : "$[?(@.child<=1.5)]" },
458
+ {name : "filter less than or equal with left hand operand missing" , path : "$[?(<=1)]" },
459
+ {name : "filter less than or equal with missing right hand value" , path : "$[?(@.child<=)]" },
460
+ {name : "filter less than or equal, string on the right" , path : "$[?(@.child<='x')]" },
461
+ {
name :
"filter less than or equal, string on the left" ,
path :
"$[?('x'<[email protected] )]" },
462
+ {name : "filter conjunction" , path : "$[?(@.child&&@.other)]" },
463
+ {name : "filter conjunction with literals and whitespace" , path : "$[?(@.child == 'x' && -9 == @.other)]" },
464
+ {name : "filter conjunction with bracket children" , path : "$[?(@['child'][*]&&@['other'])]" },
465
+ {name : "filter invalid leading conjunction" , path : "$[?(&&" },
466
+ {name : "filter conjunction with extra whitespace" , path : "$[?(@.child && @.other)]" },
467
+ {name : "filter disjunction" , path : "$[?(@.child||@.other)]" },
468
+ {name : "filter invalid leading disjunction" , path : "$[?(||" },
469
+ {name : "filter disjunction with extra whitespace" , path : "$[?(@.child || @.other)]" },
470
+ {name : "simple filter of child" , path : "$.child[?(@.child)]" },
471
+ {name : "filter with missing end" , path : "$[?(@.child" },
472
+ {name : "nested filter (edge case)" , path : "$[?(@.y[?(@.z)])]" },
473
+ {
name :
"filter negation" ,
path :
"$[?([email protected] )]" },
474
+ {
name :
"filter negation of comparison (edge case)" ,
path :
"$[?([email protected] >1)]" },
475
+ {name : "filter negation of bracket" , path : "$[?(!(@.child))]" },
476
+ {name : "filter regular expression" , path : "$[?(@.child=~/.*/)]" },
477
+ {name : "filter regular expression with escaped /" , path : `$[?(@.child=~/\/.*/)]` },
478
+ {name : "filter regular expression with escaped \\ " , path : `$[?(@.child=~/\\/)]` },
479
+ {name : "filter regular expression with missing leading /" , path : `$[?(@.child=~.*/)]` },
480
+ {name : "filter regular expression with missing trailing /" , path : `$[?(@.child=~/.*)]` },
481
+ {name : "filter regular expression to match string literal" , path : `$[?('x'=~/.*/)]` },
482
+ {name : "filter regular expression to match integer literal" , path : `$[?(0=~/.*/)]` },
483
+ {name : "filter regular expression to match float literal" , path : `$[?(.1=~/.*/)]` },
484
+ {name : "filter invalid regular expression" , path : `$[?(@.child=~/(.*/)]` },
485
+ {name : "unescaped single quote in bracket child name" , path : `$['single'quote']` },
486
+ {name : "escaped single quote in bracket child name" , path : `$['single\']quote']` },
487
+ {name : "escaped backslash in bracket child name" , path : `$['\\']` },
488
+ {name : "unescaped single quote after escaped backslash in bracket child name" , path : `$['single\\'quote']` },
489
+ {name : "unsupported escape sequence in bracket child name" , path : `$['\n']` },
490
+ {name : "unclosed and empty bracket child name with space" , path : `$[ '` },
491
+ {name : "unclosed and empty bracket child name with formfeed" , path : "[\f '" },
492
+ {name : "filter involving value of current node on left hand side" , path : "$[?(@==1)]" },
493
+ {name : "filter involving value of current node on right hand side" , path : "$[?(1==@ || 2== @ )]" },
494
+ }
495
+
496
+ for _ , tc := range testCases {
497
+ t .Run (tc .name , func (t * testing.T ) {
498
+ defer func () {
499
+ if r := recover (); r != nil {
500
+ t .Errorf ("Tokenizer panicked for path: %s\n Panic: %v" , tc .path , r )
501
+ }
502
+ }()
503
+
504
+ tokenizer := NewTokenizer (tc .path )
505
+ _ = tokenizer .Tokenize ()
506
+ })
507
+ }
508
+ }
0 commit comments