% This file is part of Jiffy released under the MIT license. % See the LICENSE file for more information. -module(jiffy_11_proper_tests). -ifdef(JIFFY_DEV). -include_lib("proper/include/proper.hrl"). -include_lib("eunit/include/eunit.hrl"). -include("jiffy_util.hrl"). opts() -> [ {max_size, 15}, {numtests, 1000} ]. run(Name) -> {msg("~s", [Name]), [ {timeout, 3600, ?_assert(proper:quickcheck(?MODULE:Name(), opts()))} ]}. proper_encode_decode_test_() -> {timeout, 3600, [ run(prop_enc_dec), run(prop_enc_dec_pretty), run(prop_enc_no_crash), run(prop_dec_no_crash_bin), run(prop_dec_no_crash_any) ]}. prop_enc_dec() -> ?FORALL(Data, json(), begin %io:format(standard_error, "Data: ~p~n", [Data]), Data == jiffy:decode(jiffy:encode(Data)) end ). -ifndef(JIFFY_NO_MAPS). to_map_ejson({Props}) -> NewProps = [{K, to_map_ejson(V)} || {K, V} <- Props], maps:from_list(NewProps); to_map_ejson(Vals) when is_list(Vals) -> [to_map_ejson(V) || V <- Vals]; to_map_ejson(Val) -> Val. prop_map_enc_dec() -> ?FORALL(Data, json(), begin MapData = to_map_ejson(Data), MapData == jiffy:decode(jiffy:encode(MapData), [return_maps]) end ). -endif. prop_enc_dec_pretty() -> ?FORALL(Data, json(), begin Data == jiffy:decode(jiffy:encode(Data, [pretty])) end ). prop_enc_no_crash() -> ?FORALL(Data, any(), begin catch jiffy:encode(Data), true end). prop_dec_no_crash_bin() -> ?FORALL(Data, binary(), begin catch jiffy:decode(Data), true end). prop_dec_no_crash_any() -> ?FORALL(Data, any(), begin catch jiffy:decode(Data), true end). % JSON Generation json_null() -> null. json_boolean() -> oneof([true, false]). json_number() -> oneof([integer(), float()]). json_string() -> escaped_utf8_bin(). json_list(S) when S =< 0 -> []; json_list(S) -> ?LETSHRINK( [ListSize], [integer(0, S)], vector(ListSize, json_text(S - ListSize)) ). json_object(S) when S =< 0 -> {[]}; json_object(S) -> ?LETSHRINK( [ObjectSize], [integer(0, S)], {vector(ObjectSize, {json_string(), json_text(S - ObjectSize)})} ). json_value() -> oneof([ json_null(), json_boolean(), json_string(), json_number() ]). json_text(S) when S > 0 -> ?LAZY(oneof([ json_list(S), json_object(S) ])); json_text(_) -> json_value(). json() -> ?SIZED(S, json_text(S)). %% XXX: Add generators % % We should add generators that generate JSON binaries directly % so we can test things that aren't produced by the encoder. % % We should also have a version of the JSON generator that inserts % errors into the JSON that we can test for. escaped_utf8_bin() -> ?SUCHTHAT(Bin, ?LET(S, ?SUCHTHAT(L, list(escaped_char()), L /= []), unicode:characters_to_binary(S, unicode, utf8)), is_binary(Bin) ). escaped_char() -> ?LET(C, char(), case C of $" -> "\\\""; C when C == 65534 -> 65533; C when C == 65535 -> 65533; C when C > 1114111 -> 1114111; C -> C end ). -endif.