CirqBuff and MBox QuickCheck Models
From CERES
This page contains the complete CirqBuff and MBox QuickCheck models described in the paper entitled Modelling of Autosar Libraries for Large Scale Testing by Wojciech Mostowski, Thomas Arts, and John Hughes. The complete model archive can be downloaded here, below the complete model quote. The C source files referenced by the model are available on request, please contact Wojciech Mostowski.
Contents
source_path.hrl
-define(AUTOSAR_SRC, ".").
qc_cb.hrl
-record(cb_state, {ptr, size, elements, data_size}).
qc_cb_setup.erl
-module(qc_cb_setup).
-export([ setup/0 ]).
-include_lib("eqc/include/eqc_c.hrl").
-include_lib("source_path.hrl").
setup() -> eqc_c:start(cb,
[ {cppflags, "-std=c99 -I " ++ ?AUTOSAR_SRC ++ "/include"},
{c_src, ?AUTOSAR_SRC ++ "/src/cirq_buffer.c"} ]).
qc_cb.erl
-module(qc_cb).
-compile(export_all).
-include_lib("eqc/include/eqc.hrl").
-include_lib("eqc/include/eqc_component.hrl").
-include_lib("cb.hrl"). % Auto-generated
-include_lib("qc_cb.hrl").
initial_state() -> #cb_state{ elements=[] }.
invariant(S) -> length(S#cb_state.elements) =< S#cb_state.size.
postcondition_common(_S, {call, _, create, _, _ }, _Res) -> true;
postcondition_common(S, Call, Res) -> eq(Res, return_value(S, Call)).
create(Size, DataSize) -> cb:'CirqBuffDynCreate'(Size, DataSize).
create_args(_S) -> [nat(), nat()].
create_pre(S, [Size, _DataSize]) -> S#cb_state.ptr == undefined andalso Size > 0.
create_next(S, R, [Size, DataSize]) ->
S#cb_state{ptr=R, size=Size, data_size = DataSize }.
create_callers() -> [qc_mbox].
create_return(_S, [Size, DataSize]) ->
#'CirqBufferType' { maxCnt = Size, currCnt = 0, dataSize = DataSize,
head = 'NULL', tail = 'NULL', bufStart = 'NULL', bufEnd = 'NULL' }.
push(Ptr, Val) -> DataPtr = eqc_c:create_array(unsigned_char, Val),
CallRes = cb:'CirqBuffPush'(Ptr, DataPtr), eqc_c:free(DataPtr), CallRes.
push_args(S) -> [S#cb_state.ptr, vector(S#cb_state.data_size, char())].
push_pre(S) ->
S#cb_state.ptr /= undefined andalso length(S#cb_state.elements) < S#cb_state.size.
push_next(S, _R, [_Ptr, Value]) ->
S#cb_state{elements = S#cb_state.elements ++ [Value]}.
push_return(S, _Args) -> % 0.
if length(S#cb_state.elements) < 128 -> 0; true -> 1 end.
push_callers() -> [qc_mbox].
pop(Ptr, DataSize) ->
DataPtr = eqc_c:create_array(unsigned_char, [0 || _E <- lists:seq(1, DataSize)]),
CallRes = cb:'CirqBuffPop'(Ptr, DataPtr),
DataRes = eqc_c:read_array(DataPtr, DataSize),
eqc_c:free(DataPtr), {DataRes, CallRes}.
pop_args(S) -> [S#cb_state.ptr, S#cb_state.data_size].
pop_pre(S) ->
S#cb_state.ptr /= undefined andalso length(S#cb_state.elements) > 0.
pop_next(S, _R, _Args) -> S#cb_state{elements = tl(S#cb_state.elements)}.
pop_return(S, _Args) -> {hd(S#cb_state.elements), 0}.
pop_callers() -> [qc_mbox].
prop_cb_length() -> ?SETUP(fun() -> qc_cb_setup:setup(), fun() -> ok end end,
?FORALL(Cmds, commands(?MODULE),
begin {H, S, Res} = run_commands(Cmds),
aggregate(command_names(Cmds),
measure(num_commands,
commands_length(Cmds),
pretty_commands(?MODULE, Cmds, {H, S, Res}, Res == ok))) end)).
prop_cb() -> ?SETUP(fun() -> qc_cb_setup:setup(), fun() -> ok end end,
?FORALL(Cmds, commands(?MODULE),
begin {_, _, Res} = run_commands(Cmds), Res == ok end)).
qc_mbox.hrl
-record(mbox_state, {ptr, size, elements, cb_state}).
qc_mbox_capi.erl
-include_lib("source_path.hrl").
api_spec() -> #api_spec {
language = c, mocking = eqc_mocking_c,
modules = [ #api_module{ name = mbox, functions = [
#api_fun_c{ name = 'CirqBuffDynCreate', ret = 'CirqBufferType *',
args = [ #api_arg_c{type = size_t, name = size, dir = in},
#api_arg_c{type = size_t, name = dataSize, dir = in} ],
classify = {qc_cb, create} },
#api_fun_c{ name = 'CirqBuffPush', ret = int,
args = [ #api_arg_c{type = 'CirqBufferType *', name = cPtr, dir = in},
#api_arg_c{ type = 'void *', name = dataPtr, dir = in,
stored_type = 'unsigned char *',
buffer = {true, "cPtr->dataSize"}} ],
classify = {qc_cb, push} },
#api_fun_c{ name = 'CirqBuffPop', ret = int,
args = [ #api_arg_c{type = 'CirqBufferType *', name = cPtr, dir = in},
#api_arg_c{ type = 'void *', name = dataPtr, dir = out,
stored_type = 'unsigned char *',
buffer = {true, "cPtr->dataSize"}} ],
classify = {qc_cb, pop} }]}]}.
start_mocking() -> eqc_mocking_c:start_mocking(mbox, ?MODULE:api_spec(),
[ "Std_Types.h", "cirq_buffer.h", "mbox.h" ],
[ ?AUTOSAR_SRC ++ "/src/mbox.c" ],
[ {cppflags, "-std=c99 -I . -I " ++ ?AUTOSAR_SRC ++ "/include"} ]).
qc_mbox_setup.erl
-module(qc_mbox_setup).
-compile(export_all).
-include_lib("eqc/include/eqc_c.hrl").
-include_lib("eqc/include/eqc_mocking.hrl").
-include("qc_mbox_capi.erl").
qc_mbox.erl
-module(qc_mbox).
-compile(export_all).
-include_lib("eqc/include/eqc.hrl").
-include_lib("eqc/include/eqc_component.hrl").
-include_lib("qc_mbox.hrl").
-include_lib("qc_cb.hrl").
-include("mbox.hrl"). % Auto-generated
-include("qc_mbox_capi.erl").
-define(PTR_SIZE, 8). % Change resp. for test running platform (here 64 bit arch.)
initial_state() -> #mbox_state{ elements=[] }.
invariant(S) -> length(S#mbox_state.elements) =< S#mbox_state.size.
postcondition_common(_S, {call, _, create, _, _ }, _R) -> true;
postcondition_common(S, Call, Res) -> eq(Res, return_value(S, Call)).
create(Size) -> mbox:'Arc_MBoxCreate'(Size).
create_args(_S) -> [choose(1, 256)].
create_pre(S, [Size]) -> S#mbox_state.ptr == undefined andalso Size > 0.
create_next(S, R, [Size]) -> S#mbox_state{ptr=R, size=Size }.
create_callouts(_S, [Size]) ->
?CALLOUT(mbox, 'CirqBuffDynCreate', [Size, ?PTR_SIZE],
#'CirqBufferType' { maxCnt = Size, currCnt = 0,
dataSize = 8, head = 'NULL', tail = 'NULL',
bufStart = 'NULL', bufEnd = 'NULL'}).
post(Ptr, Val) ->
DataPtr = eqc_c:create_array(unsigned_char, Val),
CallRes = mbox:'Arc_MBoxPost'(Ptr, DataPtr),
eqc_c:free(DataPtr), CallRes.
post_args(S) -> [S#mbox_state.ptr, vector(?PTR_SIZE, char())].
post_pre(S) -> S#mbox_state.ptr /= undefined
andalso length(S#mbox_state.elements) < S#mbox_state.size.
post_next(S, _R, [_Ptr, Value]) ->
S#mbox_state{elements = S#mbox_state.elements ++ [Value]}.
post_return(_S, _Args) -> 0.
post_callouts(S, [_Ptr, Value]) ->
?CALLOUT(mbox, 'CirqBuffPush', [?WILDCARD, Value],
if length(S#mbox_state.elements) < 128 -> 0; true -> 1 end).
fetch(Ptr) ->
DataPtr = eqc_c:create_array(unsigned_char, [0 || _E <- lists:seq(1, ?PTR_SIZE)]),
CallRes = mbox:'Arc_MBoxFetch'(Ptr, DataPtr),
DataRes = eqc_c:read_array(DataPtr, ?PTR_SIZE),
eqc_c:free(DataPtr), {DataRes, CallRes}.
fetch_args(S) -> [S#mbox_state.ptr].
fetch_pre(S) ->
S#mbox_state.ptr /= undefined andalso length(S#mbox_state.elements) > 0.
fetch_next(S, _R, [_Ptr]) -> S#mbox_state{elements = tl(S#mbox_state.elements)}.
fetch_return(S, [_Ptr]) -> {hd(S#mbox_state.elements), 0}.
fetch_callouts(S, [_Ptr]) ->
?CALLOUT(mbox, 'CirqBuffPop', [?WILDCARD], { hd(S#mbox_state.elements), 0}).
weight(#mbox_state{ptr = undefined}, Op) -> case Op of create -> 1; _ -> 0 end;
weight(_S, create) -> 0; weight(_S, post) -> 5; weight(_S, fetch) -> 1.
prop_mbox() ->
?SETUP(fun() -> qc_mbox:start_mocking(), fun() -> ok end end,
?FORALL(Cmds, more_commands(50, commands(?MODULE)),
begin {H, S, Res} = run_commands(Cmds),
aggregate(command_names(Cmds),
pretty_commands(?MODULE, Cmds, {H, S, Res}, Res == ok)) end)).
qc_cluster.erl
-module(qc_cluster).
-compile(export_all).
-include_lib("eqc/include/eqc.hrl").
-include_lib("eqc/include/eqc_cluster.hrl").
-include_lib("source_path.hrl").
components() -> [qc_cb, qc_mbox].
api_spec() -> eqc_cluster:api_spec(?MODULE).
setup_mocking() ->
eqc_mocking_c:start_mocking(mbox, api_spec(),
[ "cirq_buffer.h", "mbox.h" ],
[ ?AUTOSAR_SRC ++ "/src/mbox.c", ?AUTOSAR_SRC ++ "/src/cirq_buffer.c" ],
[ {cppflags, "-std=c99 -I " ++ ?AUTOSAR_SRC ++ "/include"} ],
components()).
property_mbox_cluster() ->
?SETUP(fun() -> setup_mocking(), fun() -> ok end end,
?FORALL(Cmds, commands(?MODULE),
begin {H, S, Res} = run_commands(Cmds),
aggregate(command_names(Cmds),
pretty_commands(?MODULE, Cmds, {H, S, Res}, Res == ok)) end )).