aboutsummaryrefslogtreecommitdiffstats
path: root/README.md
blob: e6709cfa6034aa3eccb9a8348271fe59e20a8ba2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
simple-test
===========

simple unit testing for C implemented as a single header file

brief summary
-------------

Your tests should be written as a single .c file separate from
the body of text containing your functionality to be tested.
Write the tests, include simple-test.h, point your compiler at
the necessary files / libs, and you're done!

an example
----------

consider the following simple program:

```c
/* keep this include at the very top of the file */
#include "simple-test.h"

/* any global variables, functions, other inclusions, etc.
 * should be declared here */
#include "header_with_stuff_to_be_tested.h"

int add_here(int a, int b)
{
	/* ASSERT / ECHO statements within functions
	 * like this are perfectly valid. this is
	 * useful for writing initialisation functions
	 * called at the beginning of multiple TESTs */
	ECHO("this is the local add");

	/* ensure a and b are non-0 using generic ASSERT */
	ASSERT(a);
	ASSERT(b);

	return a + b;
}

/* must come before all TESTs */
BEGIN_TEST

/* the string is a description of the test being run */
TEST("check add()'s return value")
{
	/* mixing different precisions is allowed */
	long var1 = 2;
	int8_t var2 = 2;

	/* add is a function included from our hypothetical
	 * header_with_stuff_to_be_tested.h */
	ASSERT_INT_EQ(var1+var2, add(var1, var2));

	/* generic versions of ASSERTions are also valid,
	 * but only for number types (int / uint / float ) */
	ASSERT_EQ(var1+var2, add_here(var1, var2));
}

TEST("compare two arrays of strings")
{
	int i;
	char array1[][10] = {
		"str1",
		"str2",
		"str3",
	};
	char array2[][10] = {
		"str1",
		"str2",
		/* matching will fail here */
		"different",
	};

	for(i = 0; i < sizeof(array1) / sizeof(char[10]); i++) {
		/* ECHO can be used to print (with pretty
		 * formatting) the current state within the
		 * test */
		ECHO("checking strs at i == %i", i);

		ASSERT_STR_EQ(array1[i], array2[i]);
	}
}

/* must come after all TESTs */
END_TEST
```

running this test, the output might look something like this:

![run 1](doc/run-01.png)

if var1 in the first test were changed to 0, like so:

```c
	/* mixing different precisions is allowed */
	long var1 = 0;
	int8_t var2 = 2;
```

ASSERT(a); in add_here() would fail like this:

![run 2](doc/run-02.png)

if array2 were modified instead so the third strings would match,
a successful output would look like this:

![run 3](doc/run-03.png)


defined macros
--------------

| **NAME** | **DESCRIPTION** |
|---------:|:----------------|
| **BEGIN_TEST** | must be included once, after includes and global declarations and before the first TEST statement |
| **END_TEST** | must be included once, after the final TEST statement |
| **TEST(<description>)**{} | declare a test, described by `description`, which consists of statements between the {} |
| **ECHO(<...>)** | print a formatted description of the state within the current test |
| **ASSERT<_type_name><_condition>(<args>)** | assert, on either one or two `args` of type `_type_name`, that `_condition` is true |

valid `_type_name` and `_condition` values for ASSERT statements are:

| **_type_name** | **DESCRIPTION** |
|---------------:|:----------------|
|  | if the _type_name is omitted, generic assertions which automatically determine type are used. valid only for number types, i.e. int, unsigned, double. |
| **_BOOL** | operate on args of type `bool` |
| **_INT** | operate on signed integer types |
| **_UINT** | operate on unsigned integer types |
| **_HEX** | operate on unsigned integer types. output with %X formatting |
| **_FLOAT** | operate on floating point types |
| **_PTR** | operate on generic pointer types. casts to void* |
| **_CHAR** | operate on args of type `char` |
| **_STR** | operate on strings pointed to by args of type `char*`. |
| **_WCHAR** | operate on wide character types |
| **_WSTR** | operate on wide strings pointed to by args of type `wchar_t*` |

| **_condition** | **DESCRIPTION** |
|---------------:|:----------------|
|  | if the _condition is omitted, fail if the single arg is a "not" value, i.e. NULL, 0, '\0' etc. |
| **_EQ** | fail if the two args are not equal |
| **_NEQ** | fail if the two args are equal |
| **_G** | fail if the first arg is not greater than the second |
| **_GEQ** | fail if the first arg is not greater than or equal to the second |
| **_L** | fail if the first arg is not less than the second |
| **_LEQ** | fail if the first arg is not less than or equal to the second |

note
----

this makes heavy use of _Generic, so C11 support is required

tested successfully with both gcc and clang