Skip to content

Commit c305d67

Browse files
committed
Vendor test.h
Signed-off-by: Yuxuan Shui <[email protected]>
1 parent ddde118 commit c305d67

File tree

4 files changed

+160
-4
lines changed

4 files changed

+160
-4
lines changed

.gitmodules

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +0,0 @@
1-
[submodule "subprojects/test.h"]
2-
path = subprojects/test.h
3-
url = https://github.com/yshui/test.h

subprojects/test.h

Lines changed: 0 additions & 1 deletion
This file was deleted.

subprojects/test.h/meson.build

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
project('test.h', 'c')
2+
test_h_dep = declare_dependency(include_directories: include_directories('.'))

subprojects/test.h/test.h

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
// SPDX-License-Identifier: MIT
2+
#pragma once
3+
4+
#ifdef UNIT_TEST
5+
6+
#include <stdbool.h>
7+
#include <stdio.h>
8+
#include <stdlib.h>
9+
#include <string.h>
10+
11+
struct test_file_metadata;
12+
13+
struct test_failure {
14+
bool present;
15+
const char *message;
16+
const char *file;
17+
int line;
18+
};
19+
20+
struct test_case_metadata {
21+
void (*fn)(struct test_case_metadata *, struct test_file_metadata *);
22+
struct test_failure failure;
23+
const char *name;
24+
struct test_case_metadata *next;
25+
};
26+
27+
struct test_file_metadata {
28+
bool registered;
29+
const char *name;
30+
struct test_file_metadata *next;
31+
struct test_case_metadata *tests;
32+
};
33+
34+
struct test_file_metadata __attribute__((weak)) * test_file_head;
35+
36+
#define SET_FAILURE(_message) \
37+
metadata->failure = (struct test_failure) { \
38+
.message = _message, .file = __FILE__, .line = __LINE__, \
39+
.present = true, \
40+
}
41+
42+
#define TEST_EQUAL(a, b) \
43+
do { \
44+
if ((a) != (b)) { \
45+
SET_FAILURE(#a " != " #b); \
46+
return; \
47+
} \
48+
} while (0)
49+
50+
#define TEST_TRUE(a) \
51+
do { \
52+
if (!(a)) { \
53+
SET_FAILURE(#a " is not true"); \
54+
return; \
55+
} \
56+
} while (0)
57+
58+
#define TEST_STREQUAL(a, b) \
59+
do { \
60+
if (strcmp(a, b) != 0) { \
61+
SET_FAILURE(#a " != " #b); \
62+
return; \
63+
} \
64+
} while (0)
65+
66+
#define TEST_CASE(_name) \
67+
static void __test_h_##_name(struct test_case_metadata *, \
68+
struct test_file_metadata *); \
69+
static struct test_file_metadata __test_h_file; \
70+
static struct test_case_metadata __test_h_meta_##_name = { \
71+
.name = #_name, \
72+
.fn = __test_h_##_name, \
73+
}; \
74+
static void __attribute__((constructor(101))) \
75+
__test_h_##_name##_register(void) { \
76+
__test_h_meta_##_name.next = __test_h_file.tests; \
77+
__test_h_file.tests = &__test_h_meta_##_name; \
78+
if (!__test_h_file.registered) { \
79+
__test_h_file.name = __FILE__; \
80+
__test_h_file.next = test_file_head; \
81+
test_file_head = &__test_h_file; \
82+
__test_h_file.registered = true; \
83+
} \
84+
} \
85+
static void __test_h_##_name( \
86+
struct test_case_metadata *metadata __attribute__((unused)), \
87+
struct test_file_metadata *file_metadata __attribute__((unused)))
88+
89+
extern void __attribute__((weak)) (*test_h_unittest_setup)(void);
90+
/// Run defined tests, return true if all tests succeeds
91+
/// @param[out] tests_run if not NULL, set to whether tests were run
92+
static inline void __attribute__((constructor(102))) run_tests(void) {
93+
bool should_run = false;
94+
FILE *cmdlinef = fopen("/proc/self/cmdline", "r");
95+
char *arg = NULL;
96+
int arglen;
97+
fscanf(cmdlinef, "%ms%n", &arg, &arglen);
98+
fclose(cmdlinef);
99+
for (char *pos = arg; pos < arg + arglen; pos += strlen(pos) + 1) {
100+
if (strcmp(pos, "--unittest") == 0) {
101+
should_run = true;
102+
break;
103+
}
104+
}
105+
free(arg);
106+
107+
if (!should_run) {
108+
return;
109+
}
110+
111+
if (&test_h_unittest_setup) {
112+
test_h_unittest_setup();
113+
}
114+
115+
struct test_file_metadata *i = test_file_head;
116+
int failed = 0, success = 0;
117+
while (i) {
118+
fprintf(stderr, "Running tests from %s:\n", i->name);
119+
struct test_case_metadata *j = i->tests;
120+
while (j) {
121+
fprintf(stderr, "\t%s ... ", j->name);
122+
j->failure.present = false;
123+
j->fn(j, i);
124+
if (j->failure.present) {
125+
fprintf(stderr, "failed (%s at %s:%d)\n",
126+
j->failure.message, j->failure.file,
127+
j->failure.line);
128+
failed++;
129+
} else {
130+
fprintf(stderr, "passed\n");
131+
success++;
132+
}
133+
j = j->next;
134+
}
135+
fprintf(stderr, "\n");
136+
i = i->next;
137+
}
138+
int total = failed + success;
139+
fprintf(stderr, "Test results: passed %d/%d, failed %d/%d\n", success, total,
140+
failed, total);
141+
exit(failed == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
142+
}
143+
144+
#else
145+
146+
#include <stdbool.h>
147+
148+
#define TEST_CASE(name) static void __attribute__((unused)) __test_h_##name(void)
149+
150+
#define TEST_EQUAL(a, b) \
151+
(void)(a); \
152+
(void)(b)
153+
#define TEST_TRUE(a) (void)(a)
154+
#define TEST_STREQUAL(a, b) \
155+
(void)(a); \
156+
(void)(b)
157+
158+
#endif

0 commit comments

Comments
 (0)