Current section

Files

Jump to
jiffy test jiffy_16_dedupe_keys_tests.erl
Raw

test/jiffy_16_dedupe_keys_tests.erl

% This file is part of Jiffy released under the MIT license.
% See the LICENSE file for more information.
-module(jiffy_16_dedupe_keys_tests).
-include_lib("eunit/include/eunit.hrl").
-include("jiffy_util.hrl").
% Duplicate keys with `return_maps`. We settled on
% last value wins semantics in such cases so test that
% we preserve that
%
duplicate_keys_maps_test_() ->
Opts = [return_maps],
Cases = [
% Simple duplicate
{
<<"{\"a\":1,\"a\":2}">>,
#{<<"a">> => 2}
},
% Duplicate with other keys
{
<<"{\"a\":1,\"b\":2,\"a\":3}">>,
#{<<"a">> => 3, <<"b">> => 2}
},
% Triple duplicate
{
<<"{\"x\":1,\"x\":2,\"x\":3}">>,
#{<<"x">> => 3}
},
% Duplicate in nested object
{
<<"{\"outer\":{\"k\":1,\"k\":2}}">>,
#{<<"outer">> => #{<<"k">> => 2}}
},
% No duplicates
{
<<"{\"a\":1,\"b\":2,\"c\":3}">>,
#{<<"a">> => 1, <<"b">> => 2, <<"c">> => 3}
}
],
{"Test duplicate keys with maps", lists:map(fun({Json, Result}) ->
?_assertEqual(Result, jiffy:decode(Json, Opts))
end, Cases)}.
dedupe_keys_test_() ->
Opts = [dedupe_keys],
Cases = [
% Simple sanity check
{
{[{<<"foo">>, 1}]},
{[{<<"foo">>, 1}]}
},
% Basic test
{
{[{<<"foo">>, 1}, {<<"foo">>, 2}]},
{[{<<"foo">>, 2}]}
},
% Non-repeated keys are fine
{
{[{<<"foo">>, 1}, {<<"bar">>, 2}]},
{[{<<"foo">>, 1}, {<<"bar">>, 2}]}
},
% Key order stays the same other than deduped keys
{
{[{<<"bar">>, 1}, {<<"foo">>, 2}, {<<"baz">>, 3}, {<<"foo">>, 4}]},
{[{<<"bar">>, 1}, {<<"baz">>, 3}, {<<"foo">>, 4}]}
},
% Multiple repeats are handled
{
{[{<<"foo">>, 1}, {<<"foo">>, 2}, {<<"foo">>, 3}]},
{[{<<"foo">>, 3}]}
},
% Sub-objects are covered
{
{[{<<"foo">>, {[{<<"bar">>, 1}, {<<"bar">>, 2}]}}]},
{[{<<"foo">>, {[{<<"bar">>, 2}]}}]}
},
% Objects in arrays are handled
{
[{[{<<"foo">>, 1}, {<<"foo">>, 2}]}],
[{[{<<"foo">>, 2}]}]
},
% Embedded NULL bytes are handled
{
{[{<<"foo\\u0000bar">>, 1}, {<<"foo\\u0000baz">>, 2}]},
{[{<<"foo\\u0000bar">>, 1}, {<<"foo\\u0000baz">>, 2}]}
},
% Can dedupe with embedded NULL bytes
{
{[{<<"foo\\u0000bar">>, 1}, {<<"foo\\u0000bar">>, 2}]},
{[{<<"foo\\u0000bar">>, 2}]}
}
],
{"Test dedupe_keys", lists:map(fun({Data, Result}) ->
Json = jiffy:encode(Data),
?_assertEqual(Result, jiffy:decode(Json, Opts))
end, Cases)}.
dedupe_keys_empty_test() ->
?assertEqual({[]}, jiffy:decode(<<"{}">>, [dedupe_keys])).
% Exercise the heap-allocated dedupe hash table path when count > 64 and hit
% more than HT_STACK_SLOTS. We're padding those coverage stats here, really.
dedupe_keys_large_test_() ->
N = 100,
KV = fun(I) -> [<<"\"">>, i2b(I), <<"\":">>, i2b(I)] end,
Body = iol2b(lists:join(",", [KV(I) || I <- lists:seq(1, N)])),
Dupes = iol2b(lists:join(",", [KV(I) || I <- lists:seq(1, N)])),
JUnique = <<"{", Body/binary, "}">>,
JDupes = <<"{", Body/binary, ",", Dupes/binary, "}">>,
[
{"Unique large object",
fun() ->
{Pairs} = jiffy:decode(JUnique, [dedupe_keys]),
?assertEqual(N, length(Pairs))
end},
{"All keys duplicated once",
fun() ->
{Pairs} = jiffy:decode(JDupes, [dedupe_keys]),
?assertEqual(N, length(Pairs))
end}
].