mirror of
https://github.com/yshui/picom.git
synced 2025-02-17 15:56:21 -05:00
Add 'subprojects/test.h/' from commit 'a84877df68873f80ff3620f4993619b35b21f758'
git-subtree-dir: subprojects/test.h git-subtree-mainline:061f9aea9d
git-subtree-split:a84877df68
This commit is contained in:
commit
cfdbd11328
6 changed files with 221 additions and 0 deletions
37
subprojects/test.h/README.md
Normal file
37
subprojects/test.h/README.md
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
test.h
|
||||||
|
======
|
||||||
|
|
||||||
|
A very simple, light weight, header only C unit test framework.
|
||||||
|
|
||||||
|
# Features
|
||||||
|
|
||||||
|
* Easy to use, no dependencies, no setup needed.
|
||||||
|
* Keep test cases close to the code they test.
|
||||||
|
* Automatic registration of the test cases.
|
||||||
|
|
||||||
|
# Usage
|
||||||
|
## Setup
|
||||||
|
|
||||||
|
Just include the header
|
||||||
|
|
||||||
|
```c
|
||||||
|
#include "test.h"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Defining test cases
|
||||||
|
|
||||||
|
```c
|
||||||
|
TEST_CASE(test_case_name) {
|
||||||
|
// Your code here
|
||||||
|
// ...
|
||||||
|
TEST_EQUAL(1, 0); // Fail
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Run the test cases
|
||||||
|
|
||||||
|
Build your program with `-DUNIT_TEST`, then run your program with `./program --unittest`.
|
||||||
|
|
||||||
|
# Hooks
|
||||||
|
|
||||||
|
If you define a function `test_h_unittest_setup`, it will be called before any test cases are run.
|
8
subprojects/test.h/examples/trivial_tests/Makefile
Normal file
8
subprojects/test.h/examples/trivial_tests/Makefile
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
all: normal unittest
|
||||||
|
|
||||||
|
# A normal binary, compiled without unit tests
|
||||||
|
normal: test_test1.c test_test2.c ../../test.h
|
||||||
|
gcc -O test_test1.c test_test2.c -I../../ -o $@
|
||||||
|
# A binary to run unit tests
|
||||||
|
unittest: test_test1.c test_test2.c ../../test.h
|
||||||
|
gcc -g test_test1.c test_test2.c -DUNIT_TEST -I../../ -o $@
|
15
subprojects/test.h/examples/trivial_tests/test_test1.c
Normal file
15
subprojects/test.h/examples/trivial_tests/test_test1.c
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "test.h"
|
||||||
|
|
||||||
|
int main(int argc, char *const *argv) {
|
||||||
|
printf("Hello World!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE(test1) {
|
||||||
|
TEST_EQUAL(1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE(test2) {
|
||||||
|
TEST_TRUE(false);
|
||||||
|
}
|
5
subprojects/test.h/examples/trivial_tests/test_test2.c
Normal file
5
subprojects/test.h/examples/trivial_tests/test_test2.c
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "test.h"
|
||||||
|
|
||||||
|
TEST_CASE(test2) {
|
||||||
|
}
|
2
subprojects/test.h/meson.build
Normal file
2
subprojects/test.h/meson.build
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
project('test.h', 'c')
|
||||||
|
test_h_dep = declare_dependency(include_directories: include_directories('.'))
|
154
subprojects/test.h/test.h
Normal file
154
subprojects/test.h/test.h
Normal file
|
@ -0,0 +1,154 @@
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef UNIT_TEST
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
struct test_file_metadata;
|
||||||
|
|
||||||
|
struct test_failure {
|
||||||
|
bool present;
|
||||||
|
const char *message;
|
||||||
|
const char *file;
|
||||||
|
int line;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct test_case_metadata {
|
||||||
|
void (*fn)(struct test_case_metadata *, struct test_file_metadata *);
|
||||||
|
struct test_failure failure;
|
||||||
|
const char *name;
|
||||||
|
struct test_case_metadata *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct test_file_metadata {
|
||||||
|
bool registered;
|
||||||
|
const char *name;
|
||||||
|
struct test_file_metadata *next;
|
||||||
|
struct test_case_metadata *tests;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct test_file_metadata __attribute__((weak)) * test_file_head;
|
||||||
|
|
||||||
|
#define SET_FAILURE(_message) \
|
||||||
|
metadata->failure = (struct test_failure) { \
|
||||||
|
.message = _message, .file = __FILE__, .line = __LINE__, .present = true, \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define TEST_EQUAL(a, b) \
|
||||||
|
do { \
|
||||||
|
if ((a) != (b)) { \
|
||||||
|
SET_FAILURE(#a " != " #b); \
|
||||||
|
return; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define TEST_TRUE(a) \
|
||||||
|
do { \
|
||||||
|
if (!(a)) { \
|
||||||
|
SET_FAILURE(#a " is not true"); \
|
||||||
|
return; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define TEST_STREQUAL(a, b) \
|
||||||
|
do { \
|
||||||
|
if (strcmp(a, b) != 0) { \
|
||||||
|
SET_FAILURE(#a " != " #b); \
|
||||||
|
return; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define TEST_CASE(_name) \
|
||||||
|
static void __test_h_##_name(struct test_case_metadata *, \
|
||||||
|
struct test_file_metadata *); \
|
||||||
|
static struct test_file_metadata __test_h_file; \
|
||||||
|
static struct test_case_metadata __test_h_meta_##_name = { \
|
||||||
|
.name = #_name, \
|
||||||
|
.fn = __test_h_##_name, \
|
||||||
|
}; \
|
||||||
|
static void __attribute__((constructor(101))) __test_h_##_name##_register(void) { \
|
||||||
|
__test_h_meta_##_name.next = __test_h_file.tests; \
|
||||||
|
__test_h_file.tests = &__test_h_meta_##_name; \
|
||||||
|
if (!__test_h_file.registered) { \
|
||||||
|
__test_h_file.name = __FILE__; \
|
||||||
|
__test_h_file.next = test_file_head; \
|
||||||
|
test_file_head = &__test_h_file; \
|
||||||
|
__test_h_file.registered = true; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
static void __test_h_##_name(struct test_case_metadata *metadata, \
|
||||||
|
struct test_file_metadata *file_metadata)
|
||||||
|
|
||||||
|
extern void __attribute__((weak)) (*test_h_unittest_setup)(void);
|
||||||
|
/// Run defined tests, return true if all tests succeeds
|
||||||
|
/// @param[out] tests_run if not NULL, set to whether tests were run
|
||||||
|
static inline void __attribute__((constructor(102))) run_tests(void) {
|
||||||
|
bool should_run = false;
|
||||||
|
FILE *cmdlinef = fopen("/proc/self/cmdline", "r");
|
||||||
|
char *arg = NULL;
|
||||||
|
int arglen;
|
||||||
|
fscanf(cmdlinef, "%ms%n", &arg, &arglen);
|
||||||
|
fclose(cmdlinef);
|
||||||
|
for (char *pos = arg; pos < arg + arglen; pos += strlen(pos) + 1) {
|
||||||
|
if (strcmp(pos, "--unittest") == 0) {
|
||||||
|
should_run = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(arg);
|
||||||
|
|
||||||
|
if (!should_run) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (&test_h_unittest_setup) {
|
||||||
|
test_h_unittest_setup();
|
||||||
|
}
|
||||||
|
|
||||||
|
struct test_file_metadata *i = test_file_head;
|
||||||
|
int failed = 0, success = 0;
|
||||||
|
while (i) {
|
||||||
|
fprintf(stderr, "Running tests from %s:\n", i->name);
|
||||||
|
struct test_case_metadata *j = i->tests;
|
||||||
|
while (j) {
|
||||||
|
fprintf(stderr, "\t%s ... ", j->name);
|
||||||
|
j->failure.present = false;
|
||||||
|
j->fn(j, i);
|
||||||
|
if (j->failure.present) {
|
||||||
|
fprintf(stderr, "failed (%s at %s:%d)\n", j->failure.message,
|
||||||
|
j->failure.file, j->failure.line);
|
||||||
|
failed++;
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "passed\n");
|
||||||
|
success++;
|
||||||
|
}
|
||||||
|
j = j->next;
|
||||||
|
}
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
i = i->next;
|
||||||
|
}
|
||||||
|
int total = failed + success;
|
||||||
|
fprintf(stderr, "Test results: passed %d/%d, failed %d/%d\n", success, total,
|
||||||
|
failed, total);
|
||||||
|
exit(failed == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#define TEST_CASE(name) static void __attribute__((unused)) __test_h_##name(void)
|
||||||
|
|
||||||
|
#define TEST_EQUAL(a, b) \
|
||||||
|
(void)(a); \
|
||||||
|
(void)(b)
|
||||||
|
#define TEST_TRUE(a) (void)(a)
|
||||||
|
#define TEST_STREQUAL(a, b) \
|
||||||
|
(void)(a); \
|
||||||
|
(void)(b)
|
||||||
|
|
||||||
|
#endif
|
Loading…
Add table
Reference in a new issue