Add pytest for a GCOV test-case
authorMartin Liska <mliska@suse.cz>
Mon, 21 Dec 2020 08:14:28 +0000 (09:14 +0100)
committerMartin Liska <mliska@suse.cz>
Mon, 11 Jan 2021 08:18:53 +0000 (09:18 +0100)
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 [new file with mode: 0644]
gcc/testsuite/g++.dg/gcov/pr98273.C [new file with mode: 0644]
gcc/testsuite/g++.dg/gcov/test-pr98273.py [new file with mode: 0644]
gcc/testsuite/lib/gcov.exp

diff --git a/gcc/testsuite/g++.dg/gcov/gcov.py b/gcc/testsuite/g++.dg/gcov/gcov.py
new file mode 100644 (file)
index 0000000..a8c4ea9
--- /dev/null
@@ -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 (file)
index 0000000..bfa83cb
--- /dev/null
@@ -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 (file)
index 0000000..6cb39d1
--- /dev/null
@@ -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')
index bb95643..4bcab1d 100644 (file)
@@ -247,6 +247,51 @@ 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 result [remote_exec host "pytest -m pytest --version"]
+    set status [lindex $result 0]
+    if { $status != 0 } then {
+      unresolved "could not find Python interpreter and (or) pytest module for $testcase"
+      return
+    }
+
+    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",