From: Ian Campbell <ijc@debian.org>
Date: Fri, 1 May 2020 12:35:43 +0800
Subject: Allow test suite to run out-of-tree

... such as in .pybuild/python_X.Y/build.

This involves including on extra package in the installation but is mostly
bodging things to substitute `$PYBUILD_TEST_BASE_OVERRIDE` for `$PWD` when
hunting for test resources.

Forwarded: not-needed
---
 cmakelang/command_tests/__init__.py   |  5 +++++
 cmakelang/command_tests/misc_tests.py |  3 +++
 cmakelang/format/invocation_tests.py  | 31 ++++++++++++++++++-------------
 cmakelang/lint/test/expect_tests.py   |  3 +++
 cmakelang/lint/test/genfiles.py       |  6 ++++++
 cmakelang/pypi/setup.py               |  3 +++
 cmakelang/test/screw_users_test.py    |  3 +++
 cmakelang/test/version_number_test.py |  3 +++
 cmakelang/tests.py                    |  6 ++++++
 9 files changed, 50 insertions(+), 13 deletions(-)

diff --git a/cmakelang/command_tests/__init__.py b/cmakelang/command_tests/__init__.py
index f0a1bf4..4608b0a 100644
--- a/cmakelang/command_tests/__init__.py
+++ b/cmakelang/command_tests/__init__.py
@@ -94,6 +94,9 @@ def find_sidecar(filepath, cls):
     return filepath
 
   thisdir = os.path.dirname(__file__)
+  base_override = os.getenv("PYBUILD_TEST_BASE_OVERRIDE")
+  if base_override is not None:
+    thisdir = thisdir.replace(os.environ['PWD'], base_override)
   clsname = cls.__name__
   if clsname.startswith("Test"):
     clsname = clsname[4:]
@@ -106,6 +109,8 @@ def find_sidecar(filepath, cls):
   if os.path.exists(candidate):
     return candidate
   candidate = inspect.getfile(cls)[:-3] + ".cmake"
+  if base_override is not None:
+    candidate = candidate.replace(os.environ['PWD'], base_override)
   if os.path.exists(candidate):
     return candidate
   return None
diff --git a/cmakelang/command_tests/misc_tests.py b/cmakelang/command_tests/misc_tests.py
index 96eec91..84ef906 100644
--- a/cmakelang/command_tests/misc_tests.py
+++ b/cmakelang/command_tests/misc_tests.py
@@ -130,6 +130,9 @@ project(cmakelang_test)
 
   def test_example_file(self):
     thisdir = os.path.dirname(__file__)
+    base_override = os.getenv("PYBUILD_TEST_BASE_OVERRIDE")
+    if base_override is not None:
+      thisdir = thisdir.replace(os.environ['PWD'], base_override)
     infile_path = os.path.join(
         thisdir, '..', 'format/testdata', 'test_in.cmake')
     outfile_path = os.path.join(
diff --git a/cmakelang/format/invocation_tests.py b/cmakelang/format/invocation_tests.py
index 4a4b51e..f5229ea 100644
--- a/cmakelang/format/invocation_tests.py
+++ b/cmakelang/format/invocation_tests.py
@@ -26,7 +26,12 @@ class TestInvocations(unittest.TestCase):
         'PYTHONPATH': os.path.dirname(parentdir)
     }
 
-    configpath = os.path.join(thisdir, 'testdata', 'cmake-format.py')
+    base_override = os.getenv("PYBUILD_TEST_BASE_OVERRIDE")
+    if base_override is not None:
+      self.thisdir = thisdir.replace(os.environ['PWD'], base_override)
+    else:
+      self.thisdir = thisdir
+    configpath = os.path.join(self.thisdir, 'testdata', 'cmake-format.py')
     self.tempconfig = os.path.join(self.tempdir, '.cmake-format.py')
     shutil.copyfile(configpath, self.tempconfig)
 
@@ -46,7 +51,7 @@ class TestInvocations(unittest.TestCase):
     Test invocation with an infile path and output to stdout.
     """
 
-    thisdir = os.path.realpath(os.path.dirname(__file__))
+    thisdir = self.thisdir
     infile_path = os.path.join(thisdir, 'testdata', 'test_in.cmake')
     expectfile_path = os.path.join(thisdir, 'testdata', 'test_out.cmake')
 
@@ -71,7 +76,7 @@ class TestInvocations(unittest.TestCase):
     Test invocation with an infile path and outfile path
     """
 
-    thisdir = os.path.realpath(os.path.dirname(__file__))
+    thisdir = self.thisdir
     infile_path = os.path.join(thisdir, 'testdata', 'test_in.cmake')
     expectfile_path = os.path.join(thisdir, 'testdata', 'test_out.cmake')
 
@@ -95,7 +100,7 @@ class TestInvocations(unittest.TestCase):
     Test invocation for inplace format of a file
     """
 
-    thisdir = os.path.realpath(os.path.dirname(__file__))
+    thisdir = self.thisdir
     infile_path = os.path.join(thisdir, 'testdata', 'test_in.cmake')
     expectfile_path = os.path.join(thisdir, 'testdata', 'test_out.cmake')
 
@@ -125,7 +130,7 @@ class TestInvocations(unittest.TestCase):
     Test invocation for --check of a file
     """
 
-    thisdir = os.path.realpath(os.path.dirname(__file__))
+    thisdir = self.thisdir
     unformatted_path = os.path.join(thisdir, 'testdata', 'test_in.cmake')
     formatted_path = os.path.join(thisdir, 'testdata', 'test_out.cmake')
 
@@ -145,7 +150,7 @@ class TestInvocations(unittest.TestCase):
     Test invocation with stdin as the infile and stdout as the outifle
     """
 
-    thisdir = os.path.realpath(os.path.dirname(__file__))
+    thisdir = self.thisdir
     infile_path = os.path.join(thisdir, 'testdata', 'test_in.cmake')
     expectfile_path = os.path.join(thisdir, 'testdata', 'test_out.cmake')
 
@@ -188,7 +193,7 @@ class TestInvocations(unittest.TestCase):
     specifically latin1 encoding (-> should succeed)
     """
 
-    thisdir = os.path.realpath(os.path.dirname(__file__))
+    thisdir = self.thisdir
     infile_path = os.path.join(thisdir, 'testdata', 'test_latin1_in.cmake')
     expectfile_path = os.path.join(thisdir, 'testdata', 'test_latin1_out.cmake')
 
@@ -229,7 +234,7 @@ class TestInvocations(unittest.TestCase):
     Test invocation with no config file specified
     """
     os.unlink(self.tempconfig)
-    thisdir = os.path.realpath(os.path.dirname(__file__))
+    thisdir = self.thisdir
     infile_path = os.path.join(thisdir, 'testdata', 'test_in.cmake')
     expectfile_path = os.path.join(thisdir, 'testdata', 'test_out.cmake')
 
@@ -253,7 +258,7 @@ class TestInvocations(unittest.TestCase):
     Repeat the default config test using a config file that is split. The
     custom command definitions are in the second file.
     """
-    thisdir = os.path.realpath(os.path.dirname(__file__))
+    thisdir = self.thisdir
     configdir = os.path.join(thisdir, 'testdata')
     infile_path = os.path.join(thisdir, 'testdata', 'test_in.cmake')
     expectfile_path = os.path.join(thisdir, 'testdata', 'test_out.cmake')
@@ -281,7 +286,7 @@ class TestInvocations(unittest.TestCase):
     Repeat the default config test using a config file that is split. The
     custom command definitions are in the second file.
     """
-    thisdir = os.path.realpath(os.path.dirname(__file__))
+    thisdir = self.thisdir
     configdir = os.path.join(thisdir, 'testdata')
     infile_path = os.path.join(thisdir, 'testdata', 'test_in.cmake')
     expectfile_path = os.path.join(thisdir, 'testdata', 'test_out.cmake')
@@ -308,7 +313,7 @@ class TestInvocations(unittest.TestCase):
     """
     Verify that windows line-endings are detected and preserved on input.
     """
-    thisdir = os.path.realpath(os.path.dirname(__file__))
+    thisdir = self.thisdir
     for suffix in ["win", "unix"]:
       with self.subTest(lineending=suffix):
         filename = "test_lineend_{}.cmake".format(suffix)
@@ -328,7 +333,7 @@ class TestInvocations(unittest.TestCase):
     """
     Verify that, if formatting is unchanged, an --in-place file is not modified
     """
-    thisdir = os.path.realpath(os.path.dirname(__file__))
+    thisdir = self.thisdir
     expectfile_path = os.path.join(thisdir, 'testdata', 'test_out.cmake')
     outfile_path = os.path.join(self.tempdir, 'test_out.cmake')
     shutil.copy2(expectfile_path, outfile_path)
@@ -343,7 +348,7 @@ class TestInvocations(unittest.TestCase):
     """
     Verify that the --require-valid-layout flag works as intended
     """
-    thisdir = os.path.realpath(os.path.dirname(__file__))
+    thisdir = self.thisdir
     testfilepath = os.path.join(thisdir, 'testdata', 'test_invalid.cmake')
 
     with tempfile.NamedTemporaryFile(
diff --git a/cmakelang/lint/test/expect_tests.py b/cmakelang/lint/test/expect_tests.py
index c959f47..c20cec1 100644
--- a/cmakelang/lint/test/expect_tests.py
+++ b/cmakelang/lint/test/expect_tests.py
@@ -139,6 +139,9 @@ EXCLUSIONS = [
 
 def iter_testfiles():
   thisdir = os.path.dirname(os.path.realpath(__file__))
+  base_override = os.getenv("PYBUILD_TEST_BASE_OVERRIDE")
+  if base_override is not None:
+    thisdir = thisdir.replace(os.environ['PWD'], base_override)
   for dirpath, _dirnames, filenames in os.walk(thisdir):
     for filename in filenames:
       if filename in EXCLUSIONS:
diff --git a/cmakelang/lint/test/genfiles.py b/cmakelang/lint/test/genfiles.py
index b41bc20..39d0b0e 100644
--- a/cmakelang/lint/test/genfiles.py
+++ b/cmakelang/lint/test/genfiles.py
@@ -13,6 +13,9 @@ logger = logging.getLogger(__name__)
 
 def make_expect_lint():
   thisdir = os.path.dirname(os.path.realpath(__file__))
+  base_override = os.getenv("PYBUILD_TEST_BASE_OVERRIDE")
+  if base_override is not None:
+    thisdir = thisdir.replace(os.environ['PWD'], base_override)
 
   # strip test annotations from the test file make the documentation a little
   # cleaner
@@ -27,6 +30,9 @@ def make_expect_lint():
 
 def rewrite_lint_tests():
   thisdir = os.path.dirname(os.path.realpath(__file__))
+  base_override = os.getenv("PYBUILD_TEST_BASE_OVERRIDE")
+  if base_override is not None:
+    thisdir = thisdir.replace(os.environ['PWD'], base_override)
 
   # re-process the test file to re-introduce lint that is likely to have been
   # removed by an editor
diff --git a/cmakelang/pypi/setup.py b/cmakelang/pypi/setup.py
index 36ad4c7..6a2d4fd 100644
--- a/cmakelang/pypi/setup.py
+++ b/cmakelang/pypi/setup.py
@@ -20,11 +20,14 @@ setup(
     name="cmakelang",
     packages=[
         "cmakelang",
+        "cmakelang.command_tests",
         "cmakelang.format",
         "cmakelang.lex",
         "cmakelang.lint",
+        "cmakelang.lint.test",
         "cmakelang.parse",
         "cmakelang.parse.funs",
+        "cmakelang.test",
     ],
     version=VERSION,
     description="Language tools for cmake (format, lint, etc)",
diff --git a/cmakelang/test/screw_users_test.py b/cmakelang/test/screw_users_test.py
index 3be1b1c..dd711d8 100644
--- a/cmakelang/test/screw_users_test.py
+++ b/cmakelang/test/screw_users_test.py
@@ -119,6 +119,9 @@ class DontScrewUsers(unittest.TestCase):
 
     env = os.environ.copy()
     thisdir = os.path.dirname(__file__)
+    base_override = os.getenv("PYBUILD_TEST_BASE_OVERRIDE")
+    if base_override is not None:
+      thisdir = thisdir.replace(os.environ['PWD'], base_override)
     thisdir = os.path.dirname(thisdir)
     repodir = os.path.dirname(thisdir)
     env["PYTHONPATH"] = os.path.realpath(repodir)
diff --git a/cmakelang/test/version_number_test.py b/cmakelang/test/version_number_test.py
index 26db14b..720f815 100644
--- a/cmakelang/test/version_number_test.py
+++ b/cmakelang/test/version_number_test.py
@@ -17,6 +17,9 @@ class TestVersionNumber(unittest.TestCase):
 
   def setUp(self):
     thisdir = os.path.dirname(os.path.realpath(__file__))
+    base_override = os.getenv("PYBUILD_TEST_BASE_OVERRIDE")
+    if base_override is not None:
+      thisdir = thisdir.replace(os.environ['PWD'], base_override)
     parent = os.path.dirname(thisdir)
     self.repodir = os.path.dirname(parent)
     with open(os.path.join(parent, "__init__.py")) as infile:
diff --git a/cmakelang/tests.py b/cmakelang/tests.py
index bbdbf84..ec5d7a4 100644
--- a/cmakelang/tests.py
+++ b/cmakelang/tests.py
@@ -1,5 +1,11 @@
 import unittest
 
+import sys
+import os
+base_override = os.getenv("PYBUILD_TEST_BASE_OVERRIDE")
+if base_override is not None:
+  sys.path.append(base_override)
+
 # pylint: disable=wildcard-import
 # pylint: disable=unused-wildcard-import
 # pylint: disable=unused-import
