@ -1,3 +1,9 @@
# Copyright (c) 2021-2024, PostgreSQL Global Development Group
# Test success or failure of the incremental (table-driven) JSON parser
# for a variety of small inputs.
use strict ;
use warnings ;
@ -6,6 +12,8 @@ use Test::More;
use File::Temp qw( tempfile ) ;
my $ dir = PostgreSQL::Test::Utils:: tempdir ;
sub test
{
local $ Test:: Builder:: Level = $ Test:: Builder:: Level + 1 ;
@ -14,27 +22,32 @@ sub test
my $ exe = "test_json_parser_incremental" ;
my $ chunk = length ( $ json ) ;
# Test the input with chunk sizes from max(input_size, 64) down to 1
if ( $ chunk > 64 )
{
$ chunk = 64 ;
}
my ( $ fh , $ fname ) = tempfile ( UNLINK = > 1 ) ;
my ( $ fh , $ fname ) = tempfile ( DIR = > $ dir ) ;
print $ fh "$json" ;
close ( $ fh ) ;
foreach my $ size ( reverse ( 1 .. $ chunk ) )
foreach my $ size ( reverse ( 1 .. $ chunk ) )
{
my ( $ stdout , $ stderr ) = run_command ( [ $ exe , "-c" , $ size , $ fname ] ) ;
my ( $ stdout , $ stderr ) = run_command ( [ $ exe , "-c" , $ size , $ fname ] ) ;
if ( defined ( $ params { error } ) )
{
unlike ( $ stdout , qr/SUCCESS/ , "$name, chunk size $size: test fails" ) ;
like ( $ stderr , $ params { error } , "$name, chunk size $size: correct error output" ) ;
unlike ( $ stdout , qr/SUCCESS/ ,
"$name, chunk size $size: test fails" ) ;
like ( $ stderr , $ params { error } ,
"$name, chunk size $size: correct error output" ) ;
}
else
{
like ( $ stdout , qr/SUCCESS/ , "$name, chunk size $size: test succeeds" ) ;
like ( $ stdout , qr/SUCCESS/ ,
"$name, chunk size $size: test succeeds" ) ;
is ( $ stderr , "" , "$name, chunk size $size: no error output" ) ;
}
}
@ -58,26 +71,60 @@ test("serial escapes", '"\\\\\\\\\\\\\\\\"');
test ( "interrupted escapes" , '"\\\\\\"\\\\\\\\\\"\\\\"' ) ;
test ( "whitespace" , ' "" ' ) ;
test ( "unclosed empty object" , "{" , error = > qr/input string ended unexpectedly/ ) ;
test ( "unclosed empty object" ,
"{" , error = > qr/input string ended unexpectedly/ ) ;
test ( "bad key" , "{{" , error = > qr/Expected string or "}", but found "\{"/ ) ;
test ( "bad key" , "{{}" , error = > qr/Expected string or "}", but found "\{"/ ) ;
test ( "numeric key" , "{1234: 2}" , error = > qr/Expected string or "}", but found "1234"/ ) ;
test ( "second numeric key" , '{"a": "a", 1234: 2}' , error = > qr/Expected string, but found "1234"/ ) ;
test ( "unclosed object with pair" , '{"key": "value"' , error = > qr/input string ended unexpectedly/ ) ;
test ( "missing key value" , '{"key": }' , error = > qr/Expected JSON value, but found "}"/ ) ;
test ( "missing colon" , '{"key" 12345}' , error = > qr/Expected ":", but found "12345"/ ) ;
test ( "missing comma" , '{"key": 12345 12345}' , error = > qr/Expected "," or "}", but found "12345"/ ) ;
test ( "overnested array" , "[" x 6401 , error = > qr/maximum permitted depth is 6400/ ) ;
test ( "overclosed array" , "[]]" , error = > qr/Expected end of input, but found "]"/ ) ;
test ( "unexpected token in array" , "[ }}} ]" , error = > qr/Expected array element or "]", but found "}"/ ) ;
test ( "numeric key" , "{1234: 2}" ,
error = > qr/Expected string or "}", but found "1234"/ ) ;
test (
"second numeric key" ,
'{"a": "a", 1234: 2}' ,
error = > qr/Expected string, but found "1234"/ ) ;
test (
"unclosed object with pair" ,
'{"key": "value"' ,
error = > qr/input string ended unexpectedly/ ) ;
test ( "missing key value" ,
'{"key": }' , error = > qr/Expected JSON value, but found "}"/ ) ;
test (
"missing colon" ,
'{"key" 12345}' ,
error = > qr/Expected ":", but found "12345"/ ) ;
test (
"missing comma" ,
'{"key": 12345 12345}' ,
error = > qr/Expected "," or "}", but found "12345"/ ) ;
test ( "overnested array" ,
"[" x 6401 , error = > qr/maximum permitted depth is 6400/ ) ;
test ( "overclosed array" ,
"[]]" , error = > qr/Expected end of input, but found "]"/ ) ;
test ( "unexpected token in array" ,
"[ }}} ]" , error = > qr/Expected array element or "]", but found "}"/ ) ;
test ( "junk punctuation" , "[ ||| ]" , error = > qr/Token "|" is invalid/ ) ;
test ( "missing comma in array" , "[123 123]" , error = > qr/Expected "," or "]", but found "123"/ ) ;
test ( "missing comma in array" ,
"[123 123]" , error = > qr/Expected "," or "]", but found "123"/ ) ;
test ( "misspelled boolean" , "tru" , error = > qr/Token "tru" is invalid/ ) ;
test ( "misspelled boolean in array" , "[tru]" , error = > qr/Token "tru" is invalid/ ) ;
test ( "smashed top-level scalar" , "12zz" , error = > qr/Token "12zz" is invalid/ ) ;
test ( "smashed scalar in array" , "[12zz]" , error = > qr/Token "12zz" is invalid/ ) ;
test ( "unknown escape sequence" , '"hello\vworld"' , error = > qr/Escape sequence "\\v" is invalid/ ) ;
test ( "unescaped control" , "\"hello\tworld\"" , error = > qr/Character with value 0x09 must be escaped/ ) ;
test ( "incorrect escape count" , '"\\\\\\\\\\\\\\"' , error = > qr/Token ""\\\\\\\\\\\\\\"" is invalid/ ) ;
test (
"misspelled boolean in array" ,
"[tru]" ,
error = > qr/Token "tru" is invalid/ ) ;
test ( "smashed top-level scalar" , "12zz" ,
error = > qr/Token "12zz" is invalid/ ) ;
test (
"smashed scalar in array" ,
"[12zz]" ,
error = > qr/Token "12zz" is invalid/ ) ;
test (
"unknown escape sequence" ,
'"hello\vworld"' ,
error = > qr/Escape sequence "\\v" is invalid/ ) ;
test ( "unescaped control" ,
"\"hello\tworld\"" ,
error = > qr/Character with value 0x09 must be escaped/ ) ;
test (
"incorrect escape count" ,
'"\\\\\\\\\\\\\\"' ,
error = > qr/Token ""\\\\\\\\\\\\\\"" is invalid/ ) ;
done_testing ( ) ;