public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
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


  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).