瀏覽代碼

Implement PropEr tests for JSON parsing

Big thanks to Dmitry Groshev [1] for help getting PropEr tests into
Jiffy. These generate valid EJSON to check parsing as well as check
that random inputs don't cause segfaults or other nasty effects.

Future improvements would be to write a JSON generator as well as a
version that introduces known errors into the binary for checking known
parsing errors as well.

[1] https://github.com/si14

Fixes: #10
pull/11/head
Paul J. Davis 13 年之前
父節點
當前提交
ffa2fafa28
共有 4 個檔案被更改,包括 178 行新增5 行删除
  1. +3
    -1
      .gitignore
  2. +23
    -4
      Makefile
  3. +14
    -0
      rebar.config
  4. +138
    -0
      test/jiffy_tests.erl

+ 3
- 1
.gitignore 查看文件

@ -1,4 +1,6 @@
*.app
*.beam
*.o
*.so
ebin/jiffy.app
.eunit
deps

+ 23
- 4
Makefile 查看文件

@ -1,11 +1,30 @@
all: build
%.beam: %.erl
erlc -o test/ $<
clean:
./rebar clean
rm -rf logs
rm -rf .eunit
deps: ./deps/
./rebar get-deps update-deps
build: c_src/decoder.c
build: deps
./rebar compile
check: test/etap.beam test/util.beam
etap: test/etap.beam test/util.beam
prove test/*.t
eunit:
./rebar eunit skip_deps=true
check: etap eunit
%.beam: %.erl
erlc -o test/ $<

+ 14
- 0
rebar.config 查看文件

@ -1,3 +1,8 @@
{deps, [
{proper, ".*", {git, "https://github.com/manopapad/proper.git", "master"}}
]}.
{port_sources, ["c_src/*.c"]}.
{so_name, "jiffy.so"}.
{port_envs, [
@ -15,3 +20,12 @@
{"darwin10.*-32$", "CXXFLAGS", "-m32"},
{"darwin10.*-32$", "LDFLAGS", "-arch i386"}
]}.
{eunit_opts, [
verbose,
{report, {
eunit_surefire, [{dir,"."}]
}}
]}.

+ 138
- 0
test/jiffy_tests.erl 查看文件

@ -0,0 +1,138 @@
% This file is part of Jiffy released under the MIT license.
% See the LICENSE file for more information.
-module(jiffy_tests).
-include_lib("proper/include/proper.hrl").
-include_lib("eunit/include/eunit.hrl").
proper_test_() ->
PropErOpts = [
{to_file, user},
{max_size, 60},
{numtests, 1000}
],
{timeout, 3600, ?_assertEqual([], proper:module(jiffy_tests, PropErOpts))}.
prop_encode_decode() ->
?FORALL(Data, json(),
begin
%io:format(standard_error, "Data: ~p~n", [Data]),
ExpData = conv_keys(Data),
ExpData == jiffy:decode(jiffy:encode(Data))
end
).
prop_encode_not_crash() ->
?FORALL(Data, any(), begin catch jiffy:encode(Data), true end).
prop_decode_not_crash_bin() ->
?FORALL(Data, binary(), begin catch jiffy:decode(Data), true end).
prop_decode_not_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_key() ->
oneof([json_string(), escaped_atom()]).
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_key(), 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)).
escaped_atom() ->
?LET(A, atom(),
unicode:characters_to_binary(atom_to_list(A), unicode, utf8)
).
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 -> C
end
).
% Atoms get munged to binaries in the round trip.
conv_keys({Props}) ->
{lists:map(fun({K, V}) -> {conv_key(K), conv_keys(V)} end, Props)};
conv_keys(Vals) when is_list(Vals) ->
lists:map(fun(V) -> conv_keys(V) end, Vals);
conv_keys(Other) ->
Other.
conv_key(K) when is_atom(K) ->
list_to_binary(atom_to_list(K));
conv_key(K) ->
K.

Loading…
取消
儲存