This provides optional lit-based test execution for the LLVM Libc tests, alongside the existing CMake-based test execution. Usage: ninja -C build check-libc-lit cd build && bin/llvm-lit libc/test/src/ Partially addresses [#118694](https://github.com/llvm/llvm-project/issues/118694). A future PR once this lands will flip the default (per suggestion in the RFC)
107 lines
3.7 KiB
Python
107 lines
3.7 KiB
Python
# ===----------------------------------------------------------------------===##
|
|
#
|
|
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
# See https://llvm.org/LICENSE.txt for license information.
|
|
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
#
|
|
# ===----------------------------------------------------------------------===##
|
|
|
|
"""
|
|
Lit test format for LLVM libc tests.
|
|
|
|
This format discovers pre-built test executables in the build directory
|
|
and runs them. It extends lit's ExecutableTest format.
|
|
|
|
The lit config sets test_source_root == test_exec_root (both to the build
|
|
directory), following the pattern used by llvm/test/Unit/lit.cfg.py.
|
|
|
|
Test executables are discovered by looking for files matching:
|
|
libc.test.src.<category>.<test_name>.__unit__.__build__
|
|
libc.test.src.<category>.<test_name>.__hermetic__.__build__
|
|
|
|
These are created by the add_libc_test() infrastructure.
|
|
"""
|
|
|
|
import os
|
|
import shlex
|
|
|
|
import lit.formats
|
|
import lit.Test
|
|
import lit.util
|
|
|
|
|
|
class LibcTest(lit.formats.ExecutableTest):
|
|
"""
|
|
Test format for libc unit tests.
|
|
|
|
Extends ExecutableTest to discover tests from the build directory
|
|
rather than the source directory. Test executables are named like:
|
|
libc.test.src.ctype.isalnum_test.__unit__.__build__
|
|
and return 0 on success.
|
|
"""
|
|
|
|
def getTestsInDirectory(self, testSuite, path_in_suite, litConfig, localConfig):
|
|
"""
|
|
Discover test executables in the build directory.
|
|
|
|
Since test_source_root == test_exec_root (both point to build dir),
|
|
we use getSourcePath() to find test executables.
|
|
"""
|
|
source_path = testSuite.getSourcePath(path_in_suite)
|
|
|
|
# Look for test executables in the build directory
|
|
if not os.path.isdir(source_path):
|
|
return
|
|
|
|
# Sort for deterministic test discovery/output ordering.
|
|
for filename in sorted(os.listdir(source_path)):
|
|
filepath = os.path.join(source_path, filename)
|
|
|
|
# Match our test executable pattern
|
|
if self._isTestExecutable(filename, filepath):
|
|
# Create a test with the executable name
|
|
yield lit.Test.Test(testSuite, path_in_suite + (filename,), localConfig)
|
|
|
|
def _isTestExecutable(self, filename, filepath):
|
|
"""Check if a file is a test executable we should run."""
|
|
# Pattern: libc.test.src.*.__unit__.__build__ or .__hermetic__.__build__
|
|
if not filename.startswith("libc.test."):
|
|
return False
|
|
if not (
|
|
filename.endswith(".__unit__.__build__")
|
|
or filename.endswith(".__hermetic__.__build__")
|
|
):
|
|
return False
|
|
# Must be executable
|
|
if not os.path.isfile(filepath):
|
|
return False
|
|
if not os.access(filepath, os.X_OK):
|
|
return False
|
|
return True
|
|
|
|
def execute(self, test, litConfig):
|
|
"""
|
|
Execute a test by running the test executable.
|
|
|
|
Runs from the executable's directory so relative paths (like
|
|
testdata/test.txt) work correctly.
|
|
"""
|
|
|
|
test_path = test.getSourcePath()
|
|
exec_dir = os.path.dirname(test_path)
|
|
|
|
test_cmd_template = getattr(test.config, "libc_test_cmd", "")
|
|
if test_cmd_template:
|
|
test_cmd = test_cmd_template.replace("@BINARY@", test_path)
|
|
cmd_args = shlex.split(test_cmd)
|
|
if not cmd_args:
|
|
cmd_args = [test_path]
|
|
out, err, exit_code = lit.util.executeCommand(cmd_args, cwd=exec_dir)
|
|
else:
|
|
out, err, exit_code = lit.util.executeCommand([test_path], cwd=exec_dir)
|
|
|
|
if not exit_code:
|
|
return lit.Test.PASS, ""
|
|
|
|
return lit.Test.FAIL, out + err
|