t/unit-tests: update to 10e96bc

Update to 10e96bc (Merge pull request #127 from
pks-gitlab/pks-ci-improvements, 2025-09-22). This commit includes a
couple of changes:

  - The GitHub CI has been updated to include a 32 bit CI job.
    Furthermore, the jobs now compile with "-Werror" and more warnings
    enabled.

  - An issue was addressed where `uintptr_t` is not available on
    NonStop [1].

  - The clar selftests have been restructured so that it is now possible
    to add small test suites more readily. This was done to add tests
    for the above addressed issue, where we now use "%p" to print
    pointers in a platform dependent way.

  - An issue was addressed where the test output had a trailing
    whitespace with certain output formats, which caused whitespace
    issues in the test expectation files.

[1]: <01c101dc2842$38903640$a9b0a2c0$@nexbridge.com>

Reported-by: Randall S. Becker <rsbecker@nexbridge.com>
Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Patrick Steinhardt
2025-09-22 15:16:11 +02:00
committed by Junio C Hamano
parent e7f04f651a
commit 93dbb6b3c5
24 changed files with 320 additions and 236 deletions

View File

@@ -13,30 +13,47 @@ jobs:
platform:
- os: ubuntu-latest
generator: Unix Makefiles
env:
CFLAGS: "-Werror -Wall -Wextra"
- os: ubuntu-latest
generator: Unix Makefiles
env:
CC: "clang"
CFLAGS: "-fsanitize=leak"
CFLAGS: "-Werror -Wall -Wextra -fsanitize=leak"
- os: ubuntu-latest
generator: Unix Makefiles
image: i386/debian:latest
env:
CFLAGS: "-Werror -Wall -Wextra"
- os: macos-latest
generator: Unix Makefiles
env:
CFLAGS: "-Werror -Wall -Wextra"
- os: windows-latest
generator: Visual Studio 17 2022
- os: windows-latest
generator: MSYS Makefiles
env:
CFLAGS: "-Werror -Wall -Wextra"
- os: windows-latest
generator: MinGW Makefiles
env:
CFLAGS: "-Werror -Wall -Wextra"
fail-fast: false
runs-on: ${{ matrix.platform.os }}
container: ${{matrix.platform.image}}
env:
CC: ${{matrix.platform.env.CC}}
CFLAGS: ${{matrix.platform.env.CFLAGS}}
steps:
- name: Prepare 32 bit container image
if: matrix.platform.image == 'i386/debian:latest'
run: apt -q update && apt -q -y install cmake gcc libc6-amd64 lib64stdc++6 make python3
- name: Check out
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Build
shell: bash
run: |

View File

@@ -195,7 +195,7 @@ struct clar_suite {
};
/* From clar_print_*.c */
static void clar_print_init(int test_count, int suite_count, const char *suite_names);
static void clar_print_init(int test_count, int suite_count);
static void clar_print_shutdown(int test_count, int suite_count, int error_count);
static void clar_print_error(int num, const struct clar_report *report, const struct clar_error *error);
static void clar_print_ontest(const char *suite_name, const char *test_name, int test_number, enum cl_test_status failed);
@@ -592,11 +592,7 @@ clar_test_init(int argc, char **argv)
if (argc > 1)
clar_parse_args(argc, argv);
clar_print_init(
(int)_clar_callback_count,
(int)_clar_suite_count,
""
);
clar_print_init((int)_clar_callback_count, (int)_clar_suite_count);
if (!_clar.summary_filename &&
(summary_env = getenv("CLAR_SUMMARY")) != NULL) {
@@ -875,8 +871,7 @@ void clar__assert_equal(
void *p1 = va_arg(args, void *), *p2 = va_arg(args, void *);
is_equal = (p1 == p2);
if (!is_equal)
p_snprintf(buf, sizeof(buf), "0x%"PRIxPTR" != 0x%"PRIxPTR,
(uintptr_t)p1, (uintptr_t)p2);
p_snprintf(buf, sizeof(buf), "%p != %p", p1, p2);
}
else {
int i1 = va_arg(args, int), i2 = va_arg(args, int);

View File

@@ -1,13 +1,13 @@
/* clap: clar protocol, the traditional clar output format */
static void clar_print_clap_init(int test_count, int suite_count, const char *suite_names)
static void clar_print_clap_init(int test_count, int suite_count)
{
(void)test_count;
if (_clar.verbosity < 0)
return;
printf("Loaded %d suites: %s\n", (int)suite_count, suite_names);
printf("Loaded %d suites:\n", (int)suite_count);
printf("Started (test status codes: OK='.' FAILURE='F' SKIPPED='S')\n");
}
@@ -103,11 +103,10 @@ static void clar_print_clap_onabort(const char *fmt, va_list arg)
/* tap: test anywhere protocol format */
static void clar_print_tap_init(int test_count, int suite_count, const char *suite_names)
static void clar_print_tap_init(int test_count, int suite_count)
{
(void)test_count;
(void)suite_count;
(void)suite_names;
printf("TAP version 13\n");
}
@@ -207,9 +206,9 @@ static void clar_print_tap_onabort(const char *fmt, va_list arg)
} \
} while (0)
static void clar_print_init(int test_count, int suite_count, const char *suite_names)
static void clar_print_init(int test_count, int suite_count)
{
PRINT(init, test_count, suite_count, suite_names);
PRINT(init, test_count, suite_count);
}
static void clar_print_shutdown(int test_count, int suite_count, int error_count)

