mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-16 01:43:35 +00:00
Estimated hours taken: 10 Branches: main, release Fix the monitors that were computing coverage rates in Morphine. The problem was the following. In order to check that two successes and one failure occur for a multi predicate, I was looking at two exits and one fail; but this is wrong since, of course, the two exits can be produced by different calls, and since all multi predicates ends up with a fail event. To get it right, I need to associate the call number to exit and fail events. To do that, I maintain at exit ports the list of call numbers; when an exit event occurs, I consider it as covered iff the current call number is in the list. On the contrary, I consider a failure as covered at a fail port iff the current call number is not in the list. This also holds for semidet and nondet procedures. extras/morphine/non-regression-tests/queens.exp: Update the new expected outputs. extras/morphine/non-regression-tests/queens.in: Update the year of the copyrigth message. extras/morphine/source/call_site_cov.in: extras/morphine/source/pred_cov.in: Change the code so that it does what it is supposed to do. Also use a map instead of a list to store what has to be covered for each procedure. extras/morphine/source/generate_pred_cov.m: extras/morphine/source/generate_call_site_cov.m: extras/morphine/source/coverage_util.m: Generate an initialize/1 predicate that uses map instead of lists. extras/morphine/source/coverage.op: Coverage monitors now output assoc lists.
174 lines
5.7 KiB
Plaintext
174 lines
5.7 KiB
Plaintext
%------------------------------------------------------------------------------%
|
|
% Copyright (C) 2001, 2002 IFSIC.
|
|
% This file may only be copied under the terms of the GNU Library General
|
|
% Public License - see the file License in the Morphine distribution.
|
|
%
|
|
% Author : Erwan Jahier <jahier@irisa.fr>
|
|
%
|
|
% This file implements the coverage scenario, which provides various commands
|
|
% to perform test coverage.
|
|
|
|
|
|
opium_scenario(
|
|
name : coverage,
|
|
files : [coverage],
|
|
scenarios : [],
|
|
message :
|
|
"Provides commands to perform predicate and call site coverage.\
|
|
"
|
|
).
|
|
|
|
|
|
%-----------------------------------------------------------------------%
|
|
opium_command(
|
|
name : pred_cov,
|
|
arg_list : [Call, Uncovered],
|
|
arg_type_list : [string, var],
|
|
abbrev : pc,
|
|
interface : menu,
|
|
command_type : opium,
|
|
implementation : pred_cov_Op,
|
|
parameters : [],
|
|
message :
|
|
"Takes a call to Mercury program (compiled in a debug mode) \
|
|
(\"Call\") and unifies its 2nd argument with the uncovered predicate \
|
|
criteria of the called module as well as the modules it imports which \
|
|
are in the current directory. A predicate criterion is a \
|
|
3-tuple containing a module name, a procedure name, and a list of `exit' and \
|
|
`fail' atoms; for example, the predicate criterion \
|
|
`pc(mod, foo, [exit, fail])' means that the procedure foo in module mod \
|
|
has to succeed and fail exactly once to be considered as covered. \
|
|
\n\
|
|
\n\
|
|
pred_cov/2 works as follows; it calls `morphine/bin/generate_pred_cov \
|
|
<Module>.m' which generates 2 files: \"<Module>__pred_cov\" that contains \
|
|
a monitor to perform the coverage, and \"<Module>__pred\" that contains \
|
|
the list of call sites of <Module>. Then it runs the \"<Module>__pred_cov\" \
|
|
monitor, which outputs the list of uncovered call sites. The file \
|
|
\"<Module>__pred\" is used to display the coverage ratio.\
|
|
").
|
|
|
|
pred_cov_Op(ProgramCall, Uncovered) :-
|
|
split_string(ProgramCall, " ", " ", [Module|_Args]),
|
|
append_strings(Module, ".m", FileName),
|
|
getenv("MERCURY_MORPHINE_DIR", MorphineDir),
|
|
( exists("pred_cov.in") ->
|
|
true
|
|
;
|
|
concat_string(["ln -s ", MorphineDir,
|
|
"/source/pred_cov.in "], Cmd1),
|
|
sh(Cmd1)
|
|
),
|
|
append_strings(Module, "__pred_cov", MonitorName),
|
|
append_strings(Module, "__pred", CritListFile),
|
|
( exists(MonitorName) ->
|
|
true
|
|
;
|
|
concat_string([MorphineDir, "/bin/generate_pred_cov ", FileName],
|
|
Cmd2),
|
|
print(Cmd2), nl,
|
|
sh(Cmd2)
|
|
),
|
|
crit_cov(pred, ProgramCall, MonitorName, CritListFile, Uncovered).
|
|
|
|
%-----------------------------------------------------------------------%
|
|
opium_command(
|
|
name : call_site_cov,
|
|
arg_list : [Module, Uncovered],
|
|
arg_type_list : [string, var],
|
|
abbrev : csc,
|
|
interface : menu,
|
|
command_type : opium,
|
|
implementation : call_site_cov_Op,
|
|
parameters : [],
|
|
message :
|
|
"Takes a Mercury module name \"Module\", and unifies its 2nd argument \
|
|
with the uncovered call sites criteria of \"Module\" and the modules it \
|
|
imports which are in the current directory. A call site criterion is a \
|
|
4-tuple containing a module name, a procedure name, a line number, and a \
|
|
list of `exit' and `fail' atoms; for example, the call site criterion \
|
|
`csc(mod, foo, 14, [exit, fail])' denotes the call to procedure foo in \
|
|
module mod at line 14, which has to succeed and fail exactly once to be \
|
|
considered as covered. \
|
|
\n\
|
|
\n\
|
|
call_site_cov/2 works as follows; it calls `morphine/bin/generate_call_site_cov \
|
|
<Module>.m' which generates 2 files: \"Module__call_site_cov\" that contains \
|
|
a monitor to perform the coverage, and \"Module__call_site\" that contains \
|
|
the list of call sites of Module. Then it runs the \"Module__call_site_cov\" \
|
|
monitor, which outputs the list of uncovered call sites. The file \
|
|
\"Module__call_site\" is used to display the coverage ratio.\
|
|
").
|
|
|
|
|
|
call_site_cov_Op(ProgramCall, Uncovered) :-
|
|
split_string(ProgramCall, " ", " ", [Module|_Args]),
|
|
append_strings(Module, ".m", FileName),
|
|
getenv("MERCURY_MORPHINE_DIR", MorphineDir),
|
|
( exists("call_site_cov.in") ->
|
|
true
|
|
;
|
|
concat_string(["ln -s ", MorphineDir,
|
|
"/source/call_site_cov.in "], Cmd1),
|
|
sh(Cmd1)
|
|
),
|
|
append_strings(Module, "__call_site_cov", MonitorName),
|
|
append_strings(Module, "__call_site", CritListFile),
|
|
( exists(MonitorName) ->
|
|
true
|
|
;
|
|
concat_string([MorphineDir, "/bin/generate_call_site_cov ",
|
|
FileName, " ", MorphineDir, "/../../library/"], Cmd2),
|
|
print(Cmd2), nl,
|
|
sh(Cmd2)
|
|
),
|
|
crit_cov(call_site, ProgramCall, MonitorName, CritListFile, Uncovered).
|
|
|
|
|
|
|
|
%-----------------------------------------------------------------------%
|
|
|
|
crit_cov(CovType, ProgramCall, MonitorName, CritListFile, Uncovered) :-
|
|
run(ProgramCall),
|
|
collect(MonitorName, Uncovered0),
|
|
assoc_list_to_crit(Uncovered0, Uncovered),
|
|
count_crit(CovType, Uncovered, UncoveredCard),
|
|
print("Uncovered: "), print(UncoveredCard), nl,
|
|
get_crit_list_from_file(CritListFile, ToCover),
|
|
count_crit(CovType, ToCover, ToCoverCard),
|
|
print("To cover: "), print(ToCoverCard), nl,
|
|
|
|
CoverageRate is ((ToCoverCard-UncoveredCard)/ToCoverCard*100),
|
|
printf("The coverage rate is %2g \% \n", CoverageRate).
|
|
|
|
|
|
get_crit_list_from_file(CritListFileName, CritList) :-
|
|
open(CritListFileName, read, Stream),
|
|
read(Stream, CritList),
|
|
close(Stream).
|
|
|
|
|
|
count_crit(call_site, [], 0).
|
|
count_crit(call_site, [csc(_,_,_,List) | Tail], N) :-
|
|
length(List, L),
|
|
count_crit(call_site, Tail, N0),
|
|
N is N0 + L.
|
|
|
|
count_crit(pred, [], 0).
|
|
count_crit(pred, [pc(_,_,List) | Tail], N) :-
|
|
length(List, L),
|
|
count_crit(pred, Tail, N0),
|
|
N is N0 + L.
|
|
|
|
assoc_list_to_crit(AssocList, CritList) :-
|
|
maplist(assoc_to_crit, AssocList, CritList).
|
|
|
|
assoc_to_crit(Assoc, Crit) :-
|
|
(
|
|
Assoc = p(Mod, Name) - pc(_, List),
|
|
Crit = pc(Mod, Name, List), !
|
|
;
|
|
Assoc = p(Mod, Name, LN) - csc(_, List),
|
|
Crit = csc(Mod, Name, LN, List)
|
|
).
|