diff --git a/test/001-yajl-tests.t b/test/001-yajl-tests.t deleted file mode 100755 index b89fbee..0000000 --- a/test/001-yajl-tests.t +++ /dev/null @@ -1,30 +0,0 @@ -#! /usr/bin/env escript -% This file is part of Jiffy released under the MIT license. -% See the LICENSE file for more information. - -main([]) -> - code:add_pathz("test"), - code:add_pathz("ebin"), - - Cases = read_cases(), - - etap:plan(length(Cases)), - lists:foreach(fun(Case) -> test(Case) end, Cases), - etap:end_tests(). - -test({Name, Json, {error, _}=Erl}) -> - etap:is((catch jiffy:decode(Json)), Erl, Name); -test({Name, Json, Erl}) -> - etap:is(jiffy:decode(Json), Erl, Name). - -read_cases() -> - CasesPath = filename:join(["test", "cases", "*.json"]), - FileNames = lists:sort(filelib:wildcard(CasesPath)), - lists:map(fun(F) -> make_pair(F) end, FileNames). - -make_pair(FileName) -> - {ok, Json} = file:read_file(FileName), - {BaseName, _} = lists:splitwith(fun(C) -> C /= $. end, FileName), - ErlFname = BaseName ++ ".eterm", - {ok, [Term]} = file:consult(ErlFname), - {BaseName, Json, Term}. diff --git a/test/002-literals.t b/test/002-literals.t deleted file mode 100755 index 8df7255..0000000 --- a/test/002-literals.t +++ /dev/null @@ -1,21 +0,0 @@ -#! /usr/bin/env escript -% This file is part of Jiffy released under the MIT license. -% See the LICENSE file for more information. - -main([]) -> - code:add_pathz("ebin"), - code:add_pathz("test"), - - etap:plan(6), - etap:is(jiffy:decode(<<"true">>), true, "DEC: true -> true"), - etap:is(jiffy:encode(true), <<"true">>, "ENC: true -> true"), - - etap:is(jiffy:decode(<<"false">>), false, "DEC: false -> false"), - etap:is(jiffy:encode(false), <<"false">>, "ENC: false -> false"), - - etap:is(jiffy:decode(<<"null">>), null, "DEC: null -> null"), - etap:is(jiffy:encode(null), <<"null">>, "ENC: null -> null"), - - etap:end_tests(). - - diff --git a/test/008-halfword.t b/test/008-halfword.t deleted file mode 100755 index 56f0439..0000000 --- a/test/008-halfword.t +++ /dev/null @@ -1,15 +0,0 @@ -#! /usr/bin/env escript -% This file is part of Jiffy released under the MIT license. -% See the LICENSE file for more information. - -main([]) -> - code:add_pathz("ebin"), - code:add_pathz("test"), - - etap:plan(unknown), - - etap:is(jiffy:decode(<<"1">>) =:= 1, true, "1 =:= 1"), - etap:is(jiffy:decode(<<"1">>) == 1, true, "1 == 1"), - - etap:end_tests(). - diff --git a/test/010-short-doubles.t b/test/010-short-doubles.t deleted file mode 100755 index 4aac375..0000000 --- a/test/010-short-doubles.t +++ /dev/null @@ -1,29 +0,0 @@ -#! /usr/bin/env escript -% This file is part of Jiffy released under the MIT license. -% See the LICENSE file for more information. - -filename() -> "test/cases/short-doubles.txt". - -main([]) -> - code:add_pathz("ebin"), - code:add_pathz("test"), - - etap:plan(100000), - - etap:diag("Loading test cases..."), - {ok, Cases} = file:consult(filename()), - - etap:diag("Running tests..."), - ok = run_tests(Cases), - - etap:end_tests(). - - -run_tests([]) -> - ok; -run_tests([Double | Rest]) -> - RoundTrip = jiffy:decode(jiffy:encode(Double)), - Desc = lists:flatten(io_lib:format("~e", [Double])), - etap:is(RoundTrip, Double, "Roundtrip: " ++ Desc), - run_tests(Rest). - diff --git a/test/etap.erl b/test/etap.erl deleted file mode 100644 index 6924d09..0000000 --- a/test/etap.erl +++ /dev/null @@ -1,612 +0,0 @@ -%% Copyright (c) 2008-2009 Nick Gerakines -%% -%% Permission is hereby granted, free of charge, to any person -%% obtaining a copy of this software and associated documentation -%% files (the "Software"), to deal in the Software without -%% restriction, including without limitation the rights to use, -%% copy, modify, merge, publish, distribute, sublicense, and/or sell -%% copies of the Software, and to permit persons to whom the -%% Software is furnished to do so, subject to the following -%% conditions: -%% -%% The above copyright notice and this permission notice shall be -%% included in all copies or substantial portions of the Software. -%% -%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -%% EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -%% OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -%% NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -%% HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -%% WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -%% FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -%% OTHER DEALINGS IN THE SOFTWARE. -%% -%% @author Nick Gerakines [http://socklabs.com/] -%% @author Jeremy Wall -%% @version 0.3.4 -%% @copyright 2007-2008 Jeremy Wall, 2008-2009 Nick Gerakines -%% @reference http://testanything.org/wiki/index.php/Main_Page -%% @reference http://en.wikipedia.org/wiki/Test_Anything_Protocol -%% @todo Finish implementing the skip directive. -%% @todo Document the messages handled by this receive loop. -%% @todo Explain in documentation why we use a process to handle test input. -%% @doc etap is a TAP testing module for Erlang components and applications. -%% This module allows developers to test their software using the TAP method. -%% -%%

-%% TAP, the Test Anything Protocol, is a simple text-based interface between -%% testing modules in a test harness. TAP started life as part of the test -%% harness for Perl but now has implementations in C/C++, Python, PHP, Perl -%% and probably others by the time you read this. -%%