View File

@@ -158,17 +158,24 @@ class TestSuite(object):
def find_modules(self):
modules = []
for root, _, files in os.walk(self.path):
module_root = root[len(self.path):]
module_root = [c for c in module_root.split(os.sep) if c]
tests_in_module = fnmatch.filter(files, "*.c")
if os.path.isfile(self.path):
full_path = os.path.abspath(self.path)
module_name = os.path.basename(self.path)
module_name = os.path.splitext(module_name)[0]
modules.append((full_path, module_name))
else:
for root, _, files in os.walk(self.path):
module_root = root[len(self.path):]
module_root = [c for c in module_root.split(os.sep) if c]
for test_file in tests_in_module:
full_path = os.path.join(root, test_file)
module_name = "_".join(module_root + [test_file[:-2]]).replace("-", "_")
tests_in_module = fnmatch.filter(files, "*.c")
modules.append((full_path, module_name))
for test_file in tests_in_module:
full_path = os.path.join(root, test_file)
module_name = "_".join(module_root + [test_file[:-2]]).replace("-", "_")
modules.append((full_path, module_name))
return modules
@@ -217,6 +224,7 @@ class TestSuite(object):
def write(self):
output = os.path.join(self.output, 'clar.suite')
os.makedirs(self.output, exist_ok=True)
if not self.should_generate(output):
return False
@@ -258,7 +266,11 @@ if __name__ == '__main__':
sys.exit(1)
path = args.pop() if args else '.'
if os.path.isfile(path) and not options.output:
print("Must provide --output when specifying a file")
sys.exit(1)
output = options.output or path
suite = TestSuite(path, output)
suite.load(options.force)
suite.disable(options.excluded)

View File

@@ -1,5 +1,3 @@
add_subdirectory(selftest_suite)
find_package(Python COMPONENTS Interpreter REQUIRED)
add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/clar.suite"
@@ -40,15 +38,12 @@ target_include_directories(selftest PRIVATE
)
target_link_libraries(selftest clar)
add_test(NAME build_selftest_suite
COMMAND "${CMAKE_COMMAND}" --build "${CMAKE_BINARY_DIR}" --config "$<CONFIG>" --target selftest_suite
)
set_tests_properties(build_selftest_suite PROPERTIES FIXTURES_SETUP clar_test_fixture)
add_test(NAME build_selftest
COMMAND "${CMAKE_COMMAND}" --build "${CMAKE_BINARY_DIR}" --config "$<CONFIG>" --target selftest
)
set_tests_properties(build_selftest PROPERTIES FIXTURES_SETUP clar_test_fixture)
add_test(NAME selftest COMMAND "${CMAKE_CURRENT_BINARY_DIR}/selftest" "$<TARGET_FILE:selftest_suite>")
add_subdirectory(suites)
add_test(NAME selftest COMMAND "${CMAKE_CURRENT_BINARY_DIR}/selftest" $<TARGET_FILE_DIR:combined_suite>)
set_tests_properties(selftest PROPERTIES FIXTURES_REQUIRED clar_test_fixture)

View File

@@ -1,4 +1,4 @@
Usage: selftest [options]
Usage: combined [options]
Options:
-sname Run only the suite with `name` (can go to individual test name)

View File

