Skip to content

Commit 77d8016

Browse files
committed
Merge branch 'mr/pmderodat/instr-logs' into 'master'
Instrument: add debug traces for written source files Closes #365 See merge request eng/das/cov/gnatcoverage!723 Closes https://gitlab.adacore-it.com/eng/das/cov/gnatcoverage/-/issues/365
2 parents 7a6482a + 2220f7e commit 77d8016

25 files changed

+580
-117
lines changed

testsuite/tests/instr-cov/file-context/test.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,18 +56,18 @@ def do_instr(label, args):
5656
line
5757
for line in lines_of(log)
5858
if (
59-
line.startswith("[GNATCOV.MISC] Instrumenting ")
59+
line.startswith("[GNATCOV.INSTRUMENT_SOURCES] Instrumenting ")
6060
or line.startswith("warning: ")
6161
)
6262
]
6363
thistest.fail_if_not_equal(
6464
'"gnatcov instrument" output',
6565
"\n".join(
6666
[
67-
"[GNATCOV.MISC] Instrumenting main.adb",
67+
"[GNATCOV.INSTRUMENT_SOURCES] Instrumenting main.adb",
6868
"warning: Cannot find required source file: missing_a.ads",
6969
"warning: Cannot find required source file: missing_b.ads",
70-
"[GNATCOV.MISC] Instrumenting pkg.ads",
70+
"[GNATCOV.INSTRUMENT_SOURCES] Instrumenting pkg.ads",
7171
]
7272
),
7373
"\n".join(actual_lines),
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
info: creating output path [TMP]/obj/my_tool/
2+
[GNATCOV.INSTRUMENT_CLEAN_OBJDIRS] Processing My_Tool
3+
[GNATCOV.INSTRUMENT_CLEAN_OBJDIRS] GPR file: [TMP]/my_tool.gpr
4+
[GNATCOV.INSTRUMENT_CLEAN_OBJDIRS] output directory: [TMP]/obj/my_tool/my_tool-gnatcov-instr
5+
[GNATCOV.INSTRUMENT_CLEAN_OBJDIRS] it does not exist
6+
Coverage instrumentation
7+
[C++] my_tool.cpp
8+
[GNATCOV.INSTRUMENT_SOURCES] Writing C++ buffer unit [TMP]/obj/my_tool/my_tool-gnatcov-instr/gcvrt_b_[HASH#1].cpp
9+
[GNATCOV.INSTRUMENT_SOURCES] Project: My_Tool
10+
[GNATCOV.INSTRUMENT_SOURCES] For files:
11+
[GNATCOV.INSTRUMENT_SOURCES] * [TMP]/src-my_tool/my_tool.cpp
12+
Main instrumentation
13+
[C++] my_tool.cpp
14+
[GNATCOV.INSTRUMENT_SOURCES] Writing C++ dump helper unit [TMP]/obj/my_tool/my_tool-gnatcov-instr/gcvrt_d_[HASH#2].cpp
15+
[GNATCOV.INSTRUMENT_SOURCES] Project: My_Tool
16+
[GNATCOV.INSTRUMENT_SOURCES] Filename: [TMP]/obj/my_tool/my_tool-gnatcov-instr/gcvrt_d_[HASH#2].cpp
17+
[GNATCOV.INSTRUMENT_SOURCES] For main: [TMP]/obj/my_tool/my_tool-gnatcov-instr/my_tool.cpp
18+
[GNATCOV.INSTRUMENT_SOURCES] Writing C++ buffer list unit [TMP]/obj/my_tool/my_tool-gnatcov-instr/gcvrtc-my_tool.cpp
19+
[GNATCOV.INSTRUMENT_SOURCES] Project: My_Tool
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
info: creating output path [TMP]/obj/tests/
2+
[GNATCOV.INSTRUMENT_CLEAN_OBJDIRS] Processing Mylib
3+
[GNATCOV.INSTRUMENT_CLEAN_OBJDIRS] GPR file: [TMP]/mylib.gpr
4+
[GNATCOV.INSTRUMENT_CLEAN_OBJDIRS] output directory: [TMP]/obj/mylib/mylib-gnatcov-instr
5+
[GNATCOV.INSTRUMENT_CLEAN_OBJDIRS] Processing Mylib_Extended
6+
[GNATCOV.INSTRUMENT_CLEAN_OBJDIRS] GPR file: [TMP]/mylib_extended.gpr
7+
[GNATCOV.INSTRUMENT_CLEAN_OBJDIRS] output directory: [TMP]/obj/mylib_extended/mylib_extended-gnatcov-instr
8+
[GNATCOV.INSTRUMENT_CLEAN_OBJDIRS] it does not exist
9+
[GNATCOV.INSTRUMENT_CLEAN_OBJDIRS] Processing Harness
10+
[GNATCOV.INSTRUMENT_CLEAN_OBJDIRS] GPR file: [TMP]/harness.gpr
11+
[GNATCOV.INSTRUMENT_CLEAN_OBJDIRS] output directory: [TMP]/obj/harness/harness-gnatcov-instr
12+
[GNATCOV.INSTRUMENT_CLEAN_OBJDIRS] it is an externally built project
13+
[GNATCOV.INSTRUMENT_CLEAN_OBJDIRS] Processing Tests
14+
[GNATCOV.INSTRUMENT_CLEAN_OBJDIRS] GPR file: [TMP]/tests.gpr
15+
[GNATCOV.INSTRUMENT_CLEAN_OBJDIRS] output directory: [TMP]/obj/tests/tests-gnatcov-instr
16+
[GNATCOV.INSTRUMENT_CLEAN_OBJDIRS] it does not exist
17+
Coverage instrumentation
18+
[Ada] mylib
19+
[GNATCOV.INSTRUMENT_SOURCES] Instrumenting mylib.ads
20+
[GNATCOV.INSTRUMENT_SOURCES] Instrumenting mylib.adb
21+
[GNATCOV.INSTRUMENT_SOURCES] Writing Ada buffer unit GCVRT.B[HASH#1]
22+
[GNATCOV.INSTRUMENT_SOURCES] Project: Mylib
23+
[GNATCOV.INSTRUMENT_SOURCES] Filename: gcvrt-b[HASH#1].ads
24+
[GNATCOV.INSTRUMENT_SOURCES] For units:
25+
[GNATCOV.INSTRUMENT_SOURCES] * mylib spec
26+
[GNATCOV.INSTRUMENT_SOURCES] * mylib body
27+
[GNATCOV.INSTRUMENT_SOURCES] Writing pure Ada buffer unit GCVRT.P[HASH#1]
28+
[GNATCOV.INSTRUMENT_SOURCES] Project: Mylib
29+
[GNATCOV.INSTRUMENT_SOURCES] Filename: [TMP]/obj/mylib_extended/mylib_extended-gnatcov-instr/gcvrt-p[HASH#1].ads
30+
[GNATCOV.INSTRUMENT_SOURCES] For units:
31+
[GNATCOV.INSTRUMENT_SOURCES] * mylib spec
32+
[GNATCOV.INSTRUMENT_SOURCES] * mylib body
33+
[C] mylib_ext.c
34+
[GNATCOV.INSTRUMENT_SOURCES] Writing C buffer unit [TMP]/obj/mylib_extended/mylib_extended-gnatcov-instr/gcvrt_b_[HASH#2].c
35+
[GNATCOV.INSTRUMENT_SOURCES] Project: Mylib
36+
[GNATCOV.INSTRUMENT_SOURCES] For files:
37+
[GNATCOV.INSTRUMENT_SOURCES] * [TMP]/src-mylib/mylib_ext.c
38+
Main instrumentation
39+
[Ada] test1
40+
[GNATCOV.INSTRUMENT_SOURCES] Writing Ada dump helper unit GCVRT.DB_[HASH#3]
41+
[GNATCOV.INSTRUMENT_SOURCES] Project: Tests
42+
[GNATCOV.INSTRUMENT_SOURCES] Spec filename: gcvrt-db_[HASH#3].ads
43+
[GNATCOV.INSTRUMENT_SOURCES] Body filename: gcvrt-db_[HASH#3].adb
44+
[GNATCOV.INSTRUMENT_SOURCES] For main: test1 body
45+
[Ada] test2
46+
[GNATCOV.INSTRUMENT_SOURCES] Writing Ada dump helper unit GCVRT.DB_[HASH#4]
47+
[GNATCOV.INSTRUMENT_SOURCES] Project: Tests
48+
[GNATCOV.INSTRUMENT_SOURCES] Spec filename: gcvrt-db_[HASH#4].ads
49+
[GNATCOV.INSTRUMENT_SOURCES] Body filename: gcvrt-db_[HASH#4].adb
50+
[GNATCOV.INSTRUMENT_SOURCES] For main: test2 body
51+
[C] test3.c
52+
[GNATCOV.INSTRUMENT_SOURCES] Writing C dump helper unit [TMP]/obj/tests/tests-gnatcov-instr/gcvrt_d_[HASH#5].c
53+
[GNATCOV.INSTRUMENT_SOURCES] Project: Tests
54+
[GNATCOV.INSTRUMENT_SOURCES] Filename: [TMP]/obj/tests/tests-gnatcov-instr/gcvrt_d_[HASH#5].c
55+
[GNATCOV.INSTRUMENT_SOURCES] For main: [TMP]/src-tests/test3.c
56+
[GNATCOV.INSTRUMENT_SOURCES] Writing Ada buffer list unit GCVRT.Tests
57+
[GNATCOV.INSTRUMENT_SOURCES] Project: Tests
58+
[GNATCOV.INSTRUMENT_SOURCES] Filename: gcvrt-tests.ads
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
project Harness is
2+
3+
for Source_Dirs use ("src-harness");
4+
for Object_Dir use "obj/harness";
5+
for Externally_Built use external ("HARNESS_BUILT", "true");
6+
end Harness;
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
project My_Tool is
2+
for Languages use ("C++");
3+
for Source_Dirs use ("src-my_tool");
4+
for Object_Dir use "obj/my_tool";
5+
for Main use ("my_tool.cpp");
6+
end My_Tool;
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
project Mylib is
2+
for Languages use ("Ada", "C");
3+
for Source_Dirs use ("src-mylib");
4+
for Object_Dir use "obj/mylib";
5+
end Mylib;
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
project Mylib_Extended extends "mylib.gpr" is
2+
for Source_Dirs use ("src-mylib_extended");
3+
for Object_Dir use "obj/mylib_extended";
4+
end Mylib_Extended;
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
with Ada.Text_IO; use Ada.Text_IO;
2+
3+
package body Harness is
4+
5+
------------------
6+
-- Assert_Equal --
7+
------------------
8+
9+
procedure Assert_Equal (Label : String; Expected, Actual : Integer) is
10+
begin
11+
if Expected = Actual then
12+
Put_Line ("OK " & Label);
13+
else
14+
Put_Line ("FAIL " & Label);
15+
end if;
16+
end Assert_Equal;
17+
18+
end Harness;
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
package Harness is
2+
procedure Assert_Equal (Label : String; Expected, Actual : Integer);
3+
end Harness;
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#include <iostream>
2+
3+
int
4+
main ()
5+
{
6+
std::cout << "Hello world" << std::endl;
7+
return 0;
8+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package body Mylib is
2+
3+
----------
4+
-- Next --
5+
----------
6+
7+
function Next (I : Integer) return Integer is
8+
begin
9+
return I + 1;
10+
end Next;
11+
12+
end Mylib;
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package Mylib is
2+
3+
function Next (I : Integer) return Integer;
4+
5+
function Identity (I : Integer) return Integer
6+
with Import, Convention => C, External_Name => "mylib__identity";
7+
8+
end Mylib;
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
int
2+
mylib__identity (int i)
3+
{
4+
return i;
5+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package Mylib is
2+
3+
function Next (I : Integer) return Integer;
4+
function Prev (I : Integer) return Integer is (I - 1);
5+
6+
function Identity (I : Integer) return Integer
7+
with Import, Convention => C, External_Name => "mylib__identity";
8+
9+
end Mylib;
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
with Harness;
2+
with Mylib;
3+
4+
procedure Test1 is
5+
begin
6+
Harness.Assert_Equal ("Next (0)", 1, Mylib.Next (0));
7+
Harness.Assert_Equal ("Next (1)", 2, Mylib.Next (1));
8+
end Test1;
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
with Harness;
2+
with Mylib;
3+
4+
procedure Test2 is
5+
begin
6+
Harness.Assert_Equal ("Prev (1)", 0, Mylib.Prev (1));
7+
Harness.Assert_Equal ("Prev (2)", 1, Mylib.Prev (2));
8+
end Test2;
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#include <stdio.h>
2+
3+
extern int mylib__identity (int);
4+
5+
static void
6+
assert_equal (const char *label, int expected, int actual)
7+
{
8+
const char *status = (expected == actual) ? "OK " : "FAIL";
9+
printf ("%s %s\n", status, label);
10+
}
11+
12+
int
13+
main (void)
14+
{
15+
assert_equal ("Identity (0)", 0, mylib__identity (0));
16+
assert_equal ("Identity (1)", 1, mylib__identity (1));
17+
return 0;
18+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
!C++ DEAD C++ toolchain required to instrument C++ sources
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
"""
2+
Check that "gnatcov instrument" produces the expected debug logging.
3+
"""
4+
5+
from __future__ import annotations
6+
7+
import glob
8+
import os.path
9+
import re
10+
11+
from e3.fs import mkdir, sync_tree
12+
from e3.testsuite.driver.diff import OutputRefiner, Substitute
13+
14+
from SUITE.context import thistest
15+
from SUITE.cutils import Wdir
16+
from SUITE.tutils import xcov
17+
18+
19+
# Copy projects and their sources in a temporary directory
20+
tmp = Wdir("tmp_")
21+
for pattern in ["*.gpr", "src-*"]:
22+
for item in glob.glob(os.path.join("..", pattern)):
23+
sync_tree(item, os.path.basename(item))
24+
25+
# Create an instrumentation output directories to exercise
26+
# INSTRUMENT_CLEAN_OBJDIRS variations.
27+
for project in ["mylib", "harness"]:
28+
mkdir(os.path.join("obj", project, f"{project}-gnatcov-instr"))
29+
30+
31+
class HashRefiner(OutputRefiner):
32+
"""Output refiner to hide hashes from the instrumented files.
33+
34+
Actual hashes are not portable as they vary depending on the absolute path
35+
for original source files.
36+
"""
37+
38+
hash_re = re.compile("z([0-9a-f]{8})")
39+
40+
def __init__(self):
41+
self.map = {}
42+
43+
def repl(self, match):
44+
hash_value = match.group(0)
45+
try:
46+
return self.map[hash_value]
47+
except KeyError:
48+
result = f"[HASH#{len(self.map) + 1}]"
49+
self.map[hash_value] = result
50+
return result
51+
52+
def refine(self, output):
53+
return self.hash_re.sub(self.repl, output)
54+
55+
56+
class SortByFiles(OutputRefiner):
57+
"""Output refiner to sort lines by instrumented source file.
58+
59+
The order in which "gnatcov instrument" processes units is not specified,
60+
and varies in practice. This refiner reorders logs to have stable
61+
baselines.
62+
"""
63+
64+
def refine(self, output):
65+
result = []
66+
67+
# When processing a section that contains logs for a list of source
68+
# files ("Coverage instrumentation" or "Main instrumentation"),
69+
# "by_file" maps seen filenames to the corresponding list of log lines
70+
# while "current_file" designates the last file seen for that section.
71+
by_file = None
72+
current_file = None
73+
74+
def flush_files():
75+
"""Append all log lines for files seen so far to result."""
76+
if by_file is None:
77+
return
78+
for _, lines in sorted(by_file.items()):
79+
result.extend(lines)
80+
81+
for line in output.splitlines():
82+
if line in ("Coverage instrumentation", "Main instrumentation"):
83+
# This line starts a new section: flush log lines for the
84+
# previous section (if any) and reset "by_file" and
85+
# "current_file" to be ready for the new section.
86+
flush_files()
87+
by_file = {}
88+
current_file = None
89+
result.append(line)
90+
elif by_file is None:
91+
# No section being processed: just forward this log line
92+
result.append(line)
93+
else:
94+
# If this line marks the start of processing for a new source
95+
# file, set "current_file" accordingly and start a new log line
96+
# for it.
97+
chunks = line.split()
98+
if len(chunks) == 2 and chunks[0] in ("[Ada]", "[C]", "[C++]"):
99+
current_file = chunks[1]
100+
assert current_file not in by_file
101+
by_file[current_file] = [line]
102+
else:
103+
by_file[current_file].append(line)
104+
flush_files()
105+
106+
return "".join(f"{line}\n" for line in result)
107+
108+
109+
# Run "gnatcov instrument" and check its output against our logging baselines
110+
# for all example projects.
111+
for project, subproject in [("tests", "mylib"), ("my_tool", "my_tool")]:
112+
log = f"instr-{project}.txt"
113+
xcov(
114+
[
115+
"instrument",
116+
f"-P{project}.gpr",
117+
"-cstmt",
118+
f"--projects={subproject}",
119+
"--log=instrument_clean_objdirs",
120+
"--log=instrument_sources",
121+
],
122+
out=log,
123+
)
124+
thistest.fail_if_diff(
125+
baseline_file=f"../baseline-{project}.txt",
126+
actual_file=log,
127+
failure_message=f'[{project}] "gnatcov instrument" output',
128+
# To have portable baseline comparison, hide the actual CWD and
129+
# canonicalize directory separators.
130+
output_refiners=[
131+
Substitute(os.getcwd(), "[TMP]"),
132+
SortByFiles(),
133+
HashRefiner(),
134+
Substitute("\\", "/"),
135+
],
136+
ignore_white_chars=False,
137+
)
138+
139+
thistest.result()
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
with "harness";
2+
with "mylib_extended";
3+
4+
project Tests is
5+
for Languages use ("Ada", "C");
6+
for Source_Dirs use ("src-tests");
7+
for Object_Dir use "obj/tests";
8+
for Main use ("test1.adb", "test2.adb", "test3.c");
9+
end Tests;

0 commit comments

Comments
 (0)