[PATCH 1 of 2 V2] run-tests: expose hghave to .py tests by wrapping test file

Gregory Szorc gregory.szorc at gmail.com
Fri Mar 18 21:39:35 EDT 2016


# HG changeset patch
# User Gregory Szorc <gregory.szorc at gmail.com>
# Date 1458351397 25200
#      Fri Mar 18 18:36:37 2016 -0700
# Node ID 080070fdcd2672e06899daa8e162fd759609c793
# Parent  1435a8e9b5fe38cfe900e0a75fefab046af73dd6
run-tests: expose hghave to .py tests by wrapping test file

This patch adds a "wrapper" script to invoke Python tests. Instead
of executing .py tests directly, we invoke the wrapper which installs
some code and then executes the original .py file.

The wrapper script imports hghave and exposes a "require" function in
the global namespace. This will enable .py tests to call hghave natively
(instead of invoking it as a process).

The end goal is to consume hghave as a native Python module everywhere
instead of invoking a Python process to run hghave.

As part of this, we update filterpyflakes.py to filter
"undefined name 'requires'" errors in test files. We also had to
introduce a wrapper function for require() to ensure exit code 80
is preserved. We /could/ refactor the wrapper script to catch a
hghave specific exception instead. For now, we preserve existing
functionality instead of getting too fancy.

diff --git a/tests/filterpyflakes.py b/tests/filterpyflakes.py
--- a/tests/filterpyflakes.py
+++ b/tests/filterpyflakes.py
@@ -29,8 +29,14 @@ def makekey(typeandline):
 
 
 lines = []
 for line in sys.stdin:
+    # Whitelist magic require() symbol in python tests. We can't use
+    # the block below because it already detects "undefined name"
+    # issues albeit in a way that doesn't exclude this warning.
+    if re.search(r"test-.*\.py:\d+: undefined name 'require'", line):
+        continue
+
     # We whitelist tests (see more messages in pyflakes.messages)
     pats = [
             (r"imported but unused", None),
             (r"local variable '.*' is assigned to but never used", None),
diff --git a/tests/hghave.py b/tests/hghave.py
--- a/tests/hghave.py
+++ b/tests/hghave.py
@@ -68,8 +68,22 @@ def require(features):
 
     if result['skipped'] or result['error']:
         sys.exit(1)
 
+def requirefromtest(features):
+    """Wrapper for require() that should be used from within tests.
+
+    It converts exit code 1 to exit code 80 because that is the exit code
+    the test harness wants to indicate skips.
+    """
+    try:
+        require(features)
+    except SystemExit as e:
+        if e.code == 1:
+            e.code = 80
+
+        raise
+
 def matchoutput(cmd, regexp, ignorestatus=False):
     """Return the match object if cmd executes successfully and its output
     is matched by the supplied regular expression.
     """
diff --git a/tests/run-tests.py b/tests/run-tests.py
--- a/tests/run-tests.py
+++ b/tests/run-tests.py
@@ -883,9 +883,25 @@ class PythonTest(Test):
         return os.path.join(self._testdir, b'%s.out' % self.bname)
 
     def _run(self, env):
         py3kswitch = self._py3kwarnings and b' -3' or b''
-        cmd = b'%s%s "%s"' % (PYTHON, py3kswitch, self.path)
+
+        # We don't write the test path directly to the file in order to
+        # avoid quoting concerns.
+        testlines = [
+            b'import sys',
+            b'from hghave import requirefromtest as require',
+            b'with open(sys.argv[1], "rb") as fh:',
+            b'    code = compile(fh.read(), sys.argv[1], "exec")',
+            b'exec(code)',
+        ]
+
+        testpath = os.path.join(self._testtmp, b'test.py')
+        with open(testpath, 'wb') as fh:
+            fh.write(b'\n'.join(testlines))
+
+        cmd = b'%s%s "%s" "%s"' % (PYTHON, py3kswitch, testpath, self.path)
+
         vlog("# Running", cmd)
         normalizenewlines = os.name == 'nt'
         result = self._runcommand(cmd, env,
                                   normalizenewlines=normalizenewlines)
diff --git a/tests/test-check-pyflakes.t b/tests/test-check-pyflakes.t
--- a/tests/test-check-pyflakes.t
+++ b/tests/test-check-pyflakes.t
@@ -6,7 +6,7 @@ run pyflakes on all tracked files ending
 (skipping binary file random-seed)
 
   $ hg locate 'set:**.py or grep("^!#.*python")' 2>/dev/null \
   > | xargs pyflakes 2>/dev/null | "$TESTDIR/filterpyflakes.py"
-  tests/filterpyflakes.py:61: undefined name 'undefinedname'
+  tests/filterpyflakes.py:67: undefined name 'undefinedname'
   
 


More information about the Mercurial-devel mailing list