@@ -1,49 +1,44 @@
1) Failure:
selftest::suite::1 [file:42]
combined::1 [file:42]
Function call failed: -1
2) Failure:
selftest::suite::2 [file:42]
combined::2 [file:42]
Expression is not true: 100 == 101
3) Failure:
selftest::suite::strings [file:42]
combined::strings [file:42]
String mismatch: "mismatched" != actual ("this one fails")
'mismatched' != 'expected' (at byte 0)
4) Failure:
selftest::suite::strings_with_length [file:42]
combined::strings_with_length [file:42]
String mismatch: "exactly" != actual ("this one fails")
'exa' != 'exp' (at byte 2)
5) Failure:
selftest::suite::int [file:42]
combined::int [file:42]
101 != value ("extra note on failing test")
101 != 100
6) Failure:
selftest::suite::int_fmt [file:42]
combined::int_fmt [file:42]
022 != value
0022 != 0144
7) Failure:
selftest::suite::bool [file:42]
combined::bool [file:42]
0 != value
0 != 1
8) Failure:
selftest::suite::ptr [file:42]
Pointer mismatch: p1 != p2
0x1 != 0x2
9) Failure:
selftest::suite::multiline_description [file:42]
combined::multiline_description [file:42]
Function call failed: -1
description line 1
description line 2
10) Failure:
selftest::suite::null_string [file:42]
9) Failure:
combined::null_string [file:42]
String mismatch: "expected" != actual ("this one fails")
'expected' != NULL

View File

@@ -1,9 +1,9 @@
Loaded 1 suites:
Loaded 1 suites:
Started (test status codes: OK='.' FAILURE='F' SKIPPED='S')
F
1) Failure:
selftest::suite::bool [file:42]
combined::bool [file:42]
0 != value
0 != 1

View File

@@ -1,8 +1,8 @@
Loaded 1 suites:
Loaded 1 suites:
Started (test status codes: OK='.' FAILURE='F' SKIPPED='S')
F
1) Failure:
selftest::suite::1 [file:42]
combined::1 [file:42]
Function call failed: -1

View File

@@ -1,2 +1,2 @@
Test suites (use -s<name> to run just one):
0: selftest::suite
0: combined

View File

@@ -27,10 +27,6 @@
<testcase name="bool" classname="selftest" time="0.00">
<failure type="assert"><![CDATA[0 != value
0 != 1]]></failure>
</testcase>
<testcase name="ptr" classname="selftest" time="0.00">
<failure type="assert"><![CDATA[Pointer mismatch: p1 != p2
0x1 != 0x2]]></failure>
</testcase>
<testcase name="multiline_description" classname="selftest" time="0.00">
<failure type="assert"><![CDATA[Function call failed: 1

View File

@@ -1,53 +1,48 @@
Loaded 1 suites:
Loaded 1 suites:
Started (test status codes: OK='.' FAILURE='F' SKIPPED='S')
FFFFFFFFFF
FFFFFFFFF
1) Failure:
selftest::suite::1 [file:42]
combined::1 [file:42]
Function call failed: -1
2) Failure:
selftest::suite::2 [file:42]
combined::2 [file:42]
Expression is not true: 100 == 101
3) Failure:
selftest::suite::strings [file:42]
combined::strings [file:42]
String mismatch: "mismatched" != actual ("this one fails")
'mismatched' != 'expected' (at byte 0)
4) Failure:
selftest::suite::strings_with_length [file:42]
combined::strings_with_length [file:42]
String mismatch: "exactly" != actual ("this one fails")
'exa' != 'exp' (at byte 2)
5) Failure:
selftest::suite::int [file:42]
combined::int [file:42]
101 != value ("extra note on failing test")
101 != 100
6) Failure:
selftest::suite::int_fmt [file:42]
combined::int_fmt [file:42]
022 != value
0022 != 0144
7) Failure:
selftest::suite::bool [file:42]
combined::bool [file:42]
0 != value
0 != 1
8) Failure:
selftest::suite::ptr [file:42]
Pointer mismatch: p1 != p2
0x1 != 0x2
9) Failure:
selftest::suite::multiline_description [file:42]
combined::multiline_description [file:42]
Function call failed: -1
description line 1
description line 2
10) Failure:
selftest::suite::null_string [file:42]
9) Failure:
combined::null_string [file:42]
String mismatch: "expected" != actual ("this one fails")
'expected' != NULL

View File

