xref: /libevent-2.1.12/test/tinytest_demo.c (revision 6ea1ec68)
1 /* tinytest_demo.c -- Copyright 2009-2012 Nick Mathewson
2  *
3  * Redistribution and use in source and binary forms, with or without
4  * modification, are permitted provided that the following conditions
5  * are met:
6  * 1. Redistributions of source code must retain the above copyright
7  *    notice, this list of conditions and the following disclaimer.
8  * 2. Redistributions in binary form must reproduce the above copyright
9  *    notice, this list of conditions and the following disclaimer in the
10  *    documentation and/or other materials provided with the distribution.
11  * 3. The name of the author may not be used to endorse or promote products
12  *    derived from this software without specific prior written permission.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25 
26 
27 /* Welcome to the example file for tinytest!  I'll show you how to set up
28  * some simple and not-so-simple testcases. */
29 
30 /* Make sure you include these headers. */
31 #include "tinytest.h"
32 #include "tinytest_macros.h"
33 
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <errno.h>
38 #include <time.h>
39 #ifdef _WIN32
40 #include <windows.h>
41 #else
42 #include <unistd.h>
43 #endif
44 
45 /* ============================================================ */
46 
47 /* First, let's see if strcmp is working.  (All your test cases should be
48  * functions declared to take a single void * as an argument.) */
49 void
test_strcmp(void * data)50 test_strcmp(void *data)
51 {
52 	(void)data; /* This testcase takes no data. */
53 
54 	/* Let's make sure the empty string is equal to itself */
55 	if (strcmp("","")) {
56 		/* This macro tells tinytest to stop the current test
57 		 * and go straight to the "end" label. */
58 		tt_abort_msg("The empty string was not equal to itself");
59 	}
60 
61 	/* Pretty often, calling tt_abort_msg to indicate failure is more
62 	   heavy-weight than you want.	Instead, just say: */
63 	tt_assert(strcmp("testcase", "testcase") == 0);
64 
65 	/* Occasionally, you don't want to stop the current testcase just
66 	   because a single assertion has failed.  In that case, use
67 	   tt_want: */
68 	tt_want(strcmp("tinytest", "testcase") > 0);
69 
70 	/* You can use the tt_*_op family of macros to compare values and to
71 	   fail unless they have the relationship you want.  They produce
72 	   more useful output than tt_assert, since they display the actual
73 	   values of the failing things.
74 
75 	   Fail unless strcmp("abc, "abc") == 0 */
76 	tt_int_op(strcmp("abc", "abc"), ==, 0);
77 
78 	/* Fail unless strcmp("abc, "abcd") is less than 0 */
79 	tt_int_op(strcmp("abc", "abcd"), < , 0);
80 
81 	/* Incidentally, there's a test_str_op that uses strcmp internally. */
82 	tt_str_op("abc", <, "abcd");
83 
84 
85 	/* Every test-case function needs to finish with an "end:"
86 	   label and (optionally) code to clean up local variables. */
87  end:
88 	;
89 }
90 
91 /* ============================================================ */
92 
93 /* Now let's mess with setup and teardown functions!  These are handy if
94    you have a bunch of tests that all need a similar environment, and you
95    want to reconstruct that environment freshly for each one. */
96 
97 /* First you declare a type to hold the environment info, and functions to
98    set it up and tear it down. */
99 struct data_buffer {
100 	/* We're just going to have couple of character buffer.	 Using
101 	   setup/teardown functions is probably overkill for this case.
102 
103 	   You could also do file descriptors, complicated handles, temporary
104 	   files, etc. */
105 	char buffer1[512];
106 	char buffer2[512];
107 };
108 /* The setup function needs to take a const struct testcase_t and return
109    void* */
110 void *
setup_data_buffer(const struct testcase_t * testcase)111 setup_data_buffer(const struct testcase_t *testcase)
112 {
113 	struct data_buffer *db = malloc(sizeof(struct data_buffer));
114 
115 	/* If you had a complicated set of setup rules, you might behave
116 	   differently here depending on testcase->flags or
117 	   testcase->setup_data or even or testcase->name. */
118 
119 	/* Returning a NULL here would mean that we couldn't set up for this
120 	   test, so we don't need to test db for null. */
121 	return db;
122 }
123 /* The clean function deallocates storage carefully and returns true on
124    success. */
125 int
clean_data_buffer(const struct testcase_t * testcase,void * ptr)126 clean_data_buffer(const struct testcase_t *testcase, void *ptr)
127 {
128 	struct data_buffer *db = ptr;
129 
130 	if (db) {
131 		free(db);
132 		return 1;
133 	}
134 	return 0;
135 }
136 /* Finally, declare a testcase_setup_t with these functions. */
137 struct testcase_setup_t data_buffer_setup = {
138 	setup_data_buffer, clean_data_buffer
139 };
140 
141 
142 /* Now let's write our test. */
143 void
test_memcpy(void * ptr)144 test_memcpy(void *ptr)
145 {
146 	/* This time, we use the argument. */
147 	struct data_buffer *db = ptr;
148 
149 	/* We'll also introduce a local variable that might need cleaning up. */
150 	char *mem = NULL;
151 
152 	/* Let's make sure that memcpy does what we'd like. */
153 	strcpy(db->buffer1, "String 0");
154 	memcpy(db->buffer2, db->buffer1, sizeof(db->buffer1));
155 	tt_str_op(db->buffer1, ==, db->buffer2);
156 
157         /* This one works if there's an internal NUL. */
158         tt_mem_op(db->buffer1, <, db->buffer2, sizeof(db->buffer1));
159 
160 	/* Now we've allocated memory that's referenced by a local variable.
161 	   The end block of the function will clean it up. */
162 	mem = strdup("Hello world.");
163 	tt_assert(mem);
164 
165 	/* Another rather trivial test. */
166 	tt_str_op(db->buffer1, !=, mem);
167 
168  end:
169 	/* This time our end block has something to do. */
170 	if (mem)
171 		free(mem);
172 }
173 
174 void
test_timeout(void * ptr)175 test_timeout(void *ptr)
176 {
177 	time_t t1, t2;
178 	(void)ptr;
179 	t1 = time(NULL);
180 #ifdef _WIN32
181 	Sleep(5000);
182 #else
183 	sleep(5);
184 #endif
185 	t2 = time(NULL);
186 
187 	tt_int_op(t2-t1, >=, 4);
188 
189 	tt_int_op(t2-t1, <=, 6);
190 
191  end:
192 	;
193 }
194 
195 void
test_timeout_retry(void * ptr)196 test_timeout_retry(void *ptr)
197 {
198 	static int i = 0;
199 
200 	++i;
201 	tt_int_op(i, !=, 1);
202 
203 	time_t t1, t2;
204 	(void)ptr;
205 	t1 = time(NULL);
206 #ifdef _WIN32
207 	Sleep(5000);
208 #else
209 	sleep(5);
210 #endif
211 	t2 = time(NULL);
212 
213 	tt_int_op(t2-t1, >=, 4);
214 
215 	tt_int_op(t2-t1, <=, 6);
216 
217  end:
218 	;
219 }
220 
221 /* ============================================================ */
222 
223 /* Now we need to make sure that our tests get invoked.	  First, you take
224    a bunch of related tests and put them into an array of struct testcase_t.
225 */
226 
227 struct testcase_t demo_tests[] = {
228 	/* Here's a really simple test: it has a name you can refer to it
229 	   with, and a function to invoke it. */
230 	{ "strcmp", test_strcmp, },
231 
232 	/* The second test has a flag, "TT_FORK", to make it run in a
233 	   subprocess, and a pointer to the testcase_setup_t that configures
234 	   its environment. */
235 	{ "memcpy", test_memcpy, TT_FORK, &data_buffer_setup },
236 
237 	/* This flag is off-by-default, since it takes a while to run.	You
238 	 * can enable it manually by passing +demo/timeout at the command line.*/
239 	{ "timeout", test_timeout, TT_OFF_BY_DEFAULT },
240 
241 	/* This test will be retried. (and it will not pass from the first
242 	 * time) */
243 	{ "timeout_retry", test_timeout_retry, TT_RETRIABLE },
244 
245 	/* The array has to end with END_OF_TESTCASES. */
246 	END_OF_TESTCASES
247 };
248 
249 /* Next, we make an array of testgroups.  This is mandatory.  Unlike more
250    heavy-duty testing frameworks, groups can't nest. */
251 struct testgroup_t groups[] = {
252 
253 	/* Every group has a 'prefix', and an array of tests.  That's it. */
254 	{ "demo/", demo_tests },
255 
256 	END_OF_GROUPS
257 };
258 
259 /* We can also define test aliases. These can be used for types of tests that
260  * cut across groups. */
261 const char *alltests[] = { "+..", NULL };
262 const char *slowtests[] = { "+demo/timeout", NULL };
263 struct testlist_alias_t aliases[] = {
264 
265 	{ "ALL", alltests },
266 	{ "SLOW", slowtests },
267 
268 	END_OF_ALIASES
269 };
270 
271 
272 int
main(int c,const char ** v)273 main(int c, const char **v)
274 {
275 	/* Finally, just call tinytest_main().	It lets you specify verbose
276 	   or quiet output with --verbose and --quiet.	You can list
277 	   specific tests:
278 
279 	       tinytest-demo demo/memcpy
280 
281 	   or use a ..-wildcard to select multiple tests with a common
282 	   prefix:
283 
284 	       tinytest-demo demo/..
285 
286 	   If you list no tests, you get them all by default, so that
287 	   "tinytest-demo" and "tinytest-demo .." mean the same thing.
288 
289 	*/
290 	tinytest_set_aliases(aliases);
291 	return tinytest_main(c, v, groups);
292 }
293