Skip to content

Commit c932eef

Browse files
committed
Crash test for #224
1 parent 493d61e commit c932eef

File tree

2 files changed

+173
-31
lines changed

2 files changed

+173
-31
lines changed

test/parallel_crash_tests.erl

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
-module(parallel_crash_tests).
2+
3+
-include_lib("proper/include/proper.hrl").
4+
5+
-include_lib("eunit/include/eunit.hrl").
6+
7+
8+
%%------------------------------------------------------------------------------
9+
%% Helper macros
10+
%%------------------------------------------------------------------------------
11+
12+
%% NOTE: Never add long_result to Opts for these macros.
13+
14+
state_is_clean() ->
15+
get() =:= [].
16+
17+
assertEqualsOneOf(_X, none) ->
18+
ok;
19+
assertEqualsOneOf(X, List) ->
20+
?assert(lists:any(fun(Y) -> Y =:= X end, List)).
21+
22+
-define(_passes(Test),
23+
?_passes(Test, [])).
24+
25+
-define(_passes(Test, Opts),
26+
?_assertRun(true, Test, Opts, true)).
27+
28+
-define(_errorsOut(ExpReason, Test),
29+
?_errorsOut(ExpReason, Test, [])).
30+
31+
-define(_errorsOut(ExpReason, Test, Opts),
32+
?_assertRun({error,ExpReason}, Test, Opts, true)).
33+
34+
-define(_assertRun(ExpResult, Test, Opts, AlsoLongResult),
35+
?_test(begin
36+
?assertMatch(ExpResult, proper:quickcheck(Test,Opts)),
37+
proper:clean_garbage(),
38+
?assert(state_is_clean()),
39+
case AlsoLongResult of
40+
true ->
41+
?assertMatch(ExpResult,
42+
proper:quickcheck(Test,[long_result|Opts])),
43+
proper:clean_garbage(),
44+
?assert(state_is_clean());
45+
false ->
46+
ok
47+
end
48+
end)).
49+
50+
-define(_assertCheck(ExpShortResult, CExm, Test),
51+
?_assertCheck(ExpShortResult, CExm, Test, [])).
52+
53+
-define(_assertCheck(ExpShortResult, CExm, Test, Opts),
54+
?_test(?assertCheck(ExpShortResult, CExm, Test, Opts))).
55+
56+
-define(assertCheck(ExpShortResult, CExm, Test, Opts),
57+
begin
58+
?assertMatch(ExpShortResult, proper:check(Test,CExm,Opts)),
59+
?assert(state_is_clean())
60+
end).
61+
62+
-define(_fails(Test),
63+
?_fails(Test, [])).
64+
65+
-define(_fails(Test, Opts),
66+
?_failsWith(_, Test, Opts)).
67+
68+
-define(_failsWith(ExpCExm, Test),
69+
?_failsWith(ExpCExm, Test, [])).
70+
71+
-define(_failsWith(ExpCExm, Test, Opts),
72+
?_assertFailRun(ExpCExm, none, Test, Opts)).
73+
74+
-define(_failsWithOneOf(AllCExms, Test),
75+
?_failsWithOneOf(AllCExms, Test, [])).
76+
77+
-define(_failsWithOneOf(AllCExms, Test, Opts),
78+
?_assertFailRun(_, AllCExms, Test, Opts)).
79+
80+
-define(SHRINK_TEST_OPTS, [{start_size,10},{max_shrinks,10000}]).
81+
82+
-define(_shrinksTo(ExpShrunk, Type),
83+
?_assertFailRun([ExpShrunk], none, ?FORALL(_X,Type,false),
84+
?SHRINK_TEST_OPTS)).
85+
86+
-define(_shrinksToOneOf(AllShrunk, Type),
87+
?_assertFailRun(_, [[X] || X <- AllShrunk], ?FORALL(_X,Type,false),
88+
?SHRINK_TEST_OPTS)).
89+
90+
-define(_nativeShrinksTo(ExpShrunk, TypeStr),
91+
?_assertFailRun([ExpShrunk], none,
92+
?FORALL(_X,assert_can_translate(?MODULE,TypeStr),false),
93+
?SHRINK_TEST_OPTS)).
94+
95+
-define(_nativeShrinksToOneOf(AllShrunk, TypeStr),
96+
?_assertFailRun(_, [[X] || X <- AllShrunk],
97+
?FORALL(_X,assert_can_translate(?MODULE,TypeStr),false),
98+
?SHRINK_TEST_OPTS)).
99+
100+
-define(_assertFailRun(ExpCExm, AllCExms, Test, Opts),
101+
?_test(begin
102+
ShortResult = proper:quickcheck(Test, Opts),
103+
CExm1 = get_cexm(),
104+
?checkCExm(CExm1, ExpCExm, AllCExms, Test, Opts),
105+
?assertEqual(false, ShortResult),
106+
LongResult = proper:quickcheck(Test, [long_result|Opts]),
107+
CExm2 = get_cexm(),
108+
?checkCExm(CExm2, ExpCExm, AllCExms, Test, Opts),
109+
?checkCExm(LongResult, ExpCExm, AllCExms, Test, Opts)
110+
end)).
111+
112+
113+
simple_test_() ->
114+
[
115+
?_passes(symb_statem:prop_simple())
116+
].
117+
118+
119+
parallel_simple_test_() ->
120+
[
121+
%% {timeout, 20, ?_passes(symb_statem:prop_parallel_simple())}
122+
?_passes(symb_statem:prop_parallel_simple())
123+
].

