Skip to content

Commit 278ac87

Browse files
committed
Implement '--expect-message-count' flag/expect_message_count config option.
Provide some additional safety when messages are ignored or suppressed, to warn if the number of messages is different from expectation. (Inspired by yacc 'expect' feature - for similar reasons.) See man genhtml(1) and lcovrc(5) for more details. Signed-off-by: Henry Cox <henry.cox@mediatek.com>
1 parent 4543c36 commit 278ac87

File tree

10 files changed

+429
-30
lines changed

10 files changed

+429
-30
lines changed

README

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
-------------------------------------------------
22
- README file for the LTP GCOV extension (LCOV) -
3-
- Last changes: 2024-03-21
3+
- Last changes: 2024-09-13
44
-------------------------------------------------
55

66
Description
@@ -64,9 +64,10 @@ Further README contents
6464
to lcov format
6565
bin/geninfo - Internal tool (creates LCOV data files)
6666
bin/genpng - Internal tool (creates png overviews of source files)
67+
lcovrc - LCOV configuration file
6768
man - Directory containing man pages for included tools
6869
example - Directory containing an example to demonstrate LCOV
69-
lcovrc - LCOV configuration file
70+
tests - Directory containing lcov regression tests
7071
Makefile - Makefile providing 'install' and 'uninstall' targets
7172

7273

@@ -110,8 +111,8 @@ or if you want to use the perl2lcov utility.
110111
To view the collected coverage information, point your browser to
111112
.../lcov_coverage/index.html after running the tests.
112113

113-
Note that the testcases are intended to test LCOV functionality and
114-
not to be easily readable tutorial examples.
114+
Note that the testcases are primarily intended to test LCOV functionality
115+
and not to be easily readable tutorial examples.
115116

116117
3. Dependencies:
117118
----------------
@@ -307,13 +308,16 @@ New features and capabilities fall into 7 major categories:
307308
A generic - but very simple - error handler has been added to the
308309
lcov tool suite. The error handler is used to report exceptions,
309310
and provides a mechanism for the user to ignore the particular
310-
message if desired.
311+
message if desired. Note that ignoring certain errors can cause
312+
subsequent errors and/or can result in inconsistent or confusing
313+
coverage reports.
311314
See the genhtml/lcov/geninfo man pages for details.
312315

313316
Note that some errors are unrecoverable - and cannot be suppressed or
314317
ignored.
315318

316-
Related options: --ignore-error, --keep-going
319+
Related options:
320+
--ignore-error, --expect-message-count, --keep-going
317321

318322
c) Navigation and display:
319323

lib/lcovutil.pm

Lines changed: 100 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ our @EXPORT_OK = qw($tool_name $tool_dir $lcov_version $lcov_url $VERSION
100100

101101
our @ignore;
102102
our @message_count;
103+
our @expected_message_count;
103104
our %message_types;
104105
our $suppressAfter = 100; # stop warning after this number of messages
105106
our %ERROR_ID;
@@ -1047,8 +1048,9 @@ my (@rc_filter, @rc_ignore, @rc_exclude_patterns,
10471048
@rc_erase_patterns, @rc_version_script, @unsupported_config,
10481049
@rc_source_directories, @rc_build_dir, %unsupported_rc,
10491050
$keepGoing, $help, @rc_resolveCallback,
1050-
@rc_criteria_script, @rc_contextCallback, $rc_no_branch_coverage,
1051-
$rc_no_func_coverage, $rc_no_checksum, $version);
1051+
@rc_expected_msg_counts, @rc_criteria_script, @rc_contextCallback,
1052+
$rc_no_branch_coverage, $rc_no_func_coverage, $rc_no_checksum,
1053+
$version);
10521054
my $quiet = 0;
10531055
my $tempdirname;
10541056

@@ -1059,6 +1061,7 @@ our ($lcov_remove, # If set, removes parts of tracefile
10591061
$lcov_extract); # If set, extracts parts of tracefile
10601062
our @opt_config_files;
10611063
our @opt_ignore_errors;
1064+
our @opt_expected_message_counts;
10621065
our @opt_filter;
10631066
our @comments;
10641067

