@@ -290,3 +290,219 @@ func TestTokenizer(t *testing.T) {
290290 })
291291 }
292292}
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