blob: d8ec474d1e7e07e9488e417320224d7bfae58b37 [file] [log] [blame]
%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
%% ex: ts=4 sw=4 et
%%
%% This file is part of Triq - Trifork QuickCheck
%%
%% Copyright (c) 2010-2013 by Trifork
%% Copyright 2013-2018 Triq authors
%%
%% 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(triq_statem_tests).
-export([ initial_state/0
, key/0
, command/1
, precondition/2
, postcondition/3
, next_state/3
]).
-include("triq.hrl").
%% use eunit
-include_lib("eunit/include/eunit.hrl").
%%
%% A simple statem test for the process dictionary; tests the
%% operations erlang:put/2, erlang:get/1 and and erlang:erase/1.
%%
prop_pdict_statem() ->
?FORALL(Cmds,
triq_statem:commands(?MODULE),
begin
triq_statem:run_commands(?MODULE, Cmds),
true
end).
-define(KEYS, [a,b,c,d]).
key() ->
oneof(?KEYS).
initial_state() ->
lists:filter(fun({Key,_}) -> lists:member(Key, ?KEYS) end,
erlang:get()).
command([]) ->
{call, erlang, put, [key(), int()]};
command(Props) ->
?LET({Key,Value}, frequency([{5, elements(Props)},
{1, {key(),int()}}]),
oneof([{call, erlang, put, [Key, Value]},
{call, erlang, get, [Key]},
{call, erlang, erase, [Key]}
])).
precondition(_, {call, erlang, put, [_,_]}) ->
true;
precondition(Props, {call, erlang, get, [Key]}) ->
proplists:is_defined(Key,Props);
precondition(Props, {call, erlang, erase, [Key]}) ->
proplists:is_defined(Key,Props);
precondition(_,_) ->
false.
postcondition(Props, {call, erlang, put, [Key,_]}, undefined) ->
not proplists:is_defined(Key,Props);
postcondition(Props, {call, erlang, put, [Key,_]}, Old) ->
{Key,Old} == proplists:lookup(Key,Props);
postcondition(Props, {call, erlang, get, [Key]}, Val) ->
{Key,Val} == proplists:lookup(Key,Props);
postcondition(Props, {call, erlang, erase, [Key]}, Val) ->
{Key,Val} == proplists:lookup(Key,Props);
postcondition(_,_,_) ->
false.
next_state(Props, _Var, {call, erlang, put, [Key,Value]}) ->
[{Key,Value}] ++ Props;
next_state(Props, _Var, {call, erlang, erase, [Key]}) ->
proplists:delete(Key,Props);
next_state(Props, _Var, {call, erlang, get, [_]}) ->
Props.
%% -------------------------------------------------------------------
%% Property Testing
%% -------------------------------------------------------------------
run_property_testing_test_() ->
{timeout, 60, fun run_property_testing_case/0}.
run_property_testing_case() ->
EunitLeader = erlang:group_leader(),
erlang:group_leader(whereis(user), self()),
Res = triq:module(?MODULE),
erlang:group_leader(EunitLeader, self()),
?assert(Res).