@@ -1,53 +1,48 @@
Loaded 1 suites:
Loaded 1 suites:
Started (test status codes: OK='.' FAILURE='F' SKIPPED='S')
FFFFFFFFFF
FFFFFFFFF
1) Failure:
selftest::suite::1 [file:42]
combined::1 [file:42]
Function call failed: -1
2) Failure:
selftest::suite::2 [file:42]
combined::2 [file:42]
Expression is not true: 100 == 101
3) Failure:
selftest::suite::strings [file:42]
combined::strings [file:42]
String mismatch: "mismatched" != actual ("this one fails")
'mismatched' != 'expected' (at byte 0)
4) Failure:
selftest::suite::strings_with_length [file:42]
combined::strings_with_length [file:42]
String mismatch: "exactly" != actual ("this one fails")
'exa' != 'exp' (at byte 2)
5) Failure:
selftest::suite::int [file:42]
combined::int [file:42]
101 != value ("extra note on failing test")
101 != 100
6) Failure:
selftest::suite::int_fmt [file:42]
combined::int_fmt [file:42]
022 != value
0022 != 0144
7) Failure:
selftest::suite::bool [file:42]
combined::bool [file:42]
0 != value
0 != 1
8) Failure:
selftest::suite::ptr [file:42]
Pointer mismatch: p1 != p2
0x1 != 0x2
9) Failure:
selftest::suite::multiline_description [file:42]
combined::multiline_description [file:42]
Function call failed: -1
description line 1
description line 2
10) Failure:
selftest::suite::null_string [file:42]
9) Failure:
combined::null_string [file:42]
String mismatch: "expected" != actual ("this one fails")
'expected' != NULL

View File

@@ -1,6 +1,6 @@
TAP version 13
# start of suite 1: selftest::suite
not ok 1 - selftest::suite::1
# start of suite 1: combined
not ok 1 - combined::1
---
reason: |
Function call failed: -1
@@ -9,7 +9,7 @@ not ok 1 - selftest::suite::1
line: 42
function: 'func'
---
not ok 2 - selftest::suite::2
not ok 2 - combined::2
---
reason: |
Expression is not true: 100 == 101
@@ -18,7 +18,7 @@ not ok 2 - selftest::suite::2
line: 42
function: 'func'
---
not ok 3 - selftest::suite::strings
not ok 3 - combined::strings
---
reason: |
String mismatch: "mismatched" != actual ("this one fails")
@@ -28,7 +28,7 @@ not ok 3 - selftest::suite::strings
line: 42
function: 'func'
---
not ok 4 - selftest::suite::strings_with_length
not ok 4 - combined::strings_with_length
---
reason: |
String mismatch: "exactly" != actual ("this one fails")
@@ -38,7 +38,7 @@ not ok 4 - selftest::suite::strings_with_length
line: 42
function: 'func'
---
not ok 5 - selftest::suite::int
not ok 5 - combined::int
---
reason: |
101 != value ("extra note on failing test")
@@ -48,7 +48,7 @@ not ok 5 - selftest::suite::int
line: 42
function: 'func'
---
not ok 6 - selftest::suite::int_fmt
not ok 6 - combined::int_fmt
---
reason: |
022 != value
@@ -58,7 +58,7 @@ not ok 6 - selftest::suite::int_fmt
line: 42
function: 'func'
---
not ok 7 - selftest::suite::bool
not ok 7 - combined::bool
---
reason: |
0 != value
@@ -68,17 +68,7 @@ not ok 7 - selftest::suite::bool
line: 42
function: 'func'
---
not ok 8 - selftest::suite::ptr
---
reason: |
Pointer mismatch: p1 != p2
0x1 != 0x2
at:
file: 'file'
line: 42
function: 'func'
---
not ok 9 - selftest::suite::multiline_description
not ok 8 - combined::multiline_description
---
reason: |
Function call failed: -1
@@ -89,7 +79,7 @@ not ok 9 - selftest::suite::multiline_description
line: 42
function: 'func'
---
not ok 10 - selftest::suite::null_string
not ok 9 - combined::null_string
---
reason: |
String mismatch: "expected" != actual ("this one fails")
@@ -99,4 +89,4 @@ not ok 10 - selftest::suite::null_string
line: 42
function: 'func'
---
1..10
1..9

View File

