Port 190-json-stream-parse.t etap test suite to eunit
Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch/repo Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch/commit/50126cf7 Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch/tree/50126cf7 Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch/diff/50126cf7 Branch: refs/heads/1963-eunit-bigcouch Commit: 50126cf758a9640ee0d6efffb78cec600ce46f0e Parents: a3a9613 Author: Alexander Shorin <[email protected]> Authored: Wed Jun 4 13:22:13 2014 +0400 Committer: Russell Branca <[email protected]> Committed: Mon Aug 11 13:15:38 2014 -0700 ---------------------------------------------------------------------- test/couchdb/json_stream_parse_tests.erl | 151 ++++++++++++++++++++++++++ 1 file changed, 151 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/50126cf7/test/couchdb/json_stream_parse_tests.erl ---------------------------------------------------------------------- diff --git a/test/couchdb/json_stream_parse_tests.erl b/test/couchdb/json_stream_parse_tests.erl new file mode 100644 index 0000000..92303b6 --- /dev/null +++ b/test/couchdb/json_stream_parse_tests.erl @@ -0,0 +1,151 @@ +% Licensed under the Apache License, Version 2.0 (the "License"); you may not +% use this file except in compliance with the License. You may obtain a copy of +% the License at +% +% http://www.apache.org/licenses/LICENSE-2.0 +% +% Unless required by applicable law or agreed to in writing, software +% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +% License for the specific language governing permissions and limitations under +% the License. + +-module(json_stream_parse_tests). + +-include("couch_eunit.hrl"). + +-define(CASES, + [ + {1, "1", "integer numeric literial"}, + {3.1416, "3.14160", "float numeric literal"}, % text representation may truncate, trail zeroes + {-1, "-1", "negative integer numeric literal"}, + {-3.1416, "-3.14160", "negative float numeric literal"}, + {12.0e10, "1.20000e+11", "float literal in scientific notation"}, + {1.234E+10, "1.23400e+10", "another float literal in scientific notation"}, + {-1.234E-10, "-1.23400e-10", "negative float literal in scientific notation"}, + {10.0, "1.0e+01", "yet another float literal in scientific notation"}, + {123.456, "1.23456E+2", "yet another float literal in scientific notation"}, + {10.0, "1e1", "yet another float literal in scientific notation"}, + {<<"foo">>, "\"foo\"", "string literal"}, + {<<"foo", 5, "bar">>, "\"foo\\u0005bar\"", "string literal with \\u0005"}, + {<<"">>, "\"\"", "empty string literal"}, + {<<"\n\n\n">>, "\"\\n\\n\\n\"", "only new lines literal"}, + {<<"\" \b\f\r\n\t\"">>, "\"\\\" \\b\\f\\r\\n\\t\\\"\"", + "only white spaces string literal"}, + {null, "null", "null literal"}, + {true, "true", "true literal"}, + {false, "false", "false literal"}, + {<<"null">>, "\"null\"", "null string literal"}, + {<<"true">>, "\"true\"", "true string literal"}, + {<<"false">>, "\"false\"", "false string literal"}, + {{[]}, "{}", "empty object literal"}, + {{[{<<"foo">>, <<"bar">>}]}, "{\"foo\":\"bar\"}", + "simple object literal"}, + {{[{<<"foo">>, <<"bar">>}, {<<"baz">>, 123}]}, + "{\"foo\":\"bar\",\"baz\":123}", "another simple object literal"}, + {[], "[]", "empty array literal"}, + {[[]], "[[]]", "empty array literal inside a single element array literal"}, + {[1, <<"foo">>], "[1,\"foo\"]", "simple non-empty array literal"}, + {[1199344435545.0, 1], "[1199344435545.0,1]", + "another simple non-empty array literal"}, + {[false, true, 321, null], "[false, true, 321, null]", "array of literals"}, + {{[{<<"foo">>, [123]}]}, "{\"foo\":[123]}", + "object literal with an array valued property"}, + {{[{<<"foo">>, {[{<<"bar">>, true}]}}]}, + "{\"foo\":{\"bar\":true}}", "nested object literal"}, + {{[{<<"foo">>, []}, {<<"bar">>, {[{<<"baz">>, true}]}}, + {<<"alice">>, <<"bob">>}]}, + "{\"foo\":[],\"bar\":{\"baz\":true},\"alice\":\"bob\"}", + "complex object literal"}, + {[-123, <<"foo">>, {[{<<"bar">>, []}]}, null], + "[-123,\"foo\",{\"bar\":[]},null]", + "complex array literal"} + ] +). + + +raw_json_input_test_() -> + Tests = lists:map( + fun({EJson, JsonString, Desc}) -> + {Desc, + ?_assert(equiv(EJson, json_stream_parse:to_ejson(JsonString)))} + end, ?CASES), + {"Tests with raw JSON string as the input", Tests}. + +one_byte_data_fun_test_() -> + Tests = lists:map( + fun({EJson, JsonString, Desc}) -> + DataFun = fun() -> single_byte_data_fun(JsonString) end, + {Desc, + ?_assert(equiv(EJson, json_stream_parse:to_ejson(DataFun)))} + end, ?CASES), + {"Tests with a 1 byte output data function as the input", Tests}. + +test_multiple_bytes_data_fun_test_() -> + Tests = lists:map( + fun({EJson, JsonString, Desc}) -> + DataFun = fun() -> multiple_bytes_data_fun(JsonString) end, + {Desc, + ?_assert(equiv(EJson, json_stream_parse:to_ejson(DataFun)))} + end, ?CASES), + {"Tests with a multiple bytes output data function as the input", Tests}. + + +%% Test for equivalence of Erlang terms. +%% Due to arbitrary order of construction, equivalent objects might +%% compare unequal as erlang terms, so we need to carefully recurse +%% through aggregates (tuples and objects). +equiv({Props1}, {Props2}) -> + equiv_object(Props1, Props2); +equiv(L1, L2) when is_list(L1), is_list(L2) -> + equiv_list(L1, L2); +equiv(N1, N2) when is_number(N1), is_number(N2) -> + N1 == N2; +equiv(B1, B2) when is_binary(B1), is_binary(B2) -> + B1 == B2; +equiv(true, true) -> + true; +equiv(false, false) -> + true; +equiv(null, null) -> + true. + +%% Object representation and traversal order is unknown. +%% Use the sledgehammer and sort property lists. +equiv_object(Props1, Props2) -> + L1 = lists:keysort(1, Props1), + L2 = lists:keysort(1, Props2), + Pairs = lists:zip(L1, L2), + true = lists:all( + fun({{K1, V1}, {K2, V2}}) -> + equiv(K1, K2) andalso equiv(V1, V2) + end, + Pairs). + +%% Recursively compare tuple elements for equivalence. +equiv_list([], []) -> + true; +equiv_list([V1 | L1], [V2 | L2]) -> + equiv(V1, V2) andalso equiv_list(L1, L2). + +single_byte_data_fun([]) -> + done; +single_byte_data_fun([H | T]) -> + {<<H>>, fun() -> single_byte_data_fun(T) end}. + +multiple_bytes_data_fun([]) -> + done; +multiple_bytes_data_fun(L) -> + N = crypto:rand_uniform(0, 7), + {Part, Rest} = split(L, N), + {list_to_binary(Part), fun() -> multiple_bytes_data_fun(Rest) end}. + +split(L, N) when length(L) =< N -> + {L, []}; +split(L, N) -> + take(N, L, []). + +take(0, L, Acc) -> + {lists:reverse(Acc), L}; +take(N, [H|L], Acc) -> + take(N - 1, L, [H | Acc]).