@@ -1101,6 +1104,7 @@ my %rc_common = (
11011104
"lcov_branch_coverage" => \$lcovutil::br_coverage,
11021105
"ignore_errors" => \@rc_ignore,
11031106
"max_message_count" => \$lcovutil::suppressAfter,
1107+
'expected_message_count' => \@rc_expected_msg_counts,
11041108
'stop_on_error' => \$lcovutil::stop_on_error,
11051109
'treat_warning_as_error' => \$lcovutil::treat_warning_as_error,
11061110
'warn_once_per_file' => \$lcovutil::warn_once_per_file,
@@ -1220,17 +1224,18 @@ our %argCommon = ("tempdir=s" => \$tempdirname,
12201224
\@ReadCurrentSource::source_directories,
12211225
'build-directory=s' => \@lcovutil::build_directory,
12221226

1223-
'resolve-script=s' => \@lcovutil::resolveCallback,
1224-
'context-script=s' => \@lcovutil::contextCallback,
1225-
"filter=s" => \@opt_filter,
1226-
"demangle-cpp:s" => \@lcovutil::cpp_demangle,
1227-
"ignore-errors=s" => \@opt_ignore_errors,
1228-
"keep-going" => \$keepGoing,
1229-
"config-file=s" => \@unsupported_config,
1230-
"rc=s%" => \%unsupported_rc,
1231-
"profile:s" => \$lcovutil::profile,
1232-
"exclude=s" => \@lcovutil::exclude_file_patterns,
1233-
"include=s" => \@lcovutil::include_file_patterns,
1227+
'resolve-script=s' => \@lcovutil::resolveCallback,
1228+
'context-script=s' => \@lcovutil::contextCallback,
1229+
"filter=s" => \@opt_filter,
1230+
"demangle-cpp:s" => \@lcovutil::cpp_demangle,
1231+
"ignore-errors=s" => \@opt_ignore_errors,
1232+
"expect-message-count=s" => \@opt_expected_message_counts,
1233+
"keep-going" => \$keepGoing,
1234+
"config-file=s" => \@unsupported_config,
1235+
"rc=s%" => \%unsupported_rc,
1236+
"profile:s" => \$lcovutil::profile,
1237+
"exclude=s" => \@lcovutil::exclude_file_patterns,
1238+
"include=s" => \@lcovutil::include_file_patterns,
12341239
"erase-functions=s" => \@lcovutil::exclude_function_patterns,
12351240
"omit-lines=s" => \@lcovutil::omit_line_patterns,
12361241
"substitute=s" => \@lcovutil::file_subst_patterns,
@@ -1452,6 +1457,7 @@ sub parseOptions
14521457
# apply the RC file settings if no command line arg
14531458
foreach my $rc ([\@opt_filter, \@rc_filter],
14541459
[\@opt_ignore_errors, \@rc_ignore],
1460+
[\@opt_expected_message_counts, \@rc_expected_msg_counts],
14551461
[\@lcovutil::exclude_file_patterns, \@rc_exclude_patterns],
14561462
[\@lcovutil::include_file_patterns, \@rc_include_patterns],
14571463
[\@lcovutil::file_subst_patterns, \@rc_subst_patterns],
@@ -1536,6 +1542,7 @@ sub parseOptions
15361542
lcovutil::init_parallel_params();
15371543
# Determine which errors the user wants us to ignore
15381544
parse_ignore_errors(@opt_ignore_errors);
1545+
parse_expected_message_counts(@opt_expected_message_counts);
15391546
# Determine what coverpoints the user wants to filter
15401547
push(@opt_filter, 'exception') if $lcovutil::exclude_exception_branch;
15411548
parse_cov_filters(@opt_filter);
@@ -1746,12 +1753,13 @@ sub define_errors()
17461753
my $id = 0;
17471754
foreach my $d (@lcovErrs) {
17481755
my ($k, $ref) = @$d;
1749-
$$ref = $id;
1750-
$lcovErrors{$k} = $id;
1751-
$ERROR_ID{$k} = $id;
1752-
$ERROR_NAME{$id} = $k;
1753-
$ignore[$id] = 0;
1754-
$message_count[$id] = 0;
1756+
$$ref = $id;
1757+
$lcovErrors{$k} = $id;
1758+
$ERROR_ID{$k} = $id;
1759+
$ERROR_NAME{$id} = $k;
1760+
$ignore[$id] = 0;
1761+
$message_count[$id] = 0;
1762+
$expected_message_count[$id] = undef; # no expected count, by default
17551763
++$id;
17561764
}
17571765
}
@@ -1761,6 +1769,29 @@ sub summarize_messages
17611769
my $silent = shift;
17621770
return if $lcovutil::in_child_process;
17631771

1772+
# first check for expected message count constraints
1773+
for (my $idx = 0; $idx <= $#expected_message_count; ++$idx) {
1774+
my $expr = $expected_message_count[$idx];
1775+
next unless defined($expr);
1776+
my $t = $message_count[$idx];
1777+
$expr =~ s/%C/$t/g;
1778+
my $v;
1779+
eval { $v = eval $expr; };
1780+
if ($@ || !defined($v)) {
1781+
# we checked the syntax of the message - so should not be able to fail
1782+
lcovutil::ignorable_error($lcovutil::ERROR_CALLBACK,
1783+
"evaluation of '$expr' failed: $@");
1784+
next;
1785+
}
1786+
unless ($v) {
1787+
my $type = $ERROR_NAME{$idx};
1788+
lcovutil::ignorable_error($lcovutil::ERROR_COUNT,
1789+
"'$type' constraint '$expr' is not true (see '--expect_message_count' for details)."
1790+
);
1791+
}
1792+
}
1793+
1794+
# now summarize
17641795
my %total = ('error' => 0,
17651796
'warning' => 0,
17661797
'ignore' => 0,);
@@ -1810,6 +1841,56 @@ sub parse_ignore_errors(@)
18101841
}
18111842
}
18121843

