%% -*- 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_fsm_stub). -export([command/2, initial_state/1, next_state/4, postcondition/4, precondition/3]). -import(triq_dom, [oneof/1]). %% %% An instance of this module implements the "statem" API, but %% delegates calls to an underlying implementation of the "fsm" API. %% precondition(Module, {FromName, StateData}, Call) -> case find_next_state(Module, FromName, StateData, Call) of [ToName] -> Module:precondition(FromName, ToName, StateData, Call); _ -> false end. postcondition(Module, {ToName, StateData}, Call, Result) -> Module:postcondition(undefined, ToName, StateData, Call, Result). next_state(Module, {FromName, StateData}, Result, Call) -> case find_next_state(Module, FromName, StateData, Call) of [ToName] -> ToStateData = Module:next_state_data(FromName, ToName, StateData, Result, Call), {ToName, ToStateData}; [_|_] -> exit({multiple_choise, FromName, Call}); [] -> exit({no_transition, FromName, Call}) end. command(Module, {FromName, StateData}) -> Calls = [ Call || {_ToName, Call} <- Module:FromName( StateData ) ], oneof( Calls ). initial_state(Module) -> %% TODO: Some fsm specs return additional data as the 2nd element %% of a tuple. How should that data be used for the state? Name = case Module:initial_state() of {State, _} -> State; State when is_atom(State) -> State end, { Name, Module:initial_state_data() }. %% INTERNAL find_next_state(Module, FromName, StateData, {call, M,F,Arg}=_Call) -> Candidates1 = Module:FromName(StateData), Candidates2 = lists:foldl(fun ({ToName, {call, M2, F2, ArgDom}}, Acc) when M2 == M, F2 == F -> case length(ArgDom) == length(Arg) of true when ToName == history -> ordsets:add_element(FromName, Acc); true -> ordsets:add_element(ToName, Acc); false -> Acc end; (_, Acc) -> Acc end, ordsets:new(), Candidates1), ordsets:to_list(Candidates2).