@@ -1,53 +1,48 @@
Loaded 1 suites:
Loaded 1 suites:
Started (test status codes: OK='.' FAILURE='F' SKIPPED='S')
FFFFFFFFFF
FFFFFFFFF
1) Failure:
selftest::suite::1 [file:42]
combined::1 [file:42]
Function call failed: -1
2) Failure:
selftest::suite::2 [file:42]
combined::2 [file:42]
Expression is not true: 100 == 101
3) Failure:
selftest::suite::strings [file:42]
combined::strings [file:42]
String mismatch: "mismatched" != actual ("this one fails")
'mismatched' != 'expected' (at byte 0)
4) Failure:
selftest::suite::strings_with_length [file:42]
combined::strings_with_length [file:42]
String mismatch: "exactly" != actual ("this one fails")
'exa' != 'exp' (at byte 2)
5) Failure:
selftest::suite::int [file:42]
combined::int [file:42]
101 != value ("extra note on failing test")
101 != 100
6) Failure:
selftest::suite::int_fmt [file:42]
combined::int_fmt [file:42]
022 != value
0022 != 0144
7) Failure:
selftest::suite::bool [file:42]
combined::bool [file:42]
0 != value
0 != 1
8) Failure:
selftest::suite::ptr [file:42]
Pointer mismatch: p1 != p2
0x1 != 0x2
9) Failure:
selftest::suite::multiline_description [file:42]
combined::multiline_description [file:42]
Function call failed: -1
description line 1
description line 2
10) Failure:
selftest::suite::null_string [file:42]
9) Failure:
combined::null_string [file:42]
String mismatch: "expected" != actual ("this one fails")
'expected' != NULL

View File

