From: "Martin Liška" <mliska@suse.cz>
To: David Malcolm <dmalcolm@redhat.com>, gcc-patches@gcc.gnu.org
Subject: Re: [PATCH] Add pytest for a GCOV test-case
Date: Wed, 23 Dec 2020 14:03:58 +0100 [thread overview]
Message-ID: <ef9f6c9f-df2f-2a77-0f35-22c30bd92c7d@suse.cz> (raw)
In-Reply-To: <05b7e58dc023fbea33a051a7800a214c838feeb4.camel@redhat.com>
[-- Attachment #1: Type: text/plain, Size: 8091 bytes --]
On 12/22/20 6:49 PM, David Malcolm wrote:
> On Tue, 2020-12-22 at 12:39 +0100, Martin Liška wrote:
>> Hello.
>>
>> The patch adds a new test for an existing GCOV test-case. Newly
>> added run-gcov-pytest parses JSON format produced by GCOV and
>> runs pytest on it.
>>
>> Patch can bootstrap on x86_64-linux-gnu and survives regression
>> tests.
>
> At a high level, this patch calls out to Python 3, allowing for test
> logic to be written in Python, rather than Tcl. Are we doing this
> anywhere else in our test suite?
No.
> I'm in favor of this (I'm much more
> comfortable in Python than in Tcl, I dread anytime I have to touch the
> Tcl code).
Yes, that was my original motivation. I always suffer when I'm supposed
to come up with a test-case.
>
> The test implicitly requires python3, and the 3rd party pytest module
> installed within it. What happens if these aren't installed? (ideally
> an UNSUPPORTED at the DejaGnu level, I think).
Right now, one will see the following in the .log file:
/usr/bin/python3: No module named pytest
I must confess that I don't know how to properly mark that as UNRESOLVED
in DejaGNU.
>
> Some further comments inline below...
>
>> Ready to be installed?
>> Thanks,
>> Martin
>>
>> gcc/testsuite/ChangeLog:
>>
>> PR gcov-profile/98273
>> * lib/gcov.exp: Add run-gcov-pytest function which runs pytest.
>> * g++.dg/gcov/pr98273.C: New test.
>> * g++.dg/gcov/gcov.py: New test.
>> * g++.dg/gcov/test-pr98273.py: New test.
>> ---
>> gcc/testsuite/g++.dg/gcov/gcov.py | 10 ++++++++
>> gcc/testsuite/g++.dg/gcov/pr98273.C | 24 +++++++++++++++++++
>> gcc/testsuite/g++.dg/gcov/test-pr98273.py | 27
>> ++++++++++++++++++++++
>> gcc/testsuite/lib/gcov.exp | 28
>> +++++++++++++++++++++++
>> 4 files changed, 89 insertions(+)
>> create mode 100644 gcc/testsuite/g++.dg/gcov/gcov.py
>> create mode 100644 gcc/testsuite/g++.dg/gcov/pr98273.C
>> create mode 100644 gcc/testsuite/g++.dg/gcov/test-pr98273.py
>>
>> diff --git a/gcc/testsuite/g++.dg/gcov/gcov.py
>> b/gcc/testsuite/g++.dg/gcov/gcov.py
>> new file mode 100644
>> index 00000000000..a8c4ea9ae71
>> --- /dev/null
>> +++ b/gcc/testsuite/g++.dg/gcov/gcov.py
>> @@ -0,0 +1,10 @@
>> +import gzip
>> +import json
>> +import os
>> +
>> +
>> +def gcov_from_env():
>> + # return parsed JSON content a GCOV_PATH file
>> + json_filename = os.environ['GCOV_PATH'] + '.gcov.json.gz'
>> + json_data = gzip.open(json_filename).read()
>> + return json.loads(json_data)
>> diff --git a/gcc/testsuite/g++.dg/gcov/pr98273.C
>> b/gcc/testsuite/g++.dg/gcov/pr98273.C
>> new file mode 100644
>> index 00000000000..bfa83cbe4d0
>> --- /dev/null
>> +++ b/gcc/testsuite/g++.dg/gcov/pr98273.C
>> @@ -0,0 +1,24 @@
>> +/* PR gcov-profile/98273 */
>> +
>> +/* { dg-options "--coverage -std=c++11" } */
>> +/* { dg-do run { target native } } */
>> +
>> +int
>> +main ()
>> +{
>> + int i = 42;
>> + {
>> + auto f = [] () {
>> + auto g = [] () {};
>> + g ();
>> + g ();
>> + };
>> + f ();
>> + }
>> + ++i;
>> + ++i;
>> + ++i;
>> + return 45 - i;
>> +}
>> +
>> +/* { dg-final { run-gcov-pytest pr98273.C "test-pr98273.py" } } */
>> diff --git a/gcc/testsuite/g++.dg/gcov/test-pr98273.py
>> b/gcc/testsuite/g++.dg/gcov/test-pr98273.py
>> new file mode 100644
>> index 00000000000..6cb39d10c1e
>> --- /dev/null
>> +++ b/gcc/testsuite/g++.dg/gcov/test-pr98273.py
>
> I had an idea, not sure if a good one: if all of the test logic is
> moved from the .C file to a python script, then perhaps the script
> should be the name of the .C file with a .py suffix i.e. here it could
> be "pr98273.C.py"
That does not work:
___________________________________________________________________________________________________________ ERROR collecting gcc/testsuite/g++.dg/gcov/pr98273.C.py ____________________________________________________________________________________________________________
ImportError while importing test module '/home/marxin/Programming/gcc/gcc/testsuite/g++.dg/gcov/pr98273.C.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
/usr/lib64/python3.8/importlib/__init__.py:127: in import_module
return _bootstrap._gcd_import(name[level:], package, level)
E ModuleNotFoundError: No module named 'pr98273'
=========================================================================================================================== short test summary info ============================================================================================================================
ERROR gcc/testsuite/g++.dg/gcov/pr98273.C.py
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Interrupted: 1 error during collection !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
=============================================================================================================================== 1 error in 0.08s ===============================================================================================================================
>
> Or would there be cases where different scripts could be called for the
> same .C file? Would scripts get reused between different source files?
>
> (not sure)
>
>> @@ -0,0 +1,27 @@
>> +from gcov import gcov_from_env
>> +
>> +import pytest
>> +
>> +
>> +@pytest.fixture(scope='function', autouse=True)
>> +def gcov():
>> + return gcov_from_env()
>> +
>> +
>> +def test_basics(gcov):
>> + files = gcov['files']
>> + assert len(files) == 1
>> + functions = files[0]['functions']
>> + assert len(functions) == 3
>> +
>> +
>> +def test_lines(gcov):
>> + lines = gcov['files'][0]['lines']
>> + linesdict = {}
>> + for line in lines:
>> + linesdict[int(line['line_number'])] = line
>> +
>> + assert linesdict[21]['function_name'] == 'main'
>> + assert linesdict[15]['function_name'] == '_ZZ4mainENKUlvE_clEv'
>> + assert (linesdict[12]['function_name']
>> + == '_ZZZ4mainENKUlvE_clEvENKUlvE_clEv')
>> diff --git a/gcc/testsuite/lib/gcov.exp b/gcc/testsuite/lib/gcov.exp
>> index 9276aead06b..dd589d4dd8a 100644
>> --- a/gcc/testsuite/lib/gcov.exp
>> +++ b/gcc/testsuite/lib/gcov.exp
>> @@ -247,6 +247,34 @@ proc verify-calls { testname testcase file } {
>> return $failed
>> }
>>
>> +proc run-gcov-pytest { args } {
>
> I think this function needs a leading comment, talking about what is
> invoked, and the kinds of lines that are parsed.
Sure.
>
> What happens if an exception is raised by the script? e.g. if there's
> a SyntaxError in the script, ideally it should "bubble up" through the
> Tcl layer into a DejaGnu "ERROR" I think, rather than being silently
> dropped.
It will caught now properly:
FAIL: ../../../../../../home/marxin/Programming/gcc/gcc/testsuite/g++.dg/gcov/test-pr98273.py - NameError: name 'asd' is not define
Martin
>
>> + global GCOV
>> + global srcdir subdir
>> + # Extract the test file name from the arguments.
>> + set testcase [lindex $args 0]
>> +
>> + verbose "Running $GCOV $testcase in $srcdir/$subdir" 2
>> + set testcase [remote_download host $testcase]
>> + set result [remote_exec host $GCOV "$testcase -i"]
>> +
>> + set pytest_script [lindex $args 1]
>> + setenv GCOV_PATH $testcase
>> + verbose "pytest_script: $pytest_script" 2
>> + spawn -noecho python3 -m pytest --color=no -rA -s --tb=no
>> $srcdir/$subdir/$pytest_script
>> +
>> + set prefix "\[^\r\n\]*"
>> + expect {
>> + -re "FAILED($prefix)\[^\r\n\]+\r\n" {
>> + fail "$expect_out(1,string)"
>> + exp_continue
>> + }
>> + -re "PASSED($prefix)\[^\r\n\]+\r\n" {
>> + pass "$expect_out(1,string)"
>> + exp_continue
>> + }
>> + }
>> +}
>> +
>> # Called by dg-final to run gcov and analyze the results.
>> #
>> # ARGS consists of the optional strings "branches" and/or "calls",
>
> Hope this is constructive
> Dave
>
[-- Attachment #2: 0001-Add-pytest-for-a-GCOV-test-case.patch --]
[-- Type: text/x-patch, Size: 4415 bytes --]
From 9a70db53d5f09e321ecfec8fba216b9482e4b380 Mon Sep 17 00:00:00 2001
From: Martin Liska <mliska@suse.cz>
Date: Mon, 21 Dec 2020 09:14:28 +0100
Subject: [PATCH] Add pytest for a GCOV test-case
gcc/testsuite/ChangeLog:
PR gcov-profile/98273
* lib/gcov.exp: Add run-gcov-pytest function which runs pytest.
* g++.dg/gcov/pr98273.C: New test.
* g++.dg/gcov/gcov.py: New test.
* g++.dg/gcov/test-pr98273.py: New test.
---
gcc/testsuite/g++.dg/gcov/gcov.py | 10 ++++++
gcc/testsuite/g++.dg/gcov/pr98273.C | 24 ++++++++++++++
gcc/testsuite/g++.dg/gcov/test-pr98273.py | 27 ++++++++++++++++
gcc/testsuite/lib/gcov.exp | 38 +++++++++++++++++++++++
4 files changed, 99 insertions(+)
create mode 100644 gcc/testsuite/g++.dg/gcov/gcov.py
create mode 100644 gcc/testsuite/g++.dg/gcov/pr98273.C
create mode 100644 gcc/testsuite/g++.dg/gcov/test-pr98273.py
diff --git a/gcc/testsuite/g++.dg/gcov/gcov.py b/gcc/testsuite/g++.dg/gcov/gcov.py
new file mode 100644
index 00000000000..a8c4ea9ae71
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gcov/gcov.py
@@ -0,0 +1,10 @@
+import gzip
+import json
+import os
+
+
+def gcov_from_env():
+ # return parsed JSON content a GCOV_PATH file
+ json_filename = os.environ['GCOV_PATH'] + '.gcov.json.gz'
+ json_data = gzip.open(json_filename).read()
+ return json.loads(json_data)
diff --git a/gcc/testsuite/g++.dg/gcov/pr98273.C b/gcc/testsuite/g++.dg/gcov/pr98273.C
new file mode 100644
index 00000000000..bfa83cbe4d0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gcov/pr98273.C
@@ -0,0 +1,24 @@
+/* PR gcov-profile/98273 */
+
+/* { dg-options "--coverage -std=c++11" } */
+/* { dg-do run { target native } } */
+
+int
+main ()
+{
+ int i = 42;
+ {
+ auto f = [] () {
+ auto g = [] () {};
+ g ();
+ g ();
+ };
+ f ();
+ }
+ ++i;
+ ++i;
+ ++i;
+ return 45 - i;
+}
+
+/* { dg-final { run-gcov-pytest pr98273.C "test-pr98273.py" } } */
diff --git a/gcc/testsuite/g++.dg/gcov/test-pr98273.py b/gcc/testsuite/g++.dg/gcov/test-pr98273.py
new file mode 100644
index 00000000000..6cb39d10c1e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gcov/test-pr98273.py
@@ -0,0 +1,27 @@
+from gcov import gcov_from_env
+
+import pytest
+
+
+@pytest.fixture(scope='function', autouse=True)
+def gcov():
+ return gcov_from_env()
+
+
+def test_basics(gcov):
+ files = gcov['files']
+ assert len(files) == 1
+ functions = files[0]['functions']
+ assert len(functions) == 3
+
+
+def test_lines(gcov):
+ lines = gcov['files'][0]['lines']
+ linesdict = {}
+ for line in lines:
+ linesdict[int(line['line_number'])] = line
+
+ assert linesdict[21]['function_name'] == 'main'
+ assert linesdict[15]['function_name'] == '_ZZ4mainENKUlvE_clEv'
+ assert (linesdict[12]['function_name']
+ == '_ZZZ4mainENKUlvE_clEvENKUlvE_clEv')
diff --git a/gcc/testsuite/lib/gcov.exp b/gcc/testsuite/lib/gcov.exp
index 9276aead06b..06e3ad60080 100644
--- a/gcc/testsuite/lib/gcov.exp
+++ b/gcc/testsuite/lib/gcov.exp
@@ -247,6 +247,44 @@ proc verify-calls { testname testcase file } {
return $failed
}
+# Call by dg-final to run gcov --json-format which produces a JSON file
+# that is later analysed by a pytest Python script.
+# We pass filename of a test via GCOV_PATH environment variable.
+
+proc run-gcov-pytest { args } {
+ global GCOV
+ global srcdir subdir
+ # Extract the test file name from the arguments.
+ set testcase [lindex $args 0]
+
+ verbose "Running $GCOV $testcase in $srcdir/$subdir" 2
+ set testcase [remote_download host $testcase]
+ set result [remote_exec host $GCOV "$testcase -i"]
+
+ set pytest_script [lindex $args 1]
+ setenv GCOV_PATH $testcase
+ verbose "pytest_script: $pytest_script" 2
+ spawn -noecho python3 -m pytest --color=no -rA -s --tb=no $srcdir/$subdir/$pytest_script
+
+ set prefix "\[^\r\n\]*"
+ expect {
+ -re "FAILED($prefix)\[^\r\n\]+\r\n" {
+ fail "$expect_out(1,string)"
+ exp_continue
+ }
+ -re "ERROR($prefix)\[^\r\n\]+\r\n" {
+ fail "$expect_out(1,string)"
+ exp_continue
+ }
+ -re "PASSED($prefix)\[^\r\n\]+\r\n" {
+ pass "$expect_out(1,string)"
+ exp_continue
+ }
+ }
+
+ clean-gcov $testcase
+}
+
# Called by dg-final to run gcov and analyze the results.
#
# ARGS consists of the optional strings "branches" and/or "calls",
--
2.29.2
next prev parent reply other threads:[~2020-12-23 13:03 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-12-22 11:39 Martin Liška
2020-12-22 17:49 ` David Malcolm
2020-12-23 13:03 ` Martin Liška [this message]
2021-01-05 23:36 ` Jeff Law
2021-01-07 16:14 ` Martin Liška
2021-01-08 20:29 ` Jeff Law
2021-01-13 13:38 ` Rainer Orth
2021-01-13 14:08 ` David Malcolm
2021-01-13 14:30 ` Rainer Orth
2021-01-14 8:56 ` Martin Liška
2021-01-14 13:22 ` Rainer Orth
2021-01-14 13:27 ` Rainer Orth
2021-01-14 13:33 ` Martin Liška
2021-01-15 12:28 ` Rainer Orth
2021-01-15 13:48 ` Martin Liška
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=ef9f6c9f-df2f-2a77-0f35-22c30bd92c7d@suse.cz \
--to=mliska@suse.cz \
--cc=dmalcolm@redhat.com \
--cc=gcc-patches@gcc.gnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).