-%% -%% The testing process begins by defining a plan using etap:plan/1, running -%% a number of etap tests and then calling eta:end_tests/0. Please refer to -%% the Erlang modules in the t directory of this project for example tests. --module(etap). --vsn("0.3.4"). - --export([ - ensure_test_server/0, - start_etap_server/0, - test_server/1, - msg/1, msg/2, - diag/1, diag/2, - expectation_mismatch_message/3, - plan/1, - end_tests/0, - not_ok/2, ok/2, is_ok/2, is/3, isnt/3, any/3, none/3, - fun_is/3, expect_fun/3, expect_fun/4, - is_greater/3, - skip/1, skip/2, - datetime/1, - skip/3, - bail/0, bail/1, - test_state/0, failure_count/0 -]). - --export([ - contains_ok/3, - is_before/4 -]). - --export([ - is_pid/2, - is_alive/2, - is_mfa/3 -]). - --export([ - loaded_ok/2, - can_ok/2, can_ok/3, - has_attrib/2, is_attrib/3, - is_behaviour/2 -]). - --export([ - dies_ok/2, - lives_ok/2, - throws_ok/3 -]). - - --record(test_state, { - planned = 0, - count = 0, - pass = 0, - fail = 0, - skip = 0, - skip_reason = "" -}). - -%% @spec plan(N) -> Result -%% N = unknown | skip | {skip, string()} | integer() -%% Result = ok -%% @doc Create a test plan and boot strap the test server. -plan(unknown) -> - ensure_test_server(), - etap_server ! {self(), plan, unknown}, - ok; -plan(skip) -> - io:format("1..0 # skip~n"); -plan({skip, Reason}) -> - io:format("1..0 # skip ~s~n", [Reason]); -plan(N) when is_integer(N), N > 0 -> - ensure_test_server(), - etap_server ! {self(), plan, N}, - ok. - -%% @spec end_tests() -> ok -%% @doc End the current test plan and output test results. -%% @todo This should probably be done in the test_server process. -end_tests() -> - case whereis(etap_server) of - undefined -> self() ! true; - _ -> etap_server ! {self(), state} - end, - State = receive X -> X end, - if - State#test_state.planned == -1 -> - io:format("1..~p~n", [State#test_state.count]); - true -> - ok - end, - case whereis(etap_server) of - undefined -> ok; - _ -> etap_server ! done, ok - end. - -bail() -> - bail(""). - -bail(Reason) -> - etap_server ! {self(), diag, "Bail out! " ++ Reason}, - etap_server ! done, ok, - ok. - -%% @spec test_state() -> Return -%% Return = test_state_record() | {error, string()} -%% @doc Return the current test state -test_state() -> - etap_server ! {self(), state}, - receive - X when is_record(X, test_state) -> X - after - 1000 -> {error, "Timed out waiting for etap server reply.~n"} - end. - -%% @spec failure_count() -> Return -%% Return = integer() | {error, string()} -%% @doc Return the current failure count -failure_count() -> - case test_state() of - #test_state{fail=FailureCount} -> FailureCount; - X -> X - end. - -%% @spec msg(S) -> ok -%% S = string() -%% @doc Print a message in the test output. -msg(S) -> etap_server ! {self(), diag, S}, ok. - -%% @spec msg(Format, Data) -> ok -%% Format = atom() | string() | binary() -%% Data = [term()] -%% UnicodeList = [Unicode] -%% Unicode = int() -%% @doc Print a message in the test output. -%% Function arguments are passed through io_lib:format/2. -msg(Format, Data) -> msg(io_lib:format(Format, Data)). - -%% @spec diag(S) -> ok -%% S = string() -%% @doc Print a debug/status message related to the test suite. -diag(S) -> msg("# " ++ S). - -%% @spec diag(Format, Data) -> ok -%% Format = atom() | string() | binary() -%% Data = [term()] -%% UnicodeList = [Unicode] -%% Unicode = int() -%% @doc Print a debug/status message related to the test suite. -%% Function arguments are passed through io_lib:format/2. -diag(Format, Data) -> diag(io_lib:format(Format, Data)). - -%% @spec expectation_mismatch_message(Got, Expected, Desc) -> ok -%% Got = any() -%% Expected = any() -%% Desc = string() -%% @doc Print an expectation mismatch message in the test output. -expectation_mismatch_message(Got, Expected, Desc) -> - msg(" ---"), - msg(" description: ~p", [Desc]), - msg(" found: ~p", [Got]), - msg(" wanted: ~p", [Expected]), - msg(" ..."), - ok. - -% @spec evaluate(Pass, Got, Expected, Desc) -> Result -%% Pass = true | false -%% Got = any() -%% Expected = any() -%% Desc = string() -%% Result = true | false -%% @doc Evaluate a test statement, printing an expectation mismatch message -%% if the test failed. -evaluate(Pass, Got, Expected, Desc) -> - case mk_tap(Pass, Desc) of - false -> - expectation_mismatch_message(Got, Expected, Desc), - false; - true -> - true - end. - -%% @spec ok(Expr, Desc) -> Result -%% Expr = true | false -%% Desc = string() -%% Result = true | false -%% @doc Assert that a statement is true. -ok(Expr, Desc) -> evaluate(Expr == true, Expr, true, Desc). - -%% @spec not_ok(Expr, Desc) -> Result -%% Expr = true | false -%% Desc = string() -%% Result = true | false -%% @doc Assert that a statement is false. -not_ok(Expr, Desc) -> evaluate(Expr == false, Expr, false, Desc). - -%% @spec is_ok(Expr, Desc) -> Result -%% Expr = any() -%% Desc = string() -%% Result = true | false -%% @doc Assert that two values are the same. -is_ok(Expr, Desc) -> evaluate(Expr == ok, Expr, ok, Desc). - -%% @spec is(Got, Expected, Desc) -> Result -%% Got = any() -%% Expected = any() -%% Desc = string() -%% Result = true | false -%% @doc Assert that two values are the same. -is(Got, Expected, Desc) -> evaluate(Got == Expected, Got, Expected, Desc). - -%% @spec isnt(Got, Expected, Desc) -> Result -%% Got = any() -%% Expected = any() -%% Desc = string() -%% Result = true | false -%% @doc Assert that two values are not the same. -isnt(Got, Expected, Desc) -> evaluate(Got /= Expected, Got, Expected, Desc). - -%% @spec is_greater(ValueA, ValueB, Desc) -> Result -%% ValueA = number() -%% ValueB = number() -%% Desc = string() -%% Result = true | false -%% @doc Assert that an integer is greater than another. -is_greater(ValueA, ValueB, Desc) when is_integer(ValueA), is_integer(ValueB) -> - mk_tap(ValueA > ValueB, Desc). - -%% @spec any(Got, Items, Desc) -> Result -%% Got = any() -%% Items = [any()] -%% Desc = string() -%% Result = true | false -%% @doc Assert that an item is in a list. -any(Got, Items, Desc) when is_function(Got) -> - is(lists:any(Got, Items), true, Desc); -any(Got, Items, Desc) -> - is(lists:member(Got, Items), true, Desc). - -%% @spec none(Got, Items, Desc) -> Result -%% Got = any() -%% Items = [any()] -%% Desc = string() -%% Result = true | false -%% @doc Assert that an item is not in a list. -none(Got, Items, Desc) when is_function(Got) -> - is(lists:any(Got, Items), false, Desc); -none(Got, Items, Desc) -> - is(lists:member(Got, Items), false, Desc). - -%% @spec fun_is(Fun, Expected, Desc) -> Result -%% Fun = function() -%% Expected = any() -%% Desc = string() -%% Result = true | false -%% @doc Use an anonymous function to assert a pattern match. -fun_is(Fun, Expected, Desc) when is_function(Fun) -> - is(Fun(Expected), true, Desc). - -%% @spec expect_fun(ExpectFun, Got, Desc) -> Result -%% ExpectFun = function() -%% Got = any() -%% Desc = string() -%% Result = true | false -%% @doc Use an anonymous function to assert a pattern match, using actual -%% value as the argument to the function. -expect_fun(ExpectFun, Got, Desc) -> - evaluate(ExpectFun(Got), Got, ExpectFun, Desc). - -%% @spec expect_fun(ExpectFun, Got, Desc, ExpectStr) -> Result -%% ExpectFun = function() -%% Got = any() -%% Desc = string() -%% ExpectStr = string() -%% Result = true | false -%% @doc Use an anonymous function to assert a pattern match, using actual -%% value as the argument to the function. -expect_fun(ExpectFun, Got, Desc, ExpectStr) -> - evaluate(ExpectFun(Got), Got, ExpectStr, Desc). - -%% @equiv skip(TestFun, "") -skip(TestFun) when is_function(TestFun) -> - skip(TestFun, ""). - -%% @spec skip(TestFun, Reason) -> ok -%% TestFun = function() -%% Reason = string() -%% @doc Skip a test. -skip(TestFun, Reason) when is_function(TestFun), is_list(Reason) -> - begin_skip(Reason), - catch TestFun(), - end_skip(), - ok. - -%% @spec skip(Q, TestFun, Reason) -> ok -%% Q = true | false | function() -%% TestFun = function() -%% Reason = string() -%% @doc Skips a test conditionally. The first argument to this function can -%% either be the 'true' or 'false' atoms or a function that returns 'true' or -%% 'false'. -skip(QFun, TestFun, Reason) when is_function(QFun), is_function(TestFun), is_list(Reason) -> - case QFun() of - true -> begin_skip(Reason), TestFun(), end_skip(); - _ -> TestFun() - end, - ok; - -skip(Q, TestFun, Reason) when is_function(TestFun), is_list(Reason), Q == true -> - begin_skip(Reason), - TestFun(), - end_skip(), - ok; - -skip(_, TestFun, Reason) when is_function(TestFun), is_list(Reason) -> - TestFun(), - ok. - -%% @private -begin_skip(Reason) -> - etap_server ! {self(), begin_skip, Reason}. - -%% @private -end_skip() -> - etap_server ! {self(), end_skip}. - -%% @spec contains_ok(string(), string(), string()) -> true | false -%% @doc Assert that a string is contained in another string. -contains_ok(Source, String, Desc) -> - etap:isnt( - string:str(Source, String), - 0, - Desc - ). - -%% @spec is_before(string(), string(), string(), string()) -> true | false -%% @doc Assert that a string comes before another string within a larger body. -is_before(Source, StringA, StringB, Desc) -> - etap:is_greater( - string:str(Source, StringB), - string:str(Source, StringA), - Desc - ). - -%% @doc Assert that a given variable is a pid. -is_pid(Pid, Desc) when is_pid(Pid) -> etap:ok(true, Desc); -is_pid(_, Desc) -> etap:ok(false, Desc). - -%% @doc Assert that a given process/pid is alive. -is_alive(Pid, Desc) -> - etap:ok(erlang:is_process_alive(Pid), Desc). - -%% @doc Assert that the current function of a pid is a given {M, F, A} tuple. -is_mfa(Pid, MFA, Desc) -> - etap:is({current_function, MFA}, erlang:process_info(Pid, current_function), Desc). - -%% @spec loaded_ok(atom(), string()) -> true | false -%% @doc Assert that a module has been loaded successfully. -loaded_ok(M, Desc) when is_atom(M) -> - etap:fun_is(fun({module, _}) -> true; (_) -> false end, code:load_file(M), Desc). - -%% @spec can_ok(atom(), atom()) -> true | false -%% @doc Assert that a module exports a given function. -can_ok(M, F) when is_atom(M), is_atom(F) -> - Matches = [X || {X, _} <- M:module_info(exports), X == F], - etap:ok(Matches > 0, lists:concat([M, " can ", F])). - -%% @spec can_ok(atom(), atom(), integer()) -> true | false -%% @doc Assert that a module exports a given function with a given arity. -can_ok(M, F, A) when is_atom(M); is_atom(F), is_number(A) -> - Matches = [X || X <- M:module_info(exports), X == {F, A}], - etap:ok(Matches > 0, lists:concat([M, " can ", F, "/", A])). - -%% @spec has_attrib(M, A) -> true | false -%% M = atom() -%% A = atom() -%% @doc Asserts that a module has a given attribute. -has_attrib(M, A) when is_atom(M), is_atom(A) -> - etap:isnt( - proplists:get_value(A, M:module_info(attributes), 'asdlkjasdlkads'), - 'asdlkjasdlkads', - lists:concat([M, " has attribute ", A]) - ). - -%% @spec has_attrib(M, A. V) -> true | false -%% M = atom() -%% A = atom() -%% V = any() -%% @doc Asserts that a module has a given attribute with a given value. -is_attrib(M, A, V) when is_atom(M) andalso is_atom(A) -> - etap:is( - proplists:get_value(A, M:module_info(attributes)), - [V], - lists:concat([M, "'s ", A, " is ", V]) - ). - -%% @spec is_behavior(M, B) -> true | false -%% M = atom() -%% B = atom() -%% @doc Asserts that a given module has a specific behavior. -is_behaviour(M, B) when is_atom(M) andalso is_atom(B) -> - is_attrib(M, behaviour, B). - -%% @doc Assert that an exception is raised when running a given function. -dies_ok(F, Desc) -> - case (catch F()) of - {'EXIT', _} -> etap:ok(true, Desc); - _ -> etap:ok(false, Desc) - end. - -%% @doc Assert that an exception is not raised when running a given function. -lives_ok(F, Desc) -> - etap:is(try_this(F), success, Desc). - -%% @doc Assert that the exception thrown by a function matches the given exception. -throws_ok(F, Exception, Desc) -> - try F() of - _ -> etap:ok(nok, Desc) - catch - _:E -> - etap:is(E, Exception, Desc) - end. - -%% @private -%% @doc Run a function and catch any exceptions. -try_this(F) when is_function(F, 0) -> - try F() of - _ -> success - catch - throw:E -> {throw, E}; - error:E -> {error, E}; - exit:E -> {exit, E} - end. - -%% @private -%% @doc Start the etap_server process if it is not running already. -ensure_test_server() -> - case whereis(etap_server) of - undefined -> - proc_lib:start(?MODULE, start_etap_server,[]); - _ -> - diag("The test server is already running.") - end. - -%% @private -%% @doc Start the etap_server loop and register itself as the etap_server -%% process. -start_etap_server() -> - catch register(etap_server, self()), - proc_lib:init_ack(ok), - etap:test_server(#test_state{ - planned = 0, - count = 0, - pass = 0, - fail = 0, - skip = 0, - skip_reason = "" - }). - - -%% @private -%% @doc The main etap_server receive/run loop. The etap_server receive loop -%% responds to seven messages apperatining to failure or passing of tests. -%% It is also used to initiate the testing process with the {_, plan, _} -%% message that clears the current test state. -test_server(State) -> - NewState = receive - {_From, plan, unknown} -> - io:format("# Current time local ~s~n", [datetime(erlang:localtime())]), - io:format("# Using etap version ~p~n", [ proplists:get_value(vsn, proplists:get_value(attributes, etap:module_info())) ]), - State#test_state{ - planned = -1, - count = 0, - pass = 0, - fail = 0, - skip = 0, - skip_reason = "" - }; - {_From, plan, N} -> - io:format("# Current time local ~s~n", [datetime(erlang:localtime())]), - io:format("# Using etap version ~p~n", [ proplists:get_value(vsn, proplists:get_value(attributes, etap:module_info())) ]), - io:format("1..~p~n", [N]), - State#test_state{ - planned = N, - count = 0, - pass = 0, - fail = 0, - skip = 0, - skip_reason = "" - }; - {_From, begin_skip, Reason} -> - State#test_state{ - skip = 1, - skip_reason = Reason - }; - {_From, end_skip} -> - State#test_state{ - skip = 0, - skip_reason = "" - }; - {_From, pass, Desc} -> - FullMessage = skip_diag( - " - " ++ Desc, - State#test_state.skip, - State#test_state.skip_reason - ), - io:format("ok ~p ~s~n", [State#test_state.count + 1, FullMessage]), - State#test_state{ - count = State#test_state.count + 1, - pass = State#test_state.pass + 1 - }; - - {_From, fail, Desc} -> - FullMessage = skip_diag( - " - " ++ Desc, - State#test_state.skip, - State#test_state.skip_reason - ), - io:format("not ok ~p ~s~n", [State#test_state.count + 1, FullMessage]), - State#test_state{ - count = State#test_state.count + 1, - fail = State#test_state.fail + 1 - }; - {From, state} -> - From ! State, - State; - {_From, diag, Message} -> - io:format("~s~n", [Message]), - State; - {From, count} -> - From ! State#test_state.count, - State; - {From, is_skip} -> - From ! State#test_state.skip, - State; - done -> - exit(normal) - end, - test_server(NewState). - -%% @private -%% @doc Process the result of a test and send it to the etap_server process. -mk_tap(Result, Desc) -> - IsSkip = lib:sendw(etap_server, is_skip), - case [IsSkip, Result] of - [_, true] -> - etap_server ! {self(), pass, Desc}, - true; - [1, _] -> - etap_server ! {self(), pass, Desc}, - true; - _ -> - etap_server ! {self(), fail, Desc}, - false - end. - -%% @private -%% @doc Format a date/time string. -datetime(DateTime) -> - {{Year, Month, Day}, {Hour, Min, Sec}} = DateTime, - io_lib:format("~4.10.0B-~2.10.0B-~2.10.0B ~2.10.0B:~2.10.0B:~2.10.0B", [Year, Month, Day, Hour, Min, Sec]). - -%% @private -%% @doc Craft an output message taking skip/todo into consideration. -skip_diag(Message, 0, _) -> - Message; -skip_diag(_Message, 1, "") -> - " # SKIP"; -skip_diag(_Message, 1, Reason) -> - " # SKIP : " ++ Reason. diff --git a/test/jiffy_01_yajl_tests.erl b/test/jiffy_01_yajl_tests.erl new file mode 100644 index 0000000..b3ac13a --- /dev/null +++ b/test/jiffy_01_yajl_tests.erl @@ -0,0 +1,33 @@ +% This file is part of Jiffy released under the MIT license. +% See the LICENSE file for more information. + +-module(jiffy_01_yajl_tests). + + +-include_lib("proper/include/proper.hrl"). +-include_lib("eunit/include/eunit.hrl"). + + +yajl_test_() -> + Cases = read_cases(), + [gen(Case) || Case <- Cases]. + + +gen({Name, Json, {error, _}=Erl}) -> + {Name, ?_assertThrow(Erl, jiffy:decode(Json))}; +gen({Name, Json, Erl}) -> + {Name, ?_assertEqual(Erl, jiffy:decode(Json))}. + + +read_cases() -> + CasesPath = filename:join(["..", "test", "cases", "*.json"]), + FileNames = lists:sort(filelib:wildcard(CasesPath)), + lists:map(fun(F) -> make_pair(F) end, FileNames). + + +make_pair(FileName) -> + {ok, Json} = file:read_file(FileName), + BaseName = filename:rootname(FileName), + ErlFname = BaseName ++ ".eterm", + {ok, [Term]} = file:consult(ErlFname), + {filename:basename(BaseName), Json, Term}. diff --git a/test/jiffy_02_literal_tests.erl b/test/jiffy_02_literal_tests.erl new file mode 100644 index 0000000..4c50a34 --- /dev/null +++ b/test/jiffy_02_literal_tests.erl @@ -0,0 +1,28 @@ +% This file is part of Jiffy released under the MIT license. +% See the LICENSE file for more information. + +-module(jiffy_02_literal_tests). + +-include_lib("proper/include/proper.hrl"). +-include_lib("eunit/include/eunit.hrl"). + + +true_test_() -> + {"true", [ + {"Decode", ?_assertEqual(true, jiffy:decode(<<"true">>))}, + {"Encode", ?_assertEqual(<<"true">>, jiffy:encode(true))} + ]}. + + +false_test_() -> + {"false", [ + {"Decode", ?_assertEqual(false, jiffy:decode(<<"false">>))}, + {"Encode", ?_assertEqual(<<"false">>, jiffy:encode(false))} + ]}. + + +null_test_() -> + {"null", [ + {"Decode", ?_assertEqual(null, jiffy:decode(<<"null">>))}, + {"Encode", ?_assertEqual(<<"null">>, jiffy:encode(null))} + ]}. diff --git a/test/003-numbers.t b/test/jiffy_03_number_tests.erl old mode 100755 new mode 100644 similarity index 71% rename from test/003-numbers.t rename to test/jiffy_03_number_tests.erl index 2ac2ab4..da69049 --- a/test/003-numbers.t +++ b/test/jiffy_03_number_tests.erl @@ -1,28 +1,48 @@ -#! /usr/bin/env escript % This file is part of Jiffy released under the MIT license. % See the LICENSE file for more information. -main([]) -> - code:add_pathz("ebin"), - code:add_pathz("test"), +-module(jiffy_03_number_tests). - etap:plan(59 + 2 * length(double_conversion_tests())), - util:test_good(good()), - util:test_errors(errors()), - run_double_conversion_tests(), - etap:end_tests(). +-include_lib("proper/include/proper.hrl"). +-include_lib("eunit/include/eunit.hrl"). +-include("jiffy_util.hrl"). -run_double_conversion_tests() -> - lists:foreach(fun(Double) -> - Descr = io_lib:format("~f", [Double]), - etap:is(jiffy:decode(jiffy:encode(Double)), Double, Descr), - NegDouble = -1.0 * Double, - NegDescr = io_lib:format("~f", [NegDouble]), - etap:is(jiffy:decode(jiffy:encode(NegDouble)), NegDouble, NegDescr) - end, double_conversion_tests()). -good() -> +number_success_test_() -> + [gen(ok, Case) || Case <- cases(ok)]. + + +number_failure_test_() -> + [gen(error, Case) || Case <- cases(error)]. + + +number_double_test_() -> + [gen(floats, Case) || Case <- cases(floats)]. + + +gen(ok, {J, E}) -> + gen(ok, {J, E, J}); +gen(ok, {J1, E, J2}) -> + {msg("~s", [J1]), [ + {"Decode", ?_assertEqual(E, dec(J1))}, + {"Encode", ?_assertEqual(J2, enc(E))} + ]}; + +gen(error, J) -> + {msg("Error: ~s", [J]), [ + ?_assertThrow({error, _}, dec(J)) + ]}; + +gen(floats, F) -> + NegF = -1.0 * F, + {msg("float round trip - ~p", [F]), [ + {"Pos", ?_assertEqual(F, dec(enc(F)))}, + {"Neg", ?_assertEqual(NegF, dec(enc(NegF)))} + ]}. + + +cases(ok) -> [ {<<"0">>, 0}, {<<"-0">>, 0, <<"0">>}, @@ -64,10 +84,9 @@ good() -> {<<"1.5E3">>, 1500.0, <<"1500.0">>}, {<<"2.5E-1">>, 0.25, <<"0.25">>}, {<<"-0.325E+2">>, -32.5, <<"-32.5">>} - ]. - + ]; -errors() -> +cases(error) -> [ <<"02">>, <<"-01">>, @@ -80,10 +99,9 @@ errors() -> <<"1-E2">>, <<"2E +3">>, <<"1EA">> - ]. - + ]; -double_conversion_tests() -> +cases(floats) -> [ 0.0, 0.00000001, @@ -114,5 +132,3 @@ double_conversion_tests() -> 1111111111111111111111.0, 11111111111111111111111.0 ]. - - diff --git a/test/004-strings.t b/test/jiffy_04_string_tests.erl old mode 100755 new mode 100644 similarity index 54% rename from test/004-strings.t rename to test/jiffy_04_string_tests.erl index d0214d5..46f15ff --- a/test/004-strings.t +++ b/test/jiffy_04_string_tests.erl @@ -1,21 +1,60 @@ -#! /usr/bin/env escript % This file is part of Jiffy released under the MIT license. % See the LICENSE file for more information. -main([]) -> - code:add_pathz("ebin"), - code:add_pathz("test"), +-module(jiffy_04_string_tests). - etap:plan(115), - util:test_good(good()), - util:test_good(uescaped(), [uescape]), - util:test_errors(errors()), - test_utf8(utf8_cases()), +-include_lib("proper/include/proper.hrl"). +-include_lib("eunit/include/eunit.hrl"). +-include("jiffy_util.hrl"). - etap:end_tests(). -good() -> +string_success_test_() -> + [gen(ok, Case) || Case <- cases(ok)]. + + +string_uescaped_test_() -> + [gen(uescaped, Case) || Case <- cases(uescaped)]. + + +string_error_test_() -> + [gen(error, Case) || Case <- cases(error)]. + + +string_utf8_test_() -> + [gen(utf8, Case) || Case <- cases(utf8)]. + + +gen(ok, {J, E}) -> + gen(ok, {J, E, J}); +gen(ok, {J1, E, J2}) -> + {msg("ok - ~s", [J1]), [ + {"Decode", ?_assertEqual(E, dec(J1))}, + {"Encode", ?_assertEqual(J2, enc(E))} + ]}; + +gen(uescaped, {J, E}) -> + {msg("uescape - ~s", [J]), [ + {"Decode", ?_assertEqual(E, dec(J))}, + {"Encode", ?_assertEqual(J, enc(E, [uescape]))} + ]}; + +gen(error, J) -> + {msg("error - ~s", [J]), [ + ?_assertThrow({error, _}, dec(J)) + ]}; + +gen(utf8, {Case, Fixed}) -> + Case2 = <<34, Case/binary, 34>>, + Fixed2 = <<34, Fixed/binary, 34>>, + {msg("UTF-8: ~s", [hex(Case)]), [ + ?_assertThrow({error, invalid_string}, jiffy:encode(Case)), + ?_assertEqual(Fixed2, jiffy:encode(Case, [force_utf8])), + ?_assertThrow({error, {_, invalid_string}}, jiffy:decode(Case2)) + ]}. + + +cases(ok) -> [ {<<"\"\"">>, <<"">>}, {<<"\"/\"">>, <<"/">>}, @@ -32,9 +71,9 @@ good() -> }, {<<"\"\\uFFFF\"">>, <<239,191,191>>, <<34,239,191,191,34>>}, {<<"\"\\uFFFE\"">>, <<239,191,190>>, <<34,239,191,190,34>>} - ]. + ]; -uescaped() -> +cases(uescaped) -> [ { <<"\"\\u8CA8\\u5481\\u3002\\u0091\\u0091\"">>, @@ -48,9 +87,9 @@ uescaped() -> <<"\"\\uD83D\\uDE0A\"">>, <<240, 159, 152, 138>> } - ]. + ]; -errors() -> +cases(error) -> [ "\"", <<"\"foo">>, @@ -59,30 +98,9 @@ errors() -> <<"\"\\uD834foo\\uDD1E\"">>, % CouchDB-345 <<34,78,69,73,77,69,78,32,70,216,82,82,32,70,65,69,78,33,34>> - ]. + ]; -test_utf8([]) -> - ok; -test_utf8([{Case, Fixed} | Rest]) -> - etap:fun_is( - fun({error, invalid_string}) -> true; (Else) -> Else end, - (catch jiffy:encode(Case)), - lists:flatten(io_lib:format("Invalid utf-8: ~p", [Case])) - ), - etap:fun_is( - fun(Fixed) -> true; (Else) -> Else end, - jiffy:encode(Case, [force_utf8]), - lists:flatten(io_lib:format("Fixed correctly: ~p", [Fixed])) - ), - Case2 = <<34, Case/binary, 34>>, - etap:fun_is( - fun({error, {_, invalid_string}}) -> true; (Else) -> Else end, - (catch jiffy:decode(Case2)), - lists:flatten(io_lib:format("Invalid utf-8: ~p", [Case2])) - ), - test_utf8(Rest). - -utf8_cases() -> +cases(utf8) -> [ % Stray continuation byte {<<16#C2, 16#81, 16#80>>, <<16#C2, 16#81, 16#EF, 16#BF, 16#BD>>}, @@ -110,18 +128,20 @@ utf8_cases() -> {<<16#FC, 16#80, 16#80, 16#80, 16#80>>, <<16#EF, 16#BF, 16#BD>>}, % No data in high bits. - {<<16#C0, 16#80>>, <<"\"\\u0000\"">>}, - {<<16#C1, 16#80>>, <<"\"\\u0000\"">>}, - - {<<16#E0, 16#80, 16#80>>, <<"\"\\u0000\"">>}, - {<<16#E0, 16#90, 16#80>>, <<"\"\\u0000\"">>}, - - {<<16#F0, 16#80, 16#80, 16#80>>, <<"\"\\u0000\"">>}, - {<<16#F0, 16#88, 16#80, 16#80>>, <<"\"\\u0000\"">>}, - - {<<16#F8, 16#80, 16#80, 16#80, 16#80>>, <<"\"\\u0000\"">>}, - {<<16#F8, 16#84, 16#80, 16#80, 16#80>>, <<"\"\\u0000\"">>}, - - {<<16#FC, 16#80, 16#80, 16#80, 16#80, 16#80>>, <<"\"\\u0000\"">>}, - {<<16#FC, 16#82, 16#80, 16#80, 16#80, 16#80>>, <<"\"\\u0000\"">>} + {<<16#C0, 16#80>>, <<"\\u0000">>}, + {<<16#C1, 16#80>>, <<"@">>}, + + {<<16#E0, 16#80, 16#80>>, <<"\\u0000">>}, + {<<16#E0, 16#90, 16#80>>, <<16#D0, 16#80>>}, + + {<<16#F0, 16#80, 16#80, 16#80>>, <<"\\u0000">>}, + {<<16#F0, 16#88, 16#80, 16#80>>, <<16#E8, 16#80, 16#80>>}, + + % UTF-8-like sequenecs of greater than 4 bytes + % aren't valid and are replaced with a single + % replacement 0xFFFD character. + {<<16#F8, 16#80, 16#80, 16#80, 16#80>>, <<16#EF, 16#BF, 16#BD>>}, + {<<16#F8, 16#84, 16#80, 16#80, 16#80>>, <<16#EF, 16#BF, 16#BD>>}, + {<<16#FC, 16#80, 16#80, 16#80, 16#80, 16#80>>, <<16#EF, 16#BF, 16#BD>>}, + {<<16#FC, 16#82, 16#80, 16#80, 16#80, 16#80>>, <<16#EF, 16#BF, 16#BD>>} ]. diff --git a/test/005-arrays.t b/test/jiffy_05_array_tests.erl old mode 100755 new mode 100644 similarity index 51% rename from test/005-arrays.t rename to test/jiffy_05_array_tests.erl index 1c43c0e..6e9b717 --- a/test/005-arrays.t +++ b/test/jiffy_05_array_tests.erl @@ -1,17 +1,37 @@ -#! /usr/bin/env escript % This file is part of Jiffy released under the MIT license. % See the LICENSE file for more information. -main([]) -> - code:add_pathz("ebin"), - code:add_pathz("test"), +-module(jiffy_05_array_tests). - etap:plan(18), - util:test_good(good()), - util:test_errors(errors()), - etap:end_tests(). -good() -> +-include_lib("proper/include/proper.hrl"). +-include_lib("eunit/include/eunit.hrl"). +-include("jiffy_util.hrl"). + + +array_success_test_() -> + [gen(ok, Case) || Case <- cases(ok)]. + + +array_failure_test_() -> + [gen(error, Case) || Case <- cases(error)]. + + +gen(ok, {J, E}) -> + gen(ok, {J, E, J}); +gen(ok, {J1, E, J2}) -> + {msg("~s", [J1]), [ + {"Decode", ?_assertEqual(E, dec(J1))}, + {"Encode", ?_assertEqual(J2, enc(E))} + ]}; + +gen(error, J) -> + {msg("Error: ~s", [J]), [ + ?_assertThrow({error, _}, dec(J)) + ]}. + + +cases(ok) -> [ {<<"[]">>, []}, {<<"[\t[\n]\r]">>, [[]], <<"[[]]">>}, @@ -23,9 +43,9 @@ good() -> [<<194, 161>>, <<195, 188>>], <<"[\"", 194, 161, "\",\"", 195, 188, "\"]">> } - ]. + ]; -errors() -> +cases(error) -> [ <<"[">>, <<"]">>, diff --git a/test/006-maps.t b/test/jiffy_06_object_tests.erl old mode 100755 new mode 100644 similarity index 51% rename from test/006-maps.t rename to test/jiffy_06_object_tests.erl index 45e715c..7aec347 --- a/test/006-maps.t +++ b/test/jiffy_06_object_tests.erl @@ -1,17 +1,37 @@ -#! /usr/bin/env escript % This file is part of Jiffy released under the MIT license. % See the LICENSE file for more information. -main([]) -> - code:add_pathz("ebin"), - code:add_pathz("test"), +-module(jiffy_06_object_tests). - etap:plan(15), - util:test_good(good()), - util:test_errors(errors()), - etap:end_tests(). -good() -> +-include_lib("proper/include/proper.hrl"). +-include_lib("eunit/include/eunit.hrl"). +-include("jiffy_util.hrl"). + + +object_success_test_() -> + [gen(ok, Case) || Case <- cases(ok)]. + + +object_failure_test_() -> + [gen(error, Case) || Case <- cases(error)]. + + +gen(ok, {J, E}) -> + gen(ok, {J, E, J}); +gen(ok, {J1, E, J2}) -> + {msg("~s", [J1]), [ + {"Decode", ?_assertEqual(E, dec(J1))}, + {"Encode", ?_assertEqual(J2, enc(E))} + ]}; + +gen(error, J) -> + {msg("Error: ~s", [J]), [ + ?_assertThrow({error, _}, dec(J)) + ]}. + + +cases(ok) -> [ {<<"{}">>, {[]}}, {<<"{\"foo\": \"bar\"}">>, @@ -20,9 +40,9 @@ good() -> {<<"\n\n{\"foo\":\r \"bar\",\n \"baz\"\t: 123 }">>, {[{<<"foo">>, <<"bar">>}, {<<"baz">>, 123}]}, <<"{\"foo\":\"bar\",\"baz\":123}">>} - ]. + ]; -errors() -> +cases(error) -> [ <<"{">>, <<"{,}">>, diff --git a/test/007-compound.t b/test/jiffy_07_compound_tests.erl old mode 100755 new mode 100644 similarity index 55% rename from test/007-compound.t rename to test/jiffy_07_compound_tests.erl index 2770971..7a968ab --- a/test/007-compound.t +++ b/test/jiffy_07_compound_tests.erl @@ -1,17 +1,37 @@ -#! /usr/bin/env escript % This file is part of Jiffy released under the MIT license. % See the LICENSE file for more information. -main([]) -> - code:add_pathz("ebin"), - code:add_pathz("test"), +-module(jiffy_07_compound_tests). - etap:plan(12), - util:test_good(good()), - util:test_errors(errors()), - etap:end_tests(). -good() -> +-include_lib("proper/include/proper.hrl"). +-include_lib("eunit/include/eunit.hrl"). +-include("jiffy_util.hrl"). + + +compound_success_test_() -> + [gen(ok, Case) || Case <- cases(ok)]. + + +compound_failure_test_() -> + [gen(error, Case) || Case <- cases(error)]. + + +gen(ok, {J, E}) -> + gen(ok, {J, E, J}); +gen(ok, {J1, E, J2}) -> + {msg("~s", [J1]), [ + {"Decode", ?_assertEqual(E, dec(J1))}, + {"Encode", ?_assertEqual(J2, enc(E))} + ]}; + +gen(error, J) -> + {msg("Error: ~s", [J]), [ + ?_assertThrow({error, _}, dec(J)) + ]}. + + +cases(ok) -> [ {<<"[{}]">>, [{[]}]}, {<<"{\"foo\":[123]}">>, {[{<<"foo">>, [123]}]}}, @@ -32,9 +52,9 @@ good() -> null ] } - ]. + ]; -errors() -> +cases(error) -> [ <<"[{}">>, <<"}]">> diff --git a/test/jiffy_08_halfword_tests.erl b/test/jiffy_08_halfword_tests.erl new file mode 100644 index 0000000..e18cd93 --- /dev/null +++ b/test/jiffy_08_halfword_tests.erl @@ -0,0 +1,16 @@ +% This file is part of Jiffy released under the MIT license. +% See the LICENSE file for more information. + +-module(jiffy_08_halfword_tests). + + +-include_lib("proper/include/proper.hrl"). +-include_lib("eunit/include/eunit.hrl"). +-include("jiffy_util.hrl"). + + +numerical_identity_test_() -> + [ + {"1 == 1", ?_assert(jiffy:decode(<<"1">>) == 1)}, + {"1 =:= 1", ?_assert(jiffy:decode(<<"1">>) =:= 1)} + ]. diff --git a/test/009-reg-issue-24.t b/test/jiffy_09_reg_issue_24_tests.erl old mode 100755 new mode 100644 similarity index 99% rename from test/009-reg-issue-24.t rename to test/jiffy_09_reg_issue_24_tests.erl index 8c50247..ca72d1b --- a/test/009-reg-issue-24.t +++ b/test/jiffy_09_reg_issue_24_tests.erl @@ -1,15 +1,18 @@ -#! /usr/bin/env escript % This file is part of Jiffy released under the MIT license. % See the LICENSE file for more information. -main([]) -> - code:add_pathz("ebin"), - code:add_pathz("test"), +-module(jiffy_09_reg_issue_24_tests). - etap:plan(1), - jiffy:encode(big_doc(), [uescape]), - etap:is(1, 1, "No segfault encoding large doc with uescapes."), - etap:end_tests(). + +-include_lib("proper/include/proper.hrl"). +-include_lib("eunit/include/eunit.hrl"). +-include("jiffy_util.hrl"). + + +no_segfault_test_() -> + {"no segfault", [ + ?_assert(begin jiffy:encode(big_doc(), [uescape]), true end) + ]}. big_doc() -> diff --git a/test/jiffy_10_short_double_tests.erl b/test/jiffy_10_short_double_tests.erl new file mode 100644 index 0000000..1c1d069 --- /dev/null +++ b/test/jiffy_10_short_double_tests.erl @@ -0,0 +1,34 @@ +% This file is part of Jiffy released under the MIT license. +% See the LICENSE file for more information. + +-module(jiffy_10_short_double_tests). + + +-include_lib("proper/include/proper.hrl"). +-include_lib("eunit/include/eunit.hrl"). +-include("jiffy_util.hrl"). + + +filename() -> "../test/cases/short-doubles.txt". + + +short_double_test() -> + {ok, Fd} = file:open(filename(), [read, binary, raw]), + {"all doubles round trip", ?assertEqual(0, run(Fd, 0))}. + + +run(Fd, Acc) -> + case file:read_line(Fd) of + {ok, Data} -> + V1 = re:replace(iolist_to_binary(Data), <<"\.\n">>, <<"">>), + V2 = iolist_to_binary(V1), + V3 = <<34, V2/binary, 34>>, + R = jiffy:encode(jiffy:decode(V3)), + case R == V3 of + true -> run(Fd, Acc); + false -> run(Fd, Acc + 1) + end; + eof -> + Acc + end. + diff --git a/test/jiffy_tests.erl b/test/jiffy_11_proper_tests.erl similarity index 82% rename from test/jiffy_tests.erl rename to test/jiffy_11_proper_tests.erl index 9ecea32..aca542e 100644 --- a/test/jiffy_tests.erl +++ b/test/jiffy_11_proper_tests.erl @@ -1,24 +1,35 @@ % This file is part of Jiffy released under the MIT license. % See the LICENSE file for more information. --module(jiffy_tests). +-module(jiffy_11_proper_tests). -ifdef(JIFFY_DEV). -include_lib("proper/include/proper.hrl"). -include_lib("eunit/include/eunit.hrl"). +-include("jiffy_util.hrl"). - -proper_test_() -> - PropErOpts = [ - {to_file, user}, +opts() -> + [ {max_size, 15}, {numtests, 1000} - ], - {timeout, 3600, ?_assertEqual([], proper:module(jiffy_tests, PropErOpts))}. - - -prop_encode_decode() -> + ]. + +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]), @@ -35,7 +46,7 @@ to_map_ejson(Vals) when is_list(Vals) -> to_map_ejson(Val) -> Val. -prop_map_encode_decode() -> +prop_map_enc_dec() -> ?FORALL(Data, json(), begin MapData = to_map_ejson(Data), @@ -44,20 +55,20 @@ prop_map_encode_decode() -> ). -endif. -prop_encode_decode_pretty() -> +prop_enc_dec_pretty() -> ?FORALL(Data, json(), begin Data == jiffy:decode(jiffy:encode(Data, [pretty])) end ). -prop_encode_not_crash() -> +prop_enc_no_crash() -> ?FORALL(Data, any(), begin catch jiffy:encode(Data), true end). -prop_decode_not_crash_bin() -> +prop_dec_no_crash_bin() -> ?FORALL(Data, binary(), begin catch jiffy:decode(Data), true end). -prop_decode_not_crash_any() -> +prop_dec_no_crash_any() -> ?FORALL(Data, any(), begin catch jiffy:decode(Data), true end). diff --git a/test/jiffy_util.hrl b/test/jiffy_util.hrl new file mode 100644 index 0000000..b8210e2 --- /dev/null +++ b/test/jiffy_util.hrl @@ -0,0 +1,25 @@ + +msg(Fmt, Args) -> + M1 = io_lib:format(Fmt, Args), + M2 = re:replace(M1, <<"\r">>, <<"\\\\r">>, [global]), + M3 = re:replace(M2, <<"\n">>, <<"\\\\n">>, [global]), + M4 = re:replace(M3, <<"\t">>, <<"\\\\t">>, [global]), + iolist_to_binary(M4). + + +hex(Bin) when is_binary(Bin) -> + H1 = [io_lib:format("16#~2.16.0B",[X]) || <> <= Bin], + H2 = string:join(H1, ", "), + lists:flatten(io_lib:format("<<~s>>", [lists:flatten(H2)])). + + +dec(V) -> + jiffy:decode(V). + + +enc(V) -> + iolist_to_binary(jiffy:encode(V)). + + +enc(V, Opts) -> + iolist_to_binary(jiffy:encode(V, Opts)). diff --git a/test/util.erl b/test/util.erl deleted file mode 100644 index ceaef89..0000000 --- a/test/util.erl +++ /dev/null @@ -1,44 +0,0 @@ --module(util). --export([test_good/1, test_good/2, test_errors/1]). - -test_good(Cases) -> - test_good(Cases, []). - -test_good(Cases, Options) -> - lists:foreach(fun(Case) -> check_good(Case, Options) end, Cases). - -test_errors(Cases) -> - lists:foreach(fun(Case) -> check_error(Case) end, Cases). - -ok_dec(J, _E) -> - lists:flatten(io_lib:format("Decoded ~p.", [J])). - -ok_enc(E, _J) -> - lists:flatten(io_lib:format("Encoded ~p", [E])). - -do_encode(E, Options) -> - iolist_to_binary(jiffy:encode(E, Options)). - -error_mesg(J) -> - lists:flatten(io_lib:format("Decoding ~p returns an error.", [J])). - -check_good({J, E}, Options) -> - etap:is(jiffy:decode(J), E, ok_dec(J, E)), - etap:is(do_encode(E, Options), J, ok_enc(E, J)); -check_good({J, E, J2}, Options) -> - etap:is(jiffy:decode(J), E, ok_dec(J, E)), - etap:is(do_encode(E, Options), J2, ok_enc(E, J2)). - -check_error({J, E}) -> - etap:fun_is( - fun({error, E1}) when E1 == E -> true; (E1) -> E1 end, - (catch jiffy:decode(J)), - error_mesg(J) - ); -check_error(J) -> - etap:fun_is( - fun({error, _}) -> true; (Else) -> Else end, - (catch jiffy:decode(J)), - error_mesg(J) - ). -