@@ -3,7 +3,7 @@
#include "selftest.h"
const char *selftest_binary_path;
const char *selftest_suite_directory;
#ifdef _WIN32
int __cdecl main(int argc, char *argv[])
@@ -12,12 +12,12 @@ int main(int argc, char *argv[])
#endif
{
if (argc < 2) {
fprintf(stderr, "usage: %s <selftest-suite-executable> <options>\n",
fprintf(stderr, "usage: %s <selftest-suite-directory> <options>\n",
argv[0]);
exit(1);
}
selftest_binary_path = argv[1];
selftest_suite_directory = argv[1];
memmove(argv + 1, argv + 2, argc - 1);
argc -= 1;

View File

@@ -59,38 +59,34 @@ static char *read_file(const char *path)
return content;
}
static void run(const char *expected_output_file, int expected_error_code, ...)
static char *execute(const char *suite, int expected_error_code, const char **args, size_t nargs)
{
SECURITY_ATTRIBUTES security_attributes = { 0 };
PROCESS_INFORMATION process_info = { 0 };
STARTUPINFO startup_info = { 0 };
char binary_path[4096] = { 0 };
char cmdline[4096] = { 0 };
char *expected_output = NULL;
char *output = NULL;
HANDLE stdout_write;
HANDLE stdout_read;
DWORD exit_code;
va_list ap;
size_t i;
snprintf(binary_path, sizeof(binary_path), "%s/%s_suite.exe",
selftest_suite_directory, suite);
/*
* Assemble command line arguments. In theory we'd have to properly
* quote them. In practice none of our tests actually care.
*/
va_start(ap, expected_error_code);
snprintf(cmdline, sizeof(cmdline), "selftest");
while (1) {
snprintf(cmdline, sizeof(cmdline), suite);
for (i = 0; i < nargs; i++) {
size_t cmdline_len = strlen(cmdline);
const char *arg;
arg = va_arg(ap, const char *);
if (!arg)
break;
const char *arg = args[i];
cl_assert(cmdline_len + strlen(arg) < sizeof(cmdline));
snprintf(cmdline + cmdline_len, sizeof(cmdline) - cmdline_len,
" %s", arg);
}
va_end(ap);
/*
* Create a pipe that we will use to read data from the child process.
@@ -110,17 +106,39 @@ static void run(const char *expected_output_file, int expected_error_code, ...)
startup_info.hStdError = stdout_write;
startup_info.hStdOutput = stdout_write;
startup_info.dwFlags |= STARTF_USESTDHANDLES;
cl_assert_equal_b(1, CreateProcess(selftest_binary_path, cmdline, NULL, NULL, TRUE,
cl_assert_equal_b(1, CreateProcess(binary_path, cmdline, NULL, NULL, TRUE,
0, NULL, NULL, &startup_info, &process_info));
cl_assert_equal_b(1, CloseHandle(stdout_write));
output = read_full(stdout_read, 1);
cl_assert_equal_b(1, CloseHandle(stdout_read));
cl_assert_equal_b(1, GetExitCodeProcess(process_info.hProcess, &exit_code));
cl_assert_equal_i(exit_code, expected_error_code);
return output;
}
static void assert_output(const char *suite, const char *expected_output_file, int expected_error_code, ...)
{
char *expected_output = NULL;
char *output = NULL;
const char *args[16];
va_list ap;
size_t i;
va_start(ap, expected_error_code);
for (i = 0; ; i++) {
const char *arg = va_arg(ap, const char *);
if (!arg)
break;
cl_assert(i < sizeof(args) / sizeof(*args));
args[i] = arg;
}
va_end(ap);
output = execute(suite, expected_error_code, args, i);
expected_output = read_file(cl_fixture(expected_output_file));
cl_assert_equal_s(output, expected_output);
cl_assert_equal_i(exit_code, expected_error_code);
free(expected_output);
free(output);
@@ -180,29 +198,25 @@ static char *read_file(const char *path)
return data;
}
static void run(const char *expected_output_file, int expected_error_code, ...)
static char *execute(const char *suite, int expected_error_code, const char **args, size_t nargs)
{
const char *argv[16];
int pipe_fds[2];
va_list ap;
pid_t pid;
int i;
va_start(ap, expected_error_code);
argv[0] = "selftest";
for (i = 1; ; i++) {
cl_assert(i < sizeof(argv) / sizeof(*argv));
argv[i] = va_arg(ap, const char *);
if (!argv[i])
break;
}
va_end(ap);
cl_must_pass(pipe(pipe_fds));
pid = fork();
if (!pid) {
const char *final_args[17] = { NULL };
char binary_path[4096];
size_t len = 0;
size_t i;
cl_assert(nargs < sizeof(final_args) / sizeof(*final_args));
final_args[0] = suite;
for (i = 0; i < nargs; i++)
final_args[i + 1] = args[i];
if (dup2(pipe_fds[1], STDOUT_FILENO) < 0 ||
dup2(pipe_fds[1], STDERR_FILENO) < 0 ||
close(0) < 0 ||
@@ -210,11 +224,29 @@ static void run(const char *expected_output_file, int expected_error_code, ...)
close(pipe_fds[1]) < 0)
exit(1);
execv(selftest_binary_path, (char **) argv);
cl_assert(len + strlen(selftest_suite_directory) < sizeof(binary_path));
strcpy(binary_path, selftest_suite_directory);
len += strlen(selftest_suite_directory);
cl_assert(len + 1 < sizeof(binary_path));
binary_path[len] = '/';
len += 1;
cl_assert(len + strlen(suite) < sizeof(binary_path));
strcpy(binary_path + len, suite);
len += strlen(suite);
cl_assert(len + strlen("_suite") < sizeof(binary_path));
strcpy(binary_path + len, "_suite");
len += strlen("_suite");
binary_path[len] = '\0';
execv(binary_path, (char **) final_args);
exit(1);
} else if (pid > 0) {
pid_t waited_pid;
char *expected_output, *output;
char *output;
int stat;
cl_must_pass(close(pipe_fds[1]));
@@ -226,56 +258,78 @@ static void run(const char *expected_output_file, int expected_error_code, ...)
cl_assert(WIFEXITED(stat));
cl_assert_equal_i(WEXITSTATUS(stat), expected_error_code);
expected_output = read_file(cl_fixture(expected_output_file));
cl_assert_equal_s(output, expected_output);
free(expected_output);
free(output);
return output;
} else {
cl_fail("Fork failed.");
}
return NULL;
}
static void assert_output(const char *suite, const char *expected_output_file, int expected_error_code, ...)
{
char *expected_output, *output;
const char *args[16];
va_list ap;
size_t i;
va_start(ap, expected_error_code);
for (i = 0; ; i++) {
cl_assert(i < sizeof(args) / sizeof(*args));
args[i] = va_arg(ap, const char *);
if (!args[i])
break;
}
va_end(ap);
output = execute(suite, expected_error_code, args, i);
expected_output = read_file(cl_fixture(expected_output_file));
cl_assert_equal_s(output, expected_output);
free(expected_output);
free(output);
}
#endif
void test_selftest__help(void)
{
cl_invoke(run("help", 1, "-h", NULL));
cl_invoke(assert_output("combined", "help", 1, "-h", NULL));
}
void test_selftest__without_arguments(void)
{
cl_invoke(run("without_arguments", 10, NULL));
cl_invoke(assert_output("combined", "without_arguments", 9, NULL));
}
void test_selftest__specific_test(void)
{
cl_invoke(run("specific_test", 1, "-sselftest::suite::bool", NULL));
cl_invoke(assert_output("combined", "specific_test", 1, "-scombined::bool", NULL));
}
void test_selftest__stop_on_failure(void)
{
cl_invoke(run("stop_on_failure", 1, "-Q", NULL));
cl_invoke(assert_output("combined", "stop_on_failure", 1, "-Q", NULL));
}
void test_selftest__quiet(void)
{
cl_invoke(run("quiet", 10, "-q", NULL));
cl_invoke(assert_output("combined", "quiet", 9, "-q", NULL));
}
void test_selftest__tap(void)
{
cl_invoke(run("tap", 10, "-t", NULL));
cl_invoke(assert_output("combined", "tap", 9, "-t", NULL));
}
void test_selftest__suite_names(void)
{
cl_invoke(run("suite_names", 0, "-l", NULL));
cl_invoke(assert_output("combined", "suite_names", 0, "-l", NULL));
}
void test_selftest__summary_without_filename(void)
{
struct stat st;
cl_invoke(run("summary_without_filename", 10, "-r", NULL));
cl_invoke(assert_output("combined", "summary_without_filename", 9, "-r", NULL));
/* The summary contains timestamps, so we cannot verify its contents. */
cl_must_pass(stat("summary.xml", &st));
}
@@ -283,7 +337,34 @@ void test_selftest__summary_without_filename(void)
void test_selftest__summary_with_filename(void)
{
struct stat st;
cl_invoke(run("summary_with_filename", 10, "-rdifferent.xml", NULL));
cl_invoke(assert_output("combined", "summary_with_filename", 9, "-rdifferent.xml", NULL));
/* The summary contains timestamps, so we cannot verify its contents. */
cl_must_pass(stat("different.xml", &st));
}
void test_selftest__pointer_equal(void)
{
const char *args[] = {
"-spointer::equal",
"-t"
};
char *output = execute("pointer", 0, args, 2);
cl_assert_equal_s(output,
"TAP version 13\n"
"# start of suite 1: pointer\n"
"ok 1 - pointer::equal\n"
"1..1\n"
);
free(output);
}
void test_selftest__pointer_unequal(void)
{
const char *args[] = {
"-spointer::unequal",
};
char *output = execute("pointer", 1, args, 1);
cl_assert(output);
cl_assert(strstr(output, "Pointer mismatch: "));
free(output);
}

View File

@@ -1,3 +1,3 @@
#include "clar.h"
extern const char *selftest_binary_path;
extern const char *selftest_suite_directory;

View File

@@ -1,40 +0,0 @@
find_package(Python COMPONENTS Interpreter REQUIRED)
add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/clar.suite"
COMMAND "${Python_EXECUTABLE}" "${CMAKE_SOURCE_DIR}/generate.py" --output "${CMAKE_CURRENT_BINARY_DIR}"
DEPENDS main.c selftest_suite.c
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
)
add_executable(selftest_suite)
set_target_properties(selftest_suite PROPERTIES
C_STANDARD 90
C_STANDARD_REQUIRED ON
C_EXTENSIONS OFF
)
# MSVC generates all kinds of warnings. We may want to fix these in the future
# and then unconditionally treat warnings as errors.
if(NOT MSVC)
set_target_properties(selftest_suite PROPERTIES
COMPILE_WARNING_AS_ERROR ON
)
endif()
target_sources(selftest_suite PRIVATE
main.c
selftest_suite.c
"${CMAKE_CURRENT_BINARY_DIR}/clar.suite"
)
target_compile_definitions(selftest_suite PRIVATE
CLAR_FIXTURE_PATH="${CMAKE_CURRENT_SOURCE_DIR}/resources/"
CLAR_SELFTEST
)
target_compile_options(selftest_suite PRIVATE
$<IF:$<CXX_COMPILER_ID:MSVC>,/W4,-Wall>
)
target_include_directories(selftest_suite PRIVATE
"${CMAKE_SOURCE_DIR}"
"${CMAKE_CURRENT_BINARY_DIR}"
)
target_link_libraries(selftest_suite clar)

View File

@@ -0,0 +1,53 @@
list(APPEND suites
"combined"
"pointer"
)
foreach(suite IN LISTS suites)
add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${suite}/clar.suite"
COMMAND "${Python_EXECUTABLE}"
"${CMAKE_SOURCE_DIR}/generate.py"
"${CMAKE_CURRENT_SOURCE_DIR}/${suite}.c"
--output "${CMAKE_CURRENT_BINARY_DIR}/${suite}"
DEPENDS ${suite}.c
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
)
add_executable(${suite}_suite)
set_target_properties(${suite}_suite PROPERTIES
C_STANDARD 90
C_STANDARD_REQUIRED ON
C_EXTENSIONS OFF
)
# MSVC generates all kinds of warnings. We may want to fix these in the future
# and then unconditionally treat warnings as errors.
if(NOT MSVC)
set_target_properties(${suite}_suite PROPERTIES
COMPILE_WARNING_AS_ERROR ON
)
endif()
target_sources(${suite}_suite PRIVATE
main.c
${suite}.c
"${CMAKE_CURRENT_BINARY_DIR}/${suite}/clar.suite"
)
target_compile_definitions(${suite}_suite PRIVATE
CLAR_FIXTURE_PATH="${CMAKE_CURRENT_SOURCE_DIR}/resources/"
CLAR_SELFTEST
)
target_compile_options(${suite}_suite PRIVATE
$<IF:$<CXX_COMPILER_ID:MSVC>,/W4,-Wall>
)
target_include_directories(${suite}_suite PRIVATE
"${CMAKE_SOURCE_DIR}"
"${CMAKE_CURRENT_BINARY_DIR}/${suite}"
)
target_link_libraries(${suite}_suite clar)
add_test(NAME build_${suite}_suite
COMMAND "${CMAKE_COMMAND}" --build "${CMAKE_BINARY_DIR}" --config "$<CONFIG>" --target selftest
)
set_tests_properties(build_${suite}_suite PROPERTIES FIXTURES_SETUP clar_test_fixture)
endforeach()

