Cpanel-JSON-XS
view release on metacpan or search on metacpan
4.07 2018-11-02 (rurban)
- Silence Gconvert -Wunused-result.
gcvt returns a string, sprintf int, so suppress the retval
4.06 2018-08-22 (rurban)
- Fix overloaded eq/ne comparisons (GH #116 by demerphq, GH #117 by Graham Knopp):
detect strings, protect from endless recursion. false is now ne "True".
clarify eq/ne rules in the docs.
4.05 2018-08-19 (rurban)
- Set decoded type (PR #115 by Pali)
- Add json_type_weaken (PR #114 by Pali)
- Fix tests for 5.6 (rurban, pali)
4.04 2018-06-22 (rurban)
- Fix bignum NaN/inf handling (#78 reported by Slaven Rezic)
- Move author tests to xt/ as suggested in #106, added a make xtest target.
Fixes a test fail with ASAN.
4.03 2018-06-21 (rurban)
- Add sereal cpanel_json_xs type (#110 James Rouzier)
comparison:
"utf8" controls whether the JSON text created by "encode" (and expected
by "decode") is UTF-8 encoded or not, while "latin1" and "ascii" only
control whether "encode" escapes character values outside their
respective codeset range. Neither of these flags conflict with each
other, although some combinations make less sense than others.
Care has been taken to make all flags symmetrical with respect to
"encode" and "decode", that is, texts encoded with any combination of
these flag values will be correctly decoded when the same flags are used
- in general, if you use different flag settings while encoding vs. when
decoding you likely have a bug somewhere.
Below comes a verbose discussion of these flags. Note that a "codeset"
is simply an abstract set of character-codepoint pairs, while an
encoding takes those codepoint numbers and *encodes* them, in our case
into octets. Unicode is (among other things) a codeset, UTF-8 is an
encoding, and ISO-8859-1 (= latin 1) and ASCII are both codesets *and*
encodings at the same time, which can be confusing.
"utf8" flag disabled
When "utf8" is disabled (the default), then "encode"/"decode"
generate and expect Unicode strings, that is, characters with high
ordinal Unicode values (> 255) will be encoded as such characters,
and likewise such characters are decoded as-is, no changes to them
will be done, except "(re-)interpreting" them as Unicode codepoints
or Unicode characters, respectively (to Perl, these are the same
thing in strings unless you do funny/weird/dumb stuff).
This is useful when you want to do the encoding yourself (e.g. when
you want to have UTF-16 encoded JSON texts) or when some other layer
does the encoding for you (for example, when printing to a terminal
using a filehandle that transparently encodes to UTF-8 you certainly
do NOT want to UTF-8 encode your data first and have Perl encode it
another time).
is a short comparison:
C<utf8> controls whether the JSON text created by C<encode> (and expected
by C<decode>) is UTF-8 encoded or not, while C<latin1> and C<ascii> only
control whether C<encode> escapes character values outside their respective
codeset range. Neither of these flags conflict with each other, although
some combinations make less sense than others.
Care has been taken to make all flags symmetrical with respect to
C<encode> and C<decode>, that is, texts encoded with any combination of
these flag values will be correctly decoded when the same flags are used
- in general, if you use different flag settings while encoding vs. when
decoding you likely have a bug somewhere.
Below comes a verbose discussion of these flags. Note that a "codeset" is
simply an abstract set of character-codepoint pairs, while an encoding
takes those codepoint numbers and I<encodes> them, in our case into
octets. Unicode is (among other things) a codeset, UTF-8 is an encoding,
and ISO-8859-1 (= latin 1) and ASCII are both codesets I<and> encodings at
the same time, which can be confusing.
=over 4
=item C<utf8> flag disabled
When C<utf8> is disabled (the default), then C<encode>/C<decode> generate
and expect Unicode strings, that is, characters with high ordinal Unicode
values (> 255) will be encoded as such characters, and likewise such
characters are decoded as-is, no changes to them will be done, except
"(re-)interpreting" them as Unicode codepoints or Unicode characters,
respectively (to Perl, these are the same thing in strings unless you do
funny/weird/dumb stuff).
This is useful when you want to do the encoding yourself (e.g. when you
want to have UTF-16 encoded JSON texts) or when some other layer does
the encoding for you (for example, when printing to a terminal using a
filehandle that transparently encodes to UTF-8 you certainly do NOT want
to UTF-8 encode your data first and have Perl encode it another time).
t/110_bignum.t view on Meta::CPAN
unless $ENV{PERL_TEST_DEVEL};
for (@DOS_DIGITS) {
my $s = $_;
my $digits = $s;
$digits =~ s/_//g;
# perl throws "Out of memory!" when constructing a string with 100_000_000_000 digits
my $dos = '1' . '0' x $digits;
note "decode bigint DOS attack with $s digits";
# perl throws "Killed" with a bignum of about 1_000_000_000 digits
my $num = $json->decode($dos);
is($num->bcmp($dos), 0, "decoded $s digits")
or Dump ($num);
}
}
t/122_type_encode.t view on Meta::CPAN
is($type_spec->{b}, $orig_b, "type_spec->{b} unchanged after loop encode");
}
is($results[0], '{"a":"0.0","b":1}', 'loop encode result 1 correct');
is($results[1], '{"a":null,"b":2}', 'loop encode result 2 correct (null)');
is($results[2], '{"a":"hello","b":3}', 'loop encode result 3 correct');
is($results[3], '{"a":null,"b":4}', 'loop encode result 4 correct (null)');
is($results[4], '{"a":"0.0","b":5}', 'loop encode result 5 correct');
}
# type_spec loaded via raw integer values (as if decoded from a JSON config file)
{
my $type_spec = Cpanel::JSON::XS->new->decode('{"a":260,"b":2}');
is($type_spec->{a}, JSON_TYPE_STRING_OR_NULL, 'decoded type value matches JSON_TYPE_STRING_OR_NULL');
is($type_spec->{b}, JSON_TYPE_INT, 'decoded type value matches JSON_TYPE_INT');
my $result = $cjson->encode({ a => "test", b => 42 }, $type_spec);
is($result, '{"a":"test","b":42}', 'encode with decoded-integer type_spec works');
is($type_spec->{a}, JSON_TYPE_STRING_OR_NULL, 'type_spec unchanged after encode with decoded-integer types');
is($type_spec->{b}, JSON_TYPE_INT, 'type_spec b unchanged after encode with decoded-integer types');
}
t/19_incr.t view on Meta::CPAN
# allow_singlequote: } inside single-quoted string must not close the object
{
my $coder = Cpanel::JSON::XS->new->allow_singlequote(1);
# feed partial input: the } is inside the single-quoted value, must not trigger done
ok (!defined $coder->incr_parse("{'a':'}'"), "sqstr-incr: } inside single-quote does not close object");
# complete the object
my $r = $coder->incr_parse("}");
ok (defined $r, "sqstr-incr: object completes after closing brace");
is_deeply ($r, {a => "}"}, "sqstr-incr: decoded value correct");
}
# allow_singlequote: chunked streaming with structural chars inside single-quoted string
{
my $coder = Cpanel::JSON::XS->new->allow_singlequote(1);
# feed one byte at a time to exercise every state transition
my $json = "{'x':'}[{'}";
my $r;
for my $ch (split //, $json) {
$r = $coder->incr_parse($ch);
}
ok (defined $r, "sqstr-incr chunked: defined result");
is_deeply ($r, {x => "}[{"}, "sqstr-incr chunked: decoded value correct");
}
# allow_singlequote: backslash inside single-quoted string does not cause premature end
{
my $coder = Cpanel::JSON::XS->new->allow_singlequote(1);
ok (!defined $coder->incr_parse("{'k':'a\\'"), "sqstr-incr BS: partial with escaped quote waits");
my $r = $coder->incr_parse("b'}");
ok (defined $r, "sqstr-incr BS: completes after full input");
is_deeply ($r, {k => "a'b"}, "sqstr-incr BS: decoded value correct");
}
# allow_singlequote: single-quoted array element containing structural chars
{
my $coder = Cpanel::JSON::XS->new->allow_singlequote(1);
my $r;
$r = $coder->incr_parse("['he");
ok (!defined $r, "sqstr-incr array: partial waits");
$r = $coder->incr_parse("llo}']");
ok (defined $r, "sqstr-incr array: completes");
t/25_boolean.t view on Meta::CPAN
$js = $unblessed_bool_cjson->decode($boolfalse);
SKIP: {
skip "no Scalar::Util in $]", 1 unless $have_blessed;
ok(!blessed($js->{is_false}), "->unblessed_bool for JSON false does not return blessed object");
}
cmp_ok($js->{is_false}, "==", 0, "->unblessed_bool for JSON false returns correct Perl bool value");
cmp_ok($js->{is_false}, "eq", "", "->unblessed_bool for JSON false returns correct Perl bool value");
is($unblessed_bool_cjson->encode(do { my $struct = $unblessed_bool_cjson->decode($truefalse, my $types); ($struct, $types) }), $truefalse, "encode(decode(boolean)) is identity with ->unblessed_bool");
is($cjson->encode(do { my $struct = $unblessed_bool_cjson->decode($truefalse, my $types); ($struct, $types) }), $truefalse, "booleans decoded by ->unblessed_bool(1) are encoded by ->unblessed_bool(0) in the same way");
$js = $unblessed_bool_cjson->decode($truefalse);
ok eval { $js->[0] = "new value 0" }, "decoded 'true' is modifiable" or diag($@);
ok eval { $js->[1] = "new value 1" }, "decoded 'false' is modifiable" or diag($@);
# GH #207: boolean eq/ne must not match undef (which stringifies to "")
# NOTE: we intentionally differ from JSON::PP by accepting "false" and ""
# as eq to false, and "true" as eq to true (semantic boolean matching).
ok(!($false eq undef), 'false ne undef via eq'); # the bug fix
ok(!($true eq undef), 'true ne undef via eq');
ok( $false eq "", q{false eq "" via eq}); # intentional: !!0 / SV_NO
ok( $false eq "false", q{false eq "false" via eq}); # intentional: semantic
ok( $true eq "true", q{true eq "true" via eq}); # intentional: semantic
t/96_mojo.t view on Meta::CPAN
" \$Cpanel::JSON::XS::VERSION=$Cpanel::JSON::XS::VERSION";
$js = Mojo::JSON::decode_json( $boolfalse );
is( $cjson->encode( $js ), $boolfalse, 'can encode Mojo false' );
is( $js->{is_false}, 0 ,'false == 0');
ok( !$js->{is_false}, 'ok !false');
my $mj = Mojo::JSON::encode_json( $yesno );
$js = $cjson->decode( $mj );
ok( !$js->[0], 'decoded Mojo false is false' );
ok( $js->[0] == 0, 'decoded Mojo false is zero' );
ok( $js->[0] eq "", 'decoded Mojo false is empty string' );
ok( $js->[1], 'decoded Mojo true is true' );
ok( $js->[1] == 1, 'decoded Mojo true is one' );
ok( $js->[1] eq "1", 'decoded Mojo true is "1" string' );
( run in 2.131 seconds using v1.01-cache-2.11-cpan-df04353d9ac )