[libcxx-commits] [libcxx] 5b55eb1 - [lit] Add a method to lit.TestFormat to get the list of tests associated to a path
Louis Dionne via libcxx-commits
libcxx-commits at lists.llvm.org
Tue Jun 27 13:28:00 PDT 2023
Author: Louis Dionne
Date: 2023-06-27T16:27:08-04:00
New Revision: 5b55eb1e888430abfbcde8a84c99ca35fb3c5374
URL: https://github.com/llvm/llvm-project/commit/5b55eb1e888430abfbcde8a84c99ca35fb3c5374
DIFF: https://github.com/llvm/llvm-project/commit/5b55eb1e888430abfbcde8a84c99ca35fb3c5374.diff
LOG: [lit] Add a method to lit.TestFormat to get the list of tests associated to a path
Lit TestFormat classes already needed to implement the getTestsInDirectory
method. However, some test formats may want to expand a single test path
to multiple Lit tests, for example in the case of a test that actually
generates other Lit tests.
To accommodate that, this commit adds the getTestsForPath method to
TestFormat. This method can be used to turn a single path in a Lit
test suite into a list of tests associated to that path.
Differential Revision: https://reviews.llvm.org/D151664
Added:
llvm/utils/lit/tests/Inputs/discovery-getTestsForPath/custom_format.py
llvm/utils/lit/tests/Inputs/discovery-getTestsForPath/lit.cfg
llvm/utils/lit/tests/Inputs/discovery-getTestsForPath/x.test
Modified:
libcxx/utils/libcxx/test/format.py
llvm/utils/lit/examples/many-tests/ManyTests.py
llvm/utils/lit/lit/discovery.py
llvm/utils/lit/lit/formats/base.py
llvm/utils/lit/tests/discovery.py
Removed:
################################################################################
diff --git a/libcxx/utils/libcxx/test/format.py b/libcxx/utils/libcxx/test/format.py
index 8a96dbceef4e9..13e40738d30ae 100644
--- a/libcxx/utils/libcxx/test/format.py
+++ b/libcxx/utils/libcxx/test/format.py
@@ -182,7 +182,7 @@ def parseScript(test, preamble):
return script
-class CxxStandardLibraryTest(lit.formats.TestFormat):
+class CxxStandardLibraryTest(lit.formats.FileBasedTest):
"""
Lit test format for the C++ Standard Library conformance test suite.
@@ -278,7 +278,7 @@ class CxxStandardLibraryTest(lit.formats.TestFormat):
in conjunction with the %{build} substitution.
"""
- def getTestsInDirectory(self, testSuite, pathInSuite, litConfig, localConfig):
+ def getTestsForPath(self, testSuite, pathInSuite, litConfig, localConfig):
SUPPORTED_SUFFIXES = [
"[.]pass[.]cpp$",
"[.]pass[.]mm$",
@@ -293,22 +293,22 @@ def getTestsInDirectory(self, testSuite, pathInSuite, litConfig, localConfig):
"[.]verify[.]cpp$",
"[.]fail[.]cpp$",
]
+
sourcePath = testSuite.getSourcePath(pathInSuite)
- for filename in os.listdir(sourcePath):
- # Ignore dot files and excluded tests.
- if filename.startswith(".") or filename in localConfig.excludes:
- continue
-
- filepath = os.path.join(sourcePath, filename)
- if not os.path.isdir(filepath):
- if any([re.search(ext, filename) for ext in SUPPORTED_SUFFIXES]):
- # If this is a generated test, run the generation step and add
- # as many Lit tests as necessary.
- if re.search('[.]gen[.][^.]+$', filename):
- for test in self._generateGenTest(testSuite, pathInSuite + (filename,), litConfig, localConfig):
- yield test
- else:
- yield lit.Test.Test(testSuite, pathInSuite + (filename,), localConfig)
+ filename = os.path.basename(sourcePath)
+
+ # Ignore dot files, excluded tests and tests with an unsupported suffix
+ hasSupportedSuffix = lambda f: any([re.search(ext, f) for ext in SUPPORTED_SUFFIXES])
+ if filename.startswith(".") or filename in localConfig.excludes or not hasSupportedSuffix(filename):
+ return
+
+ # If this is a generated test, run the generation step and add
+ # as many Lit tests as necessary.
+ if re.search('[.]gen[.][^.]+$', filename):
+ for test in self._generateGenTest(testSuite, pathInSuite, litConfig, localConfig):
+ yield test
+ else:
+ yield lit.Test.Test(testSuite, pathInSuite, localConfig)
def execute(self, test, litConfig):
VERIFY_FLAGS = (
diff --git a/llvm/utils/lit/examples/many-tests/ManyTests.py b/llvm/utils/lit/examples/many-tests/ManyTests.py
index df3edb55b85e9..89e818a037c39 100644
--- a/llvm/utils/lit/examples/many-tests/ManyTests.py
+++ b/llvm/utils/lit/examples/many-tests/ManyTests.py
@@ -1,7 +1,7 @@
-from lit import Test
+from lit import Test, TestFormat
-class ManyTests(object):
+class ManyTests(TestFormat):
def __init__(self, N=10000):
self.N = N
diff --git a/llvm/utils/lit/lit/discovery.py b/llvm/utils/lit/lit/discovery.py
index 5bfe1eb5acd71..e421a87b55664 100644
--- a/llvm/utils/lit/lit/discovery.py
+++ b/llvm/utils/lit/lit/discovery.py
@@ -163,35 +163,43 @@ def getTestsInSuite(
if not os.path.isdir(source_path):
test_dir_in_suite = path_in_suite[:-1]
lc = getLocalConfig(ts, test_dir_in_suite, litConfig, localConfigCache)
- test = Test.Test(ts, path_in_suite, lc)
-
- # Issue a error if the specified test would not be run if
- # the user had specified the containing directory instead of
- # of naming the test directly. This helps to avoid writing
- # tests which are not executed. The check adds some performance
- # overhead which might be important if a large number of tests
- # are being run directly.
- # This check can be disabled by using --no-indirectly-run-check or
- # setting the standalone_tests variable in the suite's configuration.
- if (
- indirectlyRunCheck
- and lc.test_format is not None
- and not lc.standalone_tests
- ):
- found = False
- for res in lc.test_format.getTestsInDirectory(
- ts, test_dir_in_suite, litConfig, lc
+
+ # TODO: Stop checking for indirectlyRunCheck and lc.standalone_tests here
+ # once we remove --no-indirectly-run-check, which is not needed anymore
+ # now that we error out when trying to run a test that wouldn't be
+ # discovered in the directory.
+ fallbackOnSingleTest = lc.test_format is None or not indirectlyRunCheck or lc.standalone_tests
+ tests = [Test.Test(ts, path_in_suite, lc)] if fallbackOnSingleTest else \
+ lc.test_format.getTestsForPath(ts, path_in_suite, litConfig, lc)
+
+ for test in tests:
+ # Issue a error if the specified test would not be run if
+ # the user had specified the containing directory instead of
+ # of naming the test directly. This helps to avoid writing
+ # tests which are not executed. The check adds some performance
+ # overhead which might be important if a large number of tests
+ # are being run directly.
+ # This check can be disabled by using --no-indirectly-run-check or
+ # setting the standalone_tests variable in the suite's configuration.
+ if (
+ indirectlyRunCheck
+ and lc.test_format is not None
+ and not lc.standalone_tests
):
- if test.getFullName() == res.getFullName():
- found = True
- break
- if not found:
- litConfig.error(
- "%r would not be run indirectly: change name or LIT config"
- "(e.g. suffixes or standalone_tests variables)" % test.getFullName()
- )
-
- yield test
+ found = False
+ for res in lc.test_format.getTestsInDirectory(
+ ts, test_dir_in_suite, litConfig, lc
+ ):
+ if test.getFullName() == res.getFullName():
+ found = True
+ break
+ if not found:
+ litConfig.error(
+ "%r would not be run indirectly: change name or LIT config"
+ "(e.g. suffixes or standalone_tests variables)" % test.getFullName()
+ )
+
+ yield test
return
# Otherwise we have a directory to search for tests, start by getting the
diff --git a/llvm/utils/lit/lit/formats/base.py b/llvm/utils/lit/lit/formats/base.py
index 0f8e984b2ab48..8430f6fe9ed58 100644
--- a/llvm/utils/lit/lit/formats/base.py
+++ b/llvm/utils/lit/lit/formats/base.py
@@ -6,27 +6,42 @@
class TestFormat(object):
- pass
-
+ def getTestsForPath(self, testSuite, path_in_suite, litConfig, localConfig):
+ """
+ Given the path to a test in the test suite, generates the Lit tests associated
+ to that path. There can be zero, one or more tests. For example, some testing
+ formats allow expanding a single path in the test suite into multiple Lit tests
+ (e.g. they are generated on the fly).
+ """
+ yield lit.Test.Test(testSuite, path_in_suite, localConfig)
###
class FileBasedTest(TestFormat):
+ def getTestsForPath(self, testSuite, path_in_suite, litConfig, localConfig):
+ """
+ Expand each path in a test suite to a Lit test using that path and assuming
+ it is a file containing the test. File extensions excluded by the configuration
+ or not contained in the allowed extensions are ignored.
+ """
+ filename = path_in_suite[-1]
+
+ # Ignore dot files and excluded tests.
+ if filename.startswith(".") or filename in localConfig.excludes:
+ return
+
+ base, ext = os.path.splitext(filename)
+ if ext in localConfig.suffixes:
+ yield lit.Test.Test(testSuite, path_in_suite, localConfig)
+
def getTestsInDirectory(self, testSuite, path_in_suite, litConfig, localConfig):
source_path = testSuite.getSourcePath(path_in_suite)
for filename in os.listdir(source_path):
- # Ignore dot files and excluded tests.
- if filename.startswith(".") or filename in localConfig.excludes:
- continue
-
filepath = os.path.join(source_path, filename)
if not os.path.isdir(filepath):
- base, ext = os.path.splitext(filename)
- if ext in localConfig.suffixes:
- yield lit.Test.Test(
- testSuite, path_in_suite + (filename,), localConfig
- )
+ for t in self.getTestsForPath(testSuite, path_in_suite + (filename,), litConfig, localConfig):
+ yield t
###
diff --git a/llvm/utils/lit/tests/Inputs/discovery-getTestsForPath/custom_format.py b/llvm/utils/lit/tests/Inputs/discovery-getTestsForPath/custom_format.py
new file mode 100644
index 0000000000000..c6f469fc81d53
--- /dev/null
+++ b/llvm/utils/lit/tests/Inputs/discovery-getTestsForPath/custom_format.py
@@ -0,0 +1,12 @@
+import os
+import lit.formats
+
+class CustomFormat(lit.formats.ShTest):
+ def getTestsForPath(self, testSuite, path_in_suite, litConfig, localConfig):
+ for sub in ['one.test', 'two.test']:
+ basePath = os.path.dirname(testSuite.getExecPath(path_in_suite))
+ os.makedirs(basePath, exist_ok=True)
+ generatedFile = os.path.join(basePath, sub)
+ with open(generatedFile, 'w') as f:
+ f.write('RUN: true')
+ yield lit.Test.Test(testSuite, (generatedFile, ), localConfig)
diff --git a/llvm/utils/lit/tests/Inputs/discovery-getTestsForPath/lit.cfg b/llvm/utils/lit/tests/Inputs/discovery-getTestsForPath/lit.cfg
new file mode 100644
index 0000000000000..10192a6cbf137
--- /dev/null
+++ b/llvm/utils/lit/tests/Inputs/discovery-getTestsForPath/lit.cfg
@@ -0,0 +1,9 @@
+import sys, os
+sys.path.append(os.path.dirname(__file__))
+from custom_format import CustomFormat
+
+config.name = "discovery-getTestsForPath-suite"
+config.suffixes = [".test"]
+config.test_format = CustomFormat()
+config.test_source_root = None
+config.test_exec_root = None
diff --git a/llvm/utils/lit/tests/Inputs/discovery-getTestsForPath/x.test b/llvm/utils/lit/tests/Inputs/discovery-getTestsForPath/x.test
new file mode 100644
index 0000000000000..e69de29bb2d1d
diff --git a/llvm/utils/lit/tests/discovery.py b/llvm/utils/lit/tests/discovery.py
index 221a634ce4354..5bf25574e15b3 100644
--- a/llvm/utils/lit/tests/discovery.py
+++ b/llvm/utils/lit/tests/discovery.py
@@ -134,14 +134,15 @@
# CHECK-ASEXEC-DIRECT-TEST: -- Available Tests --
# CHECK-ASEXEC-DIRECT-TEST: top-level-suite :: subdir/test-three
-# Check an error is emitted when the directly named test would not be run
-# indirectly (e.g. when the directory containing the test is specified).
+# Check that an error is emitted when the directly named test does not satisfy
+# the test config's requirements.
#
# RUN: not %{lit} \
# RUN: %{inputs}/discovery/test.not-txt 2>%t.err
-# RUN: FileCheck --check-prefix=CHECK-ERROR-INDIRECT-RUN-CHECK < %t.err %s
+# RUN: FileCheck --check-prefix=CHECK-ERROR-INPUT-CONTAINED-NO-TESTS < %t.err %s
#
-# CHECK-ERROR-INDIRECT-RUN-CHECK: error: 'top-level-suite :: test.not-txt' would not be run indirectly
+# CHECK-ERROR-INPUT-CONTAINED-NO-TESTS: warning: input 'Inputs/discovery/test.not-txt' contained no tests
+# CHECK-ERROR-INPUT-CONTAINED-NO-TESTS: error: did not discover any tests for provided path(s)
# Check that no error is emitted with --no-indirectly-run-check.
#
@@ -178,6 +179,15 @@
#
# CHECK-STANDALONE-DISCOVERY: error: did not discover any tests for provided path(s)
+# Check that a single file path can result in multiple tests being discovered if
+# the test format implements those semantics.
+#
+# RUN: %{lit} %{inputs}/discovery-getTestsForPath/x.test > %t.out
+# RUN: FileCheck --check-prefix=CHECK-getTestsForPath < %t.out %s
+#
+# CHECK-getTestsForPath: PASS: discovery-getTestsForPath-suite :: {{.+}}one.test
+# CHECK-getTestsForPath: PASS: discovery-getTestsForPath-suite :: {{.+}}two.test
+
# Check that we don't recurse infinitely when loading an site specific test
# suite located inside the test source root.
#
More information about the libcxx-commits
mailing list