test/symb_statem.erl

Lines changed: 50 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -28,62 +28,81 @@
2828
-module(symb_statem).
2929

3030
-export([command/1,
31-
initial_state/0, next_state/3,
32-
precondition/2, postcondition/3]).
33-
-export([foo/1, bar/1]).
31+
initial_state/0, next_state/3,
32+
precondition/2, postcondition/3]).
33+
-export([foo/1, bar/1, croak/0]).
3434
-export([prop_simple/0, prop_parallel_simple/0]).
3535

3636
-include_lib("proper/include/proper.hrl").
3737

3838
-record(state, {foo = [] :: list(),
39-
bar = [] :: list()}).
39+
bar = [] :: list()
40+
}).
4041
-type state() :: #state{}.
4142

4243
-spec initial_state() -> state().
4344
initial_state() ->
44-
#state{}.
45+
#state{}.
4546

4647
command(_S) ->
47-
oneof([{call,?MODULE,foo,[integer()]},
48-
{call,?MODULE,bar,[integer()]}]).
48+
oneof([{call,?MODULE,foo,[integer()]},
49+
{call,?MODULE,croak,[]},
50+
{call,?MODULE,bar,[integer()]}]).
4951

5052
precondition(_, _) ->
51-
true.
53+
true.
5254

55+
next_state(S, _V, {call,_,croak,[]}) ->
56+
S;
5357
next_state(S = #state{foo=Foo}, V, {call,_,foo,[_Arg]}) ->
54-
V1 = {call,erlang,element,[1,V]},
55-
S#state{foo = [V1|Foo]};
58+
V1 = {call,erlang,element,[1,V]},
59+
S#state{foo = [V1|Foo]};
5660
next_state(S = #state{bar=Bar}, V, {call,_,bar,[_Arg]}) ->
57-
V1 = {call,erlang,hd,[V]},
58-
S#state{bar = [V1|Bar]}.
61+
V1 = {call,erlang,hd,[V]},
62+
S#state{bar = [V1|Bar]}.
5963

6064
postcondition(S, {call,_,foo,[_Arg]}, Res) when is_tuple(Res) ->
61-
lists:all(fun is_integer/1, S#state.foo);
65+
lists:all(fun is_integer/1, S#state.foo);
6266
postcondition(S, {call,_,bar,[_Arg]}, Res) when is_list(Res) ->
63-
lists:all(fun is_integer/1, S#state.bar);
67+
lists:all(fun is_integer/1, S#state.bar);
68+
postcondition(_, {call,_,croak,[]}, _) ->
69+
true;
6470
postcondition(_, _, _) ->
65-
false.
71+
false.
6672

6773
foo(I) when is_integer(I) ->
68-
erlang:make_tuple(3, I).
74+
io:format(user, "foo\n", []),
75+
erlang:make_tuple(3, I).
6976

7077
bar(I) when is_integer(I) ->
71-
lists:duplicate(3, I).
78+
lists:duplicate(3, I).
79+
80+
croak() ->
81+
io:format(user, "croaking now\n", []),
82+
1/0.
7283

7384
prop_simple() ->
74-
?FORALL(Cmds, commands(?MODULE),
75-
begin
76-
{H,S,Res} = run_commands(?MODULE, Cmds),
77-
?WHENFAIL(
78-
io:format("H: ~w\nState: ~w\n:Res: ~w\n", [H,S,Res]),
79-
Res =:= ok)
80-
end).
85+
?FORALL(Cmds, commands(?MODULE),
86+
begin
87+
{H,S,Res} = run_commands(?MODULE, Cmds),
88+
?WHENFAIL(
89+
io:format("H: ~w\nState: ~w\n:Res: ~w\n", [H,S,Res]),
90+
Res =:= ok)
91+
end).
92+
93+
croaking_commands() ->
94+
exactly({
95+
[{set,{var,1},{call,symb_statem,foo,[1]}}], % seq
96+
[
97+
[{set,{var,2},{call,symb_statem,croak,[]}}], % proc 1
98+
[] % proc 2
99+
]}).
81100

82101
prop_parallel_simple() ->
83-
?FORALL(Cmds, parallel_commands(?MODULE),
84-
begin
85-
{S,P,Res} = run_parallel_commands(?MODULE, Cmds),
86-
?WHENFAIL(
87-
io:format("Seq: ~w\nParallel: ~w\n:Res: ~w\n", [S,P,Res]),
88-
Res =:= ok)
89-
end).
102+
?FORALL(Cmds, croaking_commands(),
103+
begin
104+
{S,P,Res} = run_parallel_commands(?MODULE, Cmds),
105+
?WHENFAIL(
106+
io:format(user, "Seq: ~w\nParallel: ~w\n:Res: ~w\n", [S,P,Res]),
107+
Res =:= ok)
108+
end).

0 commit comments

Comments
 (0)