-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Proposed testing framework for Standard Library facilities
This "testing framework" is based on the LLVM Integrated Tester, which is used to implement the libc++ conformance test suite. In turn, this conformance suite is also used by other non-LLVM implementations to check their conformance. Using this testing framework means that papers contributed to the Beman project will already include tests that can be reused by the major implementations, which is both a great time saver for implementers but also a great way for implementers to get experience with implementing the paper within their own implementation and provide feedback to LEWG during design reviews.
- Loading branch information
Showing
13 changed files
with
274 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,15 @@ | ||
// Copyright © 2024 Bret Brown | ||
// SPDX-License-Identifier: MIT | ||
|
||
#ifndef EXAMPLE_HXX | ||
#define EXAMPLE_HXX | ||
|
||
#include <type_traits> | ||
|
||
template <class T> | ||
constexpr bool foo() { | ||
static_assert(std::is_trivially_copyable_v<T>); | ||
return true; | ||
} | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,30 @@ | ||
add_executable(example.test) | ||
target_sources(example.test PRIVATE example.test.cxx) | ||
target_link_libraries(example.test PRIVATE example::example) | ||
# Setup the `lit` tool | ||
add_custom_command( | ||
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/venv/bin/lit" | ||
COMMAND python3 -m venv "${CMAKE_CURRENT_BINARY_DIR}/venv" | ||
COMMAND "${CMAKE_CURRENT_BINARY_DIR}/venv/bin/pip" install --upgrade pip | ||
COMMAND "${CMAKE_CURRENT_BINARY_DIR}/venv/bin/pip" install --upgrade lit | ||
) | ||
|
||
# Setup the test suite configuration | ||
configure_file("${CMAKE_SOURCE_DIR}/test/support/lit.cfg.in" | ||
"${CMAKE_CURRENT_BINARY_DIR}/lit.cfg") | ||
|
||
add_custom_target(test-depends | ||
COMMAND true | ||
DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/venv/bin/lit" | ||
"${CMAKE_CURRENT_BINARY_DIR}/lit.cfg" | ||
example | ||
COMMENT "Setup the test dependencies" | ||
) | ||
|
||
add_test( | ||
NAME setup-tests | ||
COMMAND "${CMAKE_COMMAND}" --build "${CMAKE_BINARY_DIR}" --target test-depends | ||
) | ||
|
||
add_test( | ||
NAME example.test | ||
COMMAND example.test | ||
COMMAND "${CMAKE_CURRENT_BINARY_DIR}/venv/bin/lit" -sv "${CMAKE_CURRENT_BINARY_DIR}" | ||
) | ||
set_tests_properties(example.test PROPERTIES DEPENDS setup-tests) |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
// | ||
// This test gets built and run. The test succeeds if the program | ||
// terminates normally with a 0 exit code. The test fails if it | ||
// doesn't compile, link or if it exits with an error. | ||
// | ||
|
||
#include <cassert> | ||
#include <example.hxx> | ||
|
||
int main(int, char**) { | ||
assert(foo<int>()); | ||
|
||
return 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
// | ||
// This test runs using clang-verify. This allows checking that specific | ||
// diagnostics are being emitted at compile-time. | ||
// | ||
// Clang-verify supports various directives like 'expected-error', | ||
// 'expected-warning', etc. The full set of directives supported and | ||
// how to use them is documented in https://clang.llvm.org/docs/InternalsManual.html#specifying-diagnostics. | ||
// | ||
|
||
#include <string> | ||
#include <example.hxx> | ||
|
||
void f() { | ||
foo<std::string>(); // expected-error@*:* {{static assertion failed due to requirement 'std::is_trivially_copyable_v}} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
// | ||
// This test doesn't run, it only compiles. | ||
// The test passes if the program compiles, and fails otherwise. | ||
// | ||
|
||
#include <example.hxx> | ||
|
||
static_assert(foo<int>()); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
// | ||
// This test runs whatever shell commands are specified in the RUN commands | ||
// below. This provides a lot of flexibility for controlling how the test | ||
// gets built and run. | ||
// | ||
|
||
// RUN: %{cxx} %{flags} %s -DTRANSLATION_UNIT_1 -c -o %t.tu1.o | ||
// RUN: %{cxx} %{flags} %s -DTRANSLATION_UNIT_2 -c -o %t.tu2.o | ||
// RUN: %{cxx} %{flags} %t.tu1.o %t.tu2.o -o %t.exe | ||
// RUN: %t.exe | ||
|
||
#include <example.hxx> | ||
|
||
#ifdef TRANSLATION_UNIT_1 | ||
void f() { } | ||
#endif | ||
|
||
#ifdef TRANSLATION_UNIT_2 | ||
extern void f(); | ||
|
||
int main() { | ||
f(); | ||
} | ||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import site, os | ||
site.addsitedir(os.path.join('@CMAKE_SOURCE_DIR@', 'test', 'support')) | ||
import testformat | ||
|
||
config.name = 'Beman project test suite' | ||
config.test_format = testformat.CxxStandardLibraryTest() | ||
config.test_exec_root = '@CMAKE_CURRENT_BINARY_DIR@' | ||
config.test_source_root = '@CMAKE_CURRENT_SOURCE_DIR@' | ||
flags = [ | ||
'-std=c++20', | ||
'-isysroot @CMAKE_OSX_SYSROOT@' if '@CMAKE_OSX_SYSROOT@' else '', | ||
'-isystem {}'.format(os.path.join('@CMAKE_SOURCE_DIR@', 'src', 'example')), | ||
'@CMAKE_CXX_FLAGS@' | ||
] | ||
config.substitutions = [ | ||
('%{cxx}', '@CMAKE_CXX_COMPILER@'), | ||
('%{flags}', ' '.join(filter(None, flags))) | ||
] | ||
config.available_features = [] | ||
if '@CMAKE_CXX_COMPILER_ID@' in ('Clang', 'AppleClang'): | ||
config.available_features.append('verify-support') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
import lit | ||
import os | ||
import re | ||
|
||
def _parseScript(test, preamble): | ||
""" | ||
Extract the script from a test, with substitutions applied. | ||
Returns a list of commands ready to be executed. | ||
- test | ||
The lit.Test to parse. | ||
- preamble | ||
A list of commands to perform before any command in the test. | ||
These commands can contain unexpanded substitutions, but they | ||
must not be of the form 'RUN:' -- they must be proper commands | ||
once substituted. | ||
""" | ||
# Get the default substitutions | ||
tmpDir, tmpBase = lit.TestRunner.getTempPaths(test) | ||
substitutions = lit.TestRunner.getDefaultSubstitutions(test, tmpDir, tmpBase) | ||
|
||
# Parse the test file, including custom directives | ||
scriptInTest = lit.TestRunner.parseIntegratedTestScript(test, require_script=not preamble) | ||
if isinstance(scriptInTest, lit.Test.Result): | ||
return scriptInTest | ||
|
||
script = preamble + scriptInTest | ||
return lit.TestRunner.applySubstitutions(script, substitutions, recursion_limit=10) | ||
|
||
class CxxStandardLibraryTest(lit.formats.FileBasedTest): | ||
def getTestsForPath(self, testSuite, pathInSuite, litConfig, localConfig): | ||
SUPPORTED_SUFFIXES = [ | ||
"[.]pass[.]cpp$", | ||
"[.]compile[.]pass[.]cpp$", | ||
"[.]sh[.][^.]+$", | ||
"[.]verify[.]cpp$", | ||
] | ||
|
||
sourcePath = testSuite.getSourcePath(pathInSuite) | ||
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 | ||
|
||
yield lit.Test.Test(testSuite, pathInSuite, localConfig) | ||
|
||
def execute(self, test, litConfig): | ||
supportsVerify = "verify-support" in test.config.available_features | ||
filename = test.path_in_suite[-1] | ||
|
||
if re.search("[.]sh[.][^.]+$", filename): | ||
steps = [] # The steps are already in the script | ||
return self._executeShTest(test, litConfig, steps) | ||
elif filename.endswith(".compile.pass.cpp"): | ||
steps = ["%dbg(COMPILED WITH) %{cxx} %s %{flags} -fsyntax-only"] | ||
return self._executeShTest(test, litConfig, steps) | ||
elif filename.endswith(".verify.cpp"): | ||
if not supportsVerify: | ||
return lit.Test.Result( | ||
lit.Test.UNSUPPORTED, | ||
"Test {} requires support for Clang-verify, which isn't supported by the compiler".format(test.getFullName()), | ||
) | ||
steps = ["%dbg(COMPILED WITH) %{cxx} %s %{flags} -fsyntax-only -Xclang -verify -Xclang -verify-ignore-unexpected=note -ferror-limit=0"] | ||
return self._executeShTest(test, litConfig, steps) | ||
elif filename.endswith(".pass.cpp"): | ||
steps = [ | ||
"%dbg(COMPILED WITH) %{cxx} %s %{flags} -o %t.exe", | ||
"%dbg(EXECUTED AS) %t.exe", | ||
] | ||
return self._executeShTest(test, litConfig, steps) | ||
else: | ||
return lit.Test.Result(lit.Test.UNRESOLVED, "Unknown test suffix for '{}'".format(filename)) | ||
|
||
def _executeShTest(self, test, litConfig, steps): | ||
if test.config.unsupported: | ||
return lit.Test.Result(lit.Test.UNSUPPORTED, "Test is unsupported") | ||
|
||
script = _parseScript(test, steps) | ||
if isinstance(script, lit.Test.Result): | ||
return script | ||
|
||
if litConfig.noExecute: | ||
return lit.Test.Result(lit.Test.XFAIL if test.isExpectedToFail() else lit.Test.PASS) | ||
else: | ||
_, tmpBase = lit.TestRunner.getTempPaths(test) | ||
useExternalSh = False | ||
return lit.TestRunner._runShTest(test, litConfig, useExternalSh, script, tmpBase) |