View File

@@ -11,14 +11,14 @@ static int file_size(const char *filename)
return -1;
}
void test_selftest_suite__cleanup(void)
void test_combined__cleanup(void)
{
cl_fixture_cleanup("test");
cl_assert(file_size("test/file") == -1);
}
void test_selftest_suite__1(void)
void test_combined__1(void)
{
cl_assert(1);
cl_must_pass(0); /* 0 == success */
@@ -26,7 +26,7 @@ void test_selftest_suite__1(void)
cl_must_pass(-1); /* demonstrate a failing call */
}
void test_selftest_suite__2(void)
void test_combined__2(void)
{
cl_fixture_sandbox("test");
@@ -35,7 +35,7 @@ void test_selftest_suite__2(void)
cl_assert(100 == 101);
}
void test_selftest_suite__strings(void)
void test_combined__strings(void)
{
const char *actual = "expected";
cl_assert_equal_s("expected", actual);
@@ -43,7 +43,7 @@ void test_selftest_suite__strings(void)
cl_assert_equal_s_("mismatched", actual, "this one fails");
}
void test_selftest_suite__strings_with_length(void)
void test_combined__strings_with_length(void)
{
const char *actual = "expected";
cl_assert_equal_strn("expected_", actual, 8);
@@ -52,39 +52,32 @@ void test_selftest_suite__strings_with_length(void)
cl_assert_equal_strn_("exactly", actual, 3, "this one fails");
}
void test_selftest_suite__int(void)
void test_combined__int(void)
{
int value = 100;
cl_assert_equal_i(100, value);
cl_assert_equal_i_(101, value, "extra note on failing test");
}
void test_selftest_suite__int_fmt(void)
void test_combined__int_fmt(void)
{
int value = 100;
cl_assert_equal_i_fmt(022, value, "%04o");
}
void test_selftest_suite__bool(void)
void test_combined__bool(void)
{
int value = 100;
cl_assert_equal_b(1, value); /* test equality as booleans */
cl_assert_equal_b(0, value);
}
void test_selftest_suite__ptr(void)
{
void *p1 = (void *)0x1, *p2 = (void *)0x2;
cl_assert_equal_p(p1, p1); /* pointers to same object */
cl_assert_equal_p(p1, p2);
}
void test_selftest_suite__multiline_description(void)
void test_combined__multiline_description(void)
{
cl_must_pass_(-1, "description line 1\ndescription line 2");
}
void test_selftest_suite__null_string(void)
void test_combined__null_string(void)
{
const char *actual = NULL;
cl_assert_equal_s(actual, actual);

View File

@@ -0,0 +1,13 @@
#include "clar.h"
void test_pointer__equal(void)
{
void *p1 = (void *)0x1;
cl_assert_equal_p(p1, p1);
}
void test_pointer__unequal(void)
{
void *p1 = (void *)0x1, *p2 = (void *)0x2;
cl_assert_equal_p(p1, p2);
}