1844+
sub parse_expected_message_counts(@)
1845+
{
1846+
my @constraints = split($split_char, join($split_char, @_));
1847+
# parse the list and look for errors..
1848+
foreach my $c (@constraints) {
1849+
if ($c =~ /^s*(\S+?)\s*:\s*((\d+)|(.+?))\s*$/) {
1850+
unless (exists($ERROR_ID{lc($1)})) {
1851+
lcovutil::ignorable_error($lcovutil::ERROR_USAGE,
1852+
"unknown 'expected-message-count' message type \"$1\".");
1853+
next;
1854+
}
1855+
1856+
my $id = $ERROR_ID{lc($1)};
1857+
if (defined($expected_message_count[$id])) {
1858+
my $ignore = $lcovutil::ignore[$lcovutil::ERROR_USAGE];
1859+
lcovutil::ignorable_error($lcovutil::ERROR_USAGE,
1860+
"duplicate 'expected' constraint '$c'" .
1861+
($ignore ? ': ignoring.' : ''));
1862+
next;
1863+
}
1864+
# check if syntax look resonable
1865+
my $expr = $2;
1866+
if (Scalar::Util::looks_like_number($expr)) {
1867+
$expected_message_count[$id] = "%C == $expr";
1868+
next;
1869+
}
1870+
lcovutil::ignorable_error($lcovutil::ERROR_USAGE,
1871+
"expect-message-count constraint '$c' does not appear to depend on message count: '%C' substitution not found."
1872+
) unless ($expr =~ /%C/);
1873+
1874+
# now lets try an eval
1875+
my $v = $expr;
1876+
$v =~ s/%C/0/g;
1877+
$v = eval $v;
1878+
if (defined($v)) {
1879+
$expected_message_count[$id] = $expr;
1880+
} else {
1881+
my $ignore = $lcovutil::ignore[$lcovutil::ERROR_USAGE];
1882+
lcovutil::ignorable_error($lcovutil::ERROR_USAGE,
1883+
"eval error in 'expect-message-count' constraint '$c': $@"
1884+
. ($ignore ? ': ignoring.' : ''));
1885+
}
1886+
} else {
1887+
lcovutil::ignorable_error($lcovutil::ERROR_USAGE,
1888+
"malformed expected-message-count constraint \"$c\". Expected 'msg_type = expr'."
1889+
);
1890+
}
1891+
}
1892+
}
1893+
18131894
sub message_count($)
18141895
{
18151896
my $code = shift;

man/genhtml.1

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,9 @@ genhtml \- Generate HTML view from LCOV coverage data files
8686
.RB [ \-\-ignore\-errors
8787
.IR errors ]
8888
.br
89+
.RB [\-\-expect\-message\-count
90+
.IR message_type=expr[,message_type=expr..]]
91+
.br
8992
.RB [ \-\-keep\-going ]
9093
.RB [ \-\-config\-file
9194
.IR config\-file ]
@@ -2862,7 +2865,6 @@ function alias record (
28622865
branch expression (3rd field in the .info file 'BRDA' entry) of merge data does not match
28632866
.PP
28642867

2865-
28662868
.PP
28672869
.IP \- 3
28682870
Negative number or zero line number encounted.
@@ -2962,12 +2964,84 @@ a tool called during processing returned an error code (e.g., 'find' encountered
29622964
\-\-version\-script comparison returned non\-zero mismatch indication. It likely that the version of the file which was used in coverage data extraction is different than the source version which was found. File annotations may be incorrect.
29632965
.PP
29642966

2967+
Note that certain error messages are caused by issues that you probably cannot
2968+
fix by yourself - for example, bugs in your tool chain which result in
2969+
.I inconsistent
2970+
coverage DB data (see above).
2971+
In those cases, after reviewing the messages you may want to exclude the offending code or the entire offending
2972+
file, or you may simply ignore the messages - either by converting to warning or suppressing entirely.
2973+
Another alternative is to tell
2974+
.B genhtml
2975+
about the number of messages you expect - so that it can warn you if something changes
2976+
such that the count differs, such that you know to review the messages again.
2977+
See the
2978+
.I "\-\-expect\-message\-count"
2979+
flag, below.
2980+
29652981
Also see 'man
29662982
.B lcovrc(5)
29672983
' for a discussion of the 'max_message_count' parameter which can be used to control the number of warnings which are emitted before all subsequent messages are suppressed. This can be used to reduce log file volume.
29682984
.br
29692985

29702986
.RE
2987+
.BI "\-\-expect\-message\-count message_type:expr[,message_type:expr]"
2988+
.RS
2989+
Give
2990+
.B genhtml
2991+
a constraint on the number of messages of one or more types which are expected to
2992+
be produced during execution. Note that the total includes _all_ messages
2993+
of the given type - including those which have been suppressed.
2994+
If the constraint is not true, an
2995+
error of type
2996+
.I "count"
2997+
(see above) is generated.
2998+
.I message_type
2999+
is one of the message mnemonics described above, and
3000+
.I expr
3001+
may be either
3002+
.IP \- 3
3003+
an integer - interpreted to mean that there should be exactly that number
3004+
of messages of the corresponding type, or
3005+
.IP \- 3
3006+
a Perl expression containing the substring
3007+
.B %C
3008+
; %C is replaced with the total number of messages of the corresponding type and
3009+
then evaluated. The constraint is met if the result is non-zero and is not met
3010+
otherwise.
3011+
3012+
For example:
3013+
.IP
3014+
\-\-expect\-message\-count inconsistent:5
3015+
.br
3016+
says that we expect exactly 5 messages of type 'inconsistent'.
3017+
.PP
3018+
.IP
3019+
\-\-expect\-message\-count inconsistent:%C==5
3020+
.br
3021+
also says that we expect exactly 5 messages of this type, but specified
3022+
using expression syntax.
3023+
.PP
3024+
.IP
3025+
\-\-expect\-message\-count 'inconsistent : %C > 6 && %C <= 10'
3026+
.br
3027+
says that we expect the number of messages to be in the range (6:10].
3028+
(Note that quoting may be necessary, to protect whitespace from interpretation by
3029+
your shell, if you want to improve expression readability by adding spaces to your expression.)
3030+
.PP
3031+
3032+
Multiple constraints can be specified using a comma-separated list or
3033+
by using the option multiple times.
3034+
3035+
This flag is equivalent to the
3036+
.I "expect_message_count"
3037+
configuration option. See man
3038+
.B lcovrc(5)
3039+
for more details on the expression syntax and how expressions are interpreted.
3040+
The number of messages of the particular type is substituted into the
3041+
expression before it is evaluated.
3042+
3043+
.RE
3044+
29713045
.BI "\-\-keep\-going "
29723046
.RS
29733047
Do not stop if error occurs: attempt to generate a result, however flawed.

man/geninfo.1

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ geninfo \- Generate tracefiles from GCOV coverage data files
5555
.RB [ \-\-ignore\-errors
5656
.IR errors ]
5757
.br
58+
.RB [\-\-expect\-message\-count
59+
.IR message_type=expr[,message_type=expr..]]
60+
.br
5861
.RB [ \-\-keep\-going ]
5962
.br
6063
.RB [ \-\-preserve ]
@@ -975,8 +978,27 @@ See man
975978
.B lcovrc(5)
976979
for a discussion of the 'max_message_count' parameter which can be used to control the number of warnings which are emitted before all subsequent messages are suppressed. This can be used to reduce log file volume.
977980

981+
.RE
982+
983+
.BI "\-\-expect\-message\-count message_type:expr[,message_type:expr]"
984+
.RS
985+
Give
986+
.B geninfo
987+
a constraint on the number of messages of one or more types which are expected to
988+
be produced during execution. If the constraint is not true, then generate an
989+
error of type
990+
.I "count"
991+
(see above).
978992

993+
See man
994+
.B genhtml(1)
995+
for more details about the flag, as well as the
996+
.I "expect_message_count"
997+
section in man
998+
.B lcovrc(5)
999+
for a description of the equivalent configuration file option.
9791000
.RE
1001+
9801002
.BI "\-\-keep\-going "
9811003
.RS
9821004
Do not stop if error occurs: attempt to generate a result, however flawed.

0 commit comments

Comments
 (0)