Skip to content

Instantly share code, notes, and snippets.

@davisp
Created November 14, 2011 15:01
Show Gist options
  • Save davisp/1364115 to your computer and use it in GitHub Desktop.
Save davisp/1364115 to your computer and use it in GitHub Desktop.
PropEr tests for couch_btree.erl
-module(proper_btree_tests).
-behaviour(proper_statem).
-include_lib("proper/include/proper.hrl").
-include_lib("eunit/include/eunit.hrl").
-export([
initial_state/0,
command/1,
precondition/2,
postcondition/3,
next_state/3
]).
-record(state, {fd, bt, elements}).
proper_test_() ->
catch meck:unload(couch_config),
meck:new(couch_config),
meck:expect(couch_config, get,
fun("couchdb", "btree_chunk_size", _) -> "1279" end
),
PropErOpts = [
{to_file, user},
{max_size, 60},
{numtests, 1000}
],
{timeout, 3600, ?_assertEqual([], proper:module(?MODULE, PropErOpts))}.
prop_btree_basics() ->
?FORALL(Cmds, commands(?MODULE),
begin
{H, S, R} = run_commands(?MODULE, Cmds),
cleanup(S),
io:format(standard_error, "History: ~p~n", [H]),
io:format(standard_error, "State: ~p~n", [S]),
io:format(standard_error, "Result: ~p~n", [R]),
R =:= ok
end
).
initial_state() ->
{ok, Fd} = couch_file:open("propercouch.btree", [create, overwrite]),
{ok, Bt} = couch_btree:open(nil, Fd),
#state{fd = Fd, bt = Bt, elements = dict:new()}.
command(S) ->
oneof([
{call, couch_btree, add, [S#state.bt, kvs()]},
{call, couch_btree, lookup, [S#state.bt, keys()]}
]).
precondition(_, {call, _, add, [_, KVs]}) ->
Ks = [K || {K, _} <- KVs],
length(lists:usort(Ks)) == length(Ks);
precondition(_, _) ->
true.
postcondition(S, {call, _, add, [_, KVs]}, _Result) ->
io:format(standard_error, "E: ~p~n", [dict:to_list(S#state.elements)]),
io:format(standard_error, "S: ~p~n~p~n", [S, KVs]),
lists:all(fun({K, V}) ->
{ok, V} =:= dict:find(K, S#state.elements)
end, KVs);
postcondition(S, {call, _, lookup, [_, Keys]}, Results) ->
#state{elements = L} = S,
lists:all(fun
({Key, {ok, {Key, Val}}}) -> {ok, Val} == dict:find(Key, L);
({Key, not_found}) -> not dict:is_key(Key, L)
end, lists:zip(Keys, Results)).
next_state(S, V, {call, _, add, [_, KVs]}) ->
Elems = lists:foldl(fun({K, V}, Acc) ->
dict:store(K, V, Acc)
end, S#state.elements, KVs),
S#state{
bt = {call, erlang, element, [2, V]},
elements = Elems
};
next_state(S, _V, {call, _, lookup, [_, _]}) ->
S;
next_state(S, _V, _C) ->
S.
cleanup(S) ->
exit(kill, S#state.fd),
file:delete("propercouch.btree").
%% Generators
kvs() ->
list({any(), any()}).
keys() ->
list(any()).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment