From e05bca399f02870038e4e5dcecc749c1c1825a44 Mon Sep 17 00:00:00 2001
From: Krzysztof Gogolewski <krzysztof.gogolewski@tweag.io>
Date: Sat, 25 Nov 2023 04:16:31 +0100
Subject: [PATCH] testsuite: don't initialize testdir to '.'

The test directory is removed during cleanup, if there's an interrupt
that could remove the entire repository.

Fixes #24219
---
 testsuite/driver/testglobals.py | 12 ++++++++++--
 testsuite/driver/testlib.py     | 10 ++++++----
 2 files changed, 16 insertions(+), 6 deletions(-)

diff --git a/testsuite/driver/testglobals.py b/testsuite/driver/testglobals.py
index 36f18a8c7f90..cb281b9d938c 100644
--- a/testsuite/driver/testglobals.py
+++ b/testsuite/driver/testglobals.py
@@ -436,8 +436,10 @@ class TestOptions:
        # Keep profiling callstacks.
        self.keep_prof_callstacks = False
 
-       # The directory the test is in
-       self.testdir = Path('.')
+       # The directory the test is run.
+       # Usually you should check the self.testdir property instead,
+       # which crashes when this is not initialised.
+       self.testdir_raw = None # type: Optional[Path]
 
        # Should we redirect stdout and stderr to a single file?
        self.combined_output = False
@@ -462,6 +464,12 @@ class TestOptions:
        # The extra hadrian dependencies we need for this particular test
        self.hadrian_deps = set(["test:ghc"]) # type: Set[str]
 
+   @property
+   def testdir(self) -> Path:
+       if self.testdir_raw is None:
+           raise Exception('testdir not initialized')
+       return self.testdir_raw
+
 # The default set of options
 global default_testopts
 default_testopts = TestOptions()
diff --git a/testsuite/driver/testlib.py b/testsuite/driver/testlib.py
index c23757ebfc52..e315f451e1b7 100644
--- a/testsuite/driver/testlib.py
+++ b/testsuite/driver/testlib.py
@@ -1175,7 +1175,7 @@ testdir_suffix = '.run'
 def _newTestDir(name: TestName, opts: TestOptions, tempdir, dir):
     testdir = os.path.join('', *(p for p in PurePath(dir).parts if p != '..'))
     opts.srcdir = Path.cwd() / dir
-    opts.testdir = Path(os.path.join(tempdir, testdir, name + testdir_suffix))
+    opts.testdir_raw = Path(os.path.join(tempdir, testdir, name + testdir_suffix))
     opts.compiler_always_flags = config.compiler_always_flags
 
 # -----------------------------------------------------------------------------
@@ -2952,7 +2952,9 @@ def find_expected_file(name: TestName, suff: str) -> Path:
 if config.msys:
     import stat
     def cleanup() -> None:
-        testdir = getTestOpts().testdir # type: Path
+        testdir = getTestOpts().testdir_raw # type: Optional[Path]
+        if testdir is None:
+            return
         max_attempts = 5
         retries = max_attempts
         def on_error(function, path: str, excinfo):
@@ -2992,8 +2994,8 @@ if config.msys:
                             % (testdir, exception))
 else:
     def cleanup() -> None:
-        testdir = getTestOpts().testdir
-        if testdir.exists():
+        testdir = getTestOpts().testdir_raw
+        if testdir is not None and testdir.exists():
             shutil.rmtree(str(testdir), ignore_errors=False)
 
 
-- 
GitLab