├── .gitignore ├── .travis.yml ├── Makefile ├── README ├── TODO ├── tinytest-manual.md ├── tinytest.c ├── tinytest.h ├── tinytest_demo.c └── tinytest_macros.h /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.o 3 | \#*\# 4 | .\#* 5 | 6 | /tt-demo 7 | /tt-demo.exe 8 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: c 2 | 3 | ## Comment out the compiler list for now to allow an explicit build 4 | ## matrix. 5 | # compiler: 6 | # - gcc 7 | # - clang 8 | 9 | os: 10 | - linux 11 | ## Uncomment the following line to also run the entire build matrix on OSX. 12 | ## This will make your CI builds take roughly ten times longer to finish. 13 | # - osx 14 | 15 | ## Use the Ubuntu Trusty images. 16 | dist: trusty 17 | 18 | ## We don't need sudo. 19 | ## 20 | ## We override this in the explicit build matrix to work around a 21 | ## Travis CI environment regression 22 | ## https://github.com/travis-ci/travis-ci/issues/9033 23 | sudo: false 24 | 25 | 26 | matrix: 27 | ## Create explicit matrix entries to work around a Travis CI 28 | ## environment issue. Missing keys inherit from the first list 29 | ## entry under that key outside the "include" clause. 30 | include: 31 | - compiler: gcc 32 | - compiler: clang 33 | 34 | 35 | script: 36 | - make 37 | - ./tt-demo 38 | 39 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | VERSION=1.0.1 2 | 3 | all: tt-demo 4 | 5 | .c.o: 6 | gcc -Wall -g -O2 -c $< 7 | 8 | tinytest.o: tinytest.h 9 | 10 | tinytest_demo.o: tinytest_macros.h tinytest.h 11 | 12 | OBJS=tinytest.o tinytest_demo.o 13 | 14 | tt-demo: $(OBJS) 15 | gcc -Wall -g -O2 $(OBJS) -o tt-demo 16 | 17 | lines: 18 | wc -l tinytest.c tinytest_macros.h tinytest.h 19 | 20 | clean: 21 | rm -f *.o *~ tt-demo 22 | 23 | DISTFILES=tinytest.c tinytest_demo.c tinytest.h tinytest_macros.h Makefile \ 24 | README 25 | 26 | dist: 27 | rm -rf tinytest-$(VERSION) 28 | mkdir tinytest-$(VERSION) 29 | cp $(DISTFILES) tinytest-$(VERSION) 30 | tar cf - tinytest-$(VERSION) | gzip -c -9 > tinytest-$(VERSION).tar.gz 31 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Tinytest is a tiny little test framework written in C by Nick Mathewson. 2 | 3 | It is distributed under the 3-clause BSD license. You can use it in 4 | your own programs so long as you follow the license's conditions. 5 | 6 | It's been tested on Windows, Mac, and many of the free Unixes. 7 | 8 | It knows how to fork before running certain tests, and it makes 9 | text-mode output in a format I like. 10 | 11 | For info on how to use it, check out tinytest_demo.c. 12 | 13 | You can get the latest version using Git, by pulling from 14 | git://github.com/nmathewson/tinytest.git 15 | 16 | Patches are welcome. Patches that turn this from tinytest to hugetest 17 | will not be applied. If you want a huge test framework, use CUnit. 18 | 19 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | Things to do to tinytest 2 | 3 | o Replace the license with something recognizeable 4 | o Test forking on win32. 5 | o Write minimalist libevent-legacy thing. 6 | o port libevent tests; move libevent test main into a new regress_main 7 | o allow per-group forks. 8 | o See where we're at. 9 | 10 | - Allow groups to nest, perhaps. 11 | - Port Tor to use tinytest 12 | - Warn when running multiple tests with --no-fork 13 | -------------------------------------------------------------------------------- /tinytest-manual.md: -------------------------------------------------------------------------------- 1 | The tinytest unit testing framework 2 | =================================== 3 | 4 | Tinytest is a small set of C files that you can use to write tests for 5 | your C program. It's designed to make writing tests easy and 6 | convenient. It supports the features that I find useful in a unit test 7 | framework--like running tests in subprocesses so that they can't 8 | interfere with global state, or like running or suppressing a subset of 9 | the tests. 10 | 11 | Tinytest is designed to be so small that I don't mind including its 12 | source along with all the C I write. 13 | 14 | Tinytest is *not* designed to be a replacement for heavier-weight 15 | unit-test frameworks like CUnit. It doesn't generate output in XML, 16 | HTML, or JSON. It doesn't include a mocking framework. 17 | 18 | This document describes how to use the basic features of tinytest. It 19 | will not tell you much about how to design unit tests, smoke tests, 20 | integration tests, system tests, or whatever else you might want to use 21 | tinytest for. I'm assuming that you already have some idea of what kind 22 | of test code you want to write, and you just need a minimal framework 23 | that will get out of your way and help you write it. 24 | 25 | Your first test 26 | --------------- 27 | 28 | Here's a simple example to start with. It's a standalone program that 29 | uses tinytest to check whether strdup() behaves correctly. 30 | 31 | 32 | /* You can save this as "demo.c", and then compile it with (eg) 33 | * cc -Wall -g -O2 demo.c tinytest.c -o demo 34 | */ 35 | #include 36 | #include 37 | #include 38 | #include "tinytest.h" 39 | #include "tinytest_macros.h" 40 | 41 | static void test_strdup(void *dummy_arg) 42 | { 43 | const char *str = "Hello world"; 44 | char *str2 = NULL; 45 | 46 | (void) dummy_arg; /* we're not using this argument. */ 47 | 48 | str2 = strdup(str); 49 | 50 | tt_assert(str2); /* Fail if str2 is NULL */ 51 | tt_str_op(str, ==, str2); /* Fail if the strings are not equal */ 52 | 53 | end: 54 | if (str2) 55 | free(str2); 56 | } 57 | 58 | struct testcase_t string_tests[] = { 59 | /* This test is named 'strdup'. It's implemented by the test_strdup 60 | * function, it has no flags, and no setup/teardown code. */ 61 | { "strdup", test_strdup, 0, NULL, NULL }, 62 | END_OF_TESTCASES 63 | }; 64 | 65 | struct testgroup_t test_groups[] = { 66 | /* The tests in 'string_tests' all get prefixed with 'string/' */ 67 | { "string/", string_tests }, 68 | END_OF_GROUPS 69 | }; 70 | 71 | int main(int argc, const char **argv) 72 | { 73 | return tinytest_main(argc, argv, test_groups); 74 | } 75 | 76 | 77 | Once you have compiled the program, you can run it with no arguments 78 | to invoke all its tests: 79 | 80 | $ ./demo 81 | string/strdup: OK 82 | 1 tests ok. (0 skipped) 83 | 84 | You can also control the verbosity of the output: 85 | 86 | $ ./demo --verbose 87 | string/strdup: 88 | OK demo.c:18: assert(str2) 89 | OK demo.c:19: assert(str == str2): vs 90 | 1 tests ok. (0 skipped) 91 | [510]$ ./demo --terse 92 | . 93 | [511]$ ./demo --quiet && echo "OK" || echo "FAIL" 94 | OK 95 | 96 | 97 | Most of the code above is boilerplate. The "main" function just 98 | delegates to tinytest_main(), and passes it an array of testgroup_t 99 | structures. Each test_group_t points to an array of testcase_t 100 | structures -- and each of *those* has (at minimum) a test name, and a 101 | function that implements the test. 102 | 103 | Note that the test function is declared as 'void test_strdup(void *dummy)'. 104 | All test functions must be declared as returning void and taking a 105 | single void pointer as an argument. (More about the use of this 106 | argument later.) 107 | 108 | The body of the test function calls two tinytest check macros: 109 | tt_assert() and tt_str_op(). These functions check whether a given 110 | condition holds: tt_assert(str2) checks that 'str2' is true; and 111 | tt_str_op(str,==,str2) checks that str1 and str2 are equal according to 112 | strcmp(). If one of these conditions doesn't hold, the check macro will 113 | print a useful error message, mark the test as having failed, and go to the 114 | "end:" label to exit the function. 115 | 116 | 117 | Note that the "end:" label is mandatory, and all the cleanup code in the 118 | function goes after the "end:" label. If one of the check macros fails, then 119 | it will invoke "goto end;" after it fails, so that the cleanup code gets 120 | executed before the function returns. 121 | 122 | More tools for writing test functions 123 | ------------------------------------- 124 | 125 | The 'tinytest_macros.h' header declares a bunch of macros to help you write 126 | test functions. 127 | 128 | These macros cause unconditional failure of the current test, and go to the 129 | 'end:' label to exit the function: 130 | 131 | tt_abort(); 132 | tt_abort_printf((format, ...)); 133 | tt_abort_msg(msg); 134 | tt_abort_perror(op); 135 | 136 | They differ in how they report an error. The 'tt_abort()' macro will just 137 | report that the test failed on a given line number; the 'tt_printf()' macro 138 | will use a printf-style function to format its inputs; the 'tt_abort_msg()' 139 | macro prints a string, and the tt_abort_perror() macro will report the 140 | current value of errno along with a string "op" describing what it was that 141 | failed. 142 | 143 | These macros check a boolean condition: 144 | 145 | tt_assert(condition); 146 | tt_assert_msg(condition, msg); 147 | 148 | Each of these macros checks whether a condition is true, and 149 | causes the test to fail if it is not true. On failure, they report the 150 | message (if provided), or the condition that failed. 151 | 152 | These macros perform binary comparisons, and print the values of their 153 | arguments on failure: 154 | 155 | tt_int_op(a, op, b) 156 | tt_uint_op(a, op, b) 157 | tt_ptr_op(a, op, b) 158 | tt_str_op(a, op, b) 159 | tt_mem_op(a, op, b, len) 160 | 161 | In each case, the "op" argument should be one of "==", "<=", "<", "!=", ">", 162 | or ">=". The test succeeds if "a op b" is true, where the rules of the 163 | comparison are determined by the type: tt_int_op performs a comparison after 164 | casting to long; tt_uint_op compares after casting to unsigned long; 165 | and tt_ptr_op checks after casting to void *. The tt_str_op macro uses 166 | strcmp() to compare its arguments, and tt_mem_op uses memcmp() with the given 167 | length value. 168 | 169 | The tt_*_op() macros behave the same as would a corresponding tt_assert() 170 | macro, except that they produce more useful output on failure. A failed call 171 | to "tt_assert(x == 3);" will just say "FAIL: assert(x == 3)". But a failed 172 | call to tt_int_op(x == 3);" will display the actual run-time value for x, 173 | which will often help in debugging failed tests. 174 | 175 | 176 | The following macros behave the same as the above macros, except that they do 177 | not "goto end;" on failure. The tt_fail macros correspond to tt_abort, the 178 | tt_want macros correspond to tt_assert, and the tt_want_*_op macros 179 | correspond to the tt_*_op macros: 180 | 181 | tt_fail(); 182 | tt_fail_printf((format, ...)); 183 | tt_fail_msg(msg); 184 | tt_fail_perror(op); 185 | 186 | tt_want(condition) 187 | tt_want_msg(condition, msg); 188 | 189 | tt_want_int_op(a, op, b) 190 | tt_want_uint_op(a, op, b) 191 | tt_want_ptr_op(a, op, b) 192 | tt_want_str_op(a, op, b) 193 | tt_want_mem_op(a, op, b, len) 194 | 195 | 196 | Tips for correct cleanup blocks 197 | ------------------------------- 198 | 199 | Remember that most of the check macros can transfer execution to your "end:" 200 | label, so there may be more paths through your function than you first 201 | realize. To ensure that your cleanup blocks are correct, I recommend that 202 | you check-and-release every resource that could be allocated by your 203 | function. 204 | 205 | So here's a good pattern: 206 | 207 | { 208 | char *x = NULL; 209 | tt_int_op(some_func(), ==, 0); 210 | 211 | x = malloc(100); 212 | tt_assert(x); 213 | 214 | /* more tests go here... */ 215 | end: 216 | if (x) free(x); 217 | } 218 | 219 | 220 | And here's how not to do it: 221 | 222 | { 223 | char *x; 224 | tt_int_op(some_func(), ==, 0); 225 | 226 | x = malloc(100); 227 | tt_assert(x); 228 | 229 | end: 230 | /* Whoops! x might be uninitialized! */ 231 | if (x) free(x); 232 | } 233 | 234 | And here's another way to mess up: 235 | 236 | { 237 | tt_int_op(some_func(), ==, 0); 238 | 239 | { 240 | char *x; 241 | x = malloc(100); 242 | tt_assert(x); 243 | /* ... more tests that use x ... */ 244 | free(x); 245 | } 246 | 247 | end: 248 | /* uh-oh! we might wind up here, unable to free x! */ 249 | } 250 | 251 | 252 | You can also program your way around these problems through appropriate use 253 | of control flow, but it's generally better to just use the recommended 254 | pattern above. 255 | 256 | Running tests in a separate process 257 | ----------------------------------- 258 | 259 | Sometimes you might need to run tests in isolation so that they can have no 260 | effect on global state. (It sure gets confusing when tests interfere with 261 | each other.) To do this, you can set the TT_FORK flag on any test: Doing 262 | this will make the tinytest use fork() [on *nix] or CreateProcess [on 263 | Windows] to run that test in a sub-process. 264 | 265 | For example, if you wanted the test_strdup() test from the first thing above 266 | to run in a subprocess, you would declare string_tests[] as: 267 | 268 | struct testcase_t string_tests[] = { 269 | { "strdup", test_strdup, TT_FORK, NULL, NULL }, 270 | END_OF_TESTCASES 271 | }; 272 | 273 | 274 | Setup and tear-down functions 275 | ----------------------------- 276 | 277 | Sometimes you want to share setup and cleanup code for a large number of 278 | tests. To do this, write a function that creates an environment and another 279 | that tears it down, and wrap them in a testcase_setup_t structure: 280 | 281 | struct env { 282 | const char *test_string; 283 | char buf[1024]; 284 | }; 285 | 286 | void *create_test_environment(const struct testcase_t *testcase) 287 | { 288 | struct env *env = calloc(sizeof(*env), 1); 289 | 290 | if (! env) 291 | return NULL; /* Return NULL to indicate failure */ 292 | 293 | /* In this case, we're assuming setup_data is a string, and we 294 | can store it into the environment unprocessed. But really, 295 | setup_data can be any void *, so long as the setup function knows 296 | how to use it. */ 297 | env->test_string = testcase->setup_data; 298 | 299 | /* If there were other fields of env, we would initialize them here. 300 | */ 301 | 302 | return env; 303 | } 304 | 305 | void *cleanup_test_environment(struct testcase_t *, void *env_) 306 | { 307 | struct env *env = env_; 308 | 309 | /* on error, we should return 0 from this function */ 310 | return 1; 311 | } 312 | 313 | struct testcase_setup_t env_setup = { 314 | setup_test_environment, 315 | cleanup_test_environment 316 | }; 317 | 318 | And now we can write tests that use these environments, as in: 319 | 320 | static void testcase(void *arg) 321 | { 322 | struct env *env = arg; 323 | /* test here can use fields in env */ 324 | done: 325 | ; 326 | } 327 | 328 | struct testcase_t some_tests[] = { 329 | { "test_name", testcase, 0, &env_setup, (void*)"a string" }, 330 | END_OF_TESTCASES 331 | }; 332 | 333 | 334 | Skipping tests 335 | -------------- 336 | 337 | Not every test needs to be on by default, and not every test needs to be on 338 | for every platform. If you want to mark a test as not-to-be-run, you can 339 | set the TT_SKIP flag on it. If you want to mark it as off-by-default 340 | (perhaps because it is slow or buggy), you can set the TT_OFF_BY_DEFAULT flag. 341 | 342 | #ifdef _WIN32 343 | #define SKIP_ON_WINDOWS TT_SKIP 344 | #else 345 | #define SKIP_ON_WINDOWS 0 346 | #endif 347 | 348 | struct testcase_t some_tests[] = { 349 | { "not_on_windows", test_skipped1, SKIP_ON_WINDOWS, NULL, NULL }, 350 | { "not_by_default", test_skipped2, TT_OFF_BY_DEFAULT, NULL, NULL }, 351 | END_OF_TESTCASES 352 | }; 353 | 354 | If you want to decide whether to skip a test at runtime, you can do so by 355 | calling tt_skip(): 356 | 357 | if (wombat_init() < 0) { 358 | /* Couldn't initialize the wombat subsystem. I guess we aren't 359 | running this test. */ 360 | tt_skip(); 361 | } 362 | 363 | As you might expect, tt_skip() macro calls "goto end" to exit the test 364 | function. 365 | 366 | 367 | 368 | 369 | Inside test functions: reporting information 370 | -------------------------------------------- 371 | 372 | All output from a test case is generated using the TT_DECLARE macro. If 373 | you override TT_DECLARE before including tinytest_macros.h, you can 374 | replace its behavior with something else. TT_DECLARE takes two 375 | arguments: a prefix that , and a set of printf arguments in parenthesis. 376 | 377 | 378 | Example use: 379 | 380 | if (sec_elapsed > 120) 381 | TT_DECLARE("WARN", 382 | ("The test took %d seconds to run!", sec_elapsed)); 383 | 384 | If tinytest is running verbosely, the TT_BLATHER() macro takes a set of 385 | printf arguments and writes them to stdout using TT_DECLARE: 386 | 387 | x = get_wombat_count(); 388 | TT_BLATHER(("There are %d wombats", x)); 389 | 390 | Note the extra set of parenthesis in both cases; they are mandatory. 391 | 392 | Managing many tests 393 | ------------------- 394 | 395 | Once you start to have a lot of tests, you can put them in separate 396 | modules. You don't need to export the functions from the modules; 397 | instead, just export the arrays of testcases. So in file1.c, you might 398 | say: 399 | 400 | struct testcase_t string_tests[] = { 401 | { "strdup", test_strdup, 0, NULL, NULL }, 402 | { "strstr", test_strstr, TT_FORK, NULL, NULL }, 403 | { "reverse", test_reverse, 0, NULL, NULL }, 404 | END_OF_TESTCASES 405 | }; 406 | 407 | And in file2.c you might say: 408 | 409 | struct testcase_t portal_tests[] = { 410 | { "orange", test_portal, 0, &portal_setup, (char*)"orange" }, 411 | { "blue", test_portal, 0, &portal_setup, (char*)"blue" }, 412 | { "longfall", test_longfall, TT_FORK, NULL, NULL }, 413 | END_OF_TESTCASES 414 | }; 415 | 416 | And in test_main.c you could say: 417 | 418 | extern testcase_t string_tests[]; 419 | extern testcase_t portal_tests[]; 420 | struct testgroup_t test_groups[] = { 421 | { "string/", string_tests }, 422 | { "portal/", portal_tests }, 423 | END_OF_GROUPS 424 | }; 425 | 426 | When you run these tests, the names of the string tests will be prefixed 427 | with "string/", and the names of the portal tests will be prefixed with 428 | "portal/". 429 | 430 | 431 | Invoking tinytest 432 | ----------------- 433 | 434 | You can control the verbosity of tinytest from the command line. By 435 | default, tinytest prints the name of every test as it runs, and tells 436 | you about failed check macros and tests. 437 | 438 | If you pass the "--terse" command line option, tinytest will print a dot 439 | for each passing test, instead of its name. If you pass the "--quiet" 440 | option, tinytest will only tell you about failed tests. And if you pass 441 | "--verbose" flag, tinytest will print a line for every check macro, 442 | including ones that are successful. 443 | 444 | You can list all the test cases, instead of running them, by passing the 445 | "--list-tests" flag. 446 | 447 | You can control which tests will be run by listing them on the command 448 | line. The string ".." is a wildcard that matches at the end of test 449 | names. So for examine, in the section above, you could run only the 450 | portal tests by passing "portal/.." on the command line. 451 | 452 | To disable tests, prefix their names or a wildcard with the : character. 453 | So to turn off the longfall and string tests, you could pass 454 | ":portal/longfall :string/..". 455 | 456 | To run an off-by-default test, prefix its name (or a wildcard pattern 457 | matching its name) with the + character. (Thus, you can run all tests, 458 | including off-by-default tests, by passing "+.." on the command line. 459 | 460 | If you need to run a test in a debugger, and the debugger doesn't follow 461 | fork() or CreateProcess() very well, you can turn off the pre-test 462 | forking with the "--no-fork" option. Doing this when you're running 463 | more than a single test can give you unexpected results, though: after 464 | all, you're turning off the test isolation. 465 | 466 | 467 | Legal boilerplate 468 | ----------------- 469 | 470 | There is no warranty on tinytest or on any code in this document. 471 | 472 | Tinytest itself is distributed under the 3-clause BSD license. 473 | 474 | Absolutely everybody has permission to copy any of the code *in this 475 | document* freely into your own programs, modify it however you want, and 476 | do anything else with it that copyright laws would otherwise restrict. 477 | You do not need to give me credit or reproduce any kind of notice. 478 | 479 | But if it would make you more comfortable to have a a formal license, you 480 | may also use all of this code under the terms of the "3-clause BSD 481 | license" quoted here: 482 | 483 | > Copyright 2009-2014 Nick Mathewson 484 | > 485 | > Redistribution and use in source and binary forms, with or without 486 | > modification, are permitted provided that the following conditions 487 | > are met: 488 | > 1. Redistributions of source code must retain the above copyright 489 | > notice, this list of conditions and the following disclaimer. 490 | > 2. Redistributions in binary form must reproduce the above copyright 491 | > notice, this list of conditions and the following disclaimer in the 492 | > documentation and/or other materials provided with the distribution. 493 | > 3. The name of the author may not be used to endorse or promote products 494 | > derived from this software without specific prior written permission. 495 | * 496 | > THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 497 | > IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 498 | > OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 499 | > IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 500 | > INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 501 | > NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 502 | > DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 503 | > THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 504 | > (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 505 | > THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 506 | 507 | -------------------------------------------------------------------------------- /tinytest.c: -------------------------------------------------------------------------------- 1 | /* tinytest.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 | #ifdef TINYTEST_LOCAL 26 | #include "tinytest_local.h" 27 | #endif 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | #ifndef NO_FORKING 35 | 36 | #ifdef _WIN32 37 | #include 38 | #else 39 | #include 40 | #include 41 | #include 42 | #endif 43 | 44 | #if defined(__APPLE__) && defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) 45 | #if (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1060 && \ 46 | __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1070) 47 | /* Workaround for a stupid bug in OSX 10.6 */ 48 | #define FORK_BREAKS_GCOV 49 | #include 50 | #endif 51 | #endif 52 | 53 | #endif /* !NO_FORKING */ 54 | 55 | #ifndef __GNUC__ 56 | #define __attribute__(x) 57 | #endif 58 | 59 | #include "tinytest.h" 60 | #include "tinytest_macros.h" 61 | 62 | #define LONGEST_TEST_NAME 16384 63 | 64 | static int in_tinytest_main = 0; /**< true if we're in tinytest_main().*/ 65 | static int n_ok = 0; /**< Number of tests that have passed */ 66 | static int n_bad = 0; /**< Number of tests that have failed. */ 67 | static int n_skipped = 0; /**< Number of tests that have been skipped. */ 68 | 69 | static int opt_forked = 0; /**< True iff we're called from inside a win32 fork*/ 70 | static int opt_nofork = 0; /**< Suppress calls to fork() for debugging. */ 71 | static int opt_verbosity = 1; /**< -==quiet,0==terse,1==normal,2==verbose */ 72 | const char *verbosity_flag = ""; 73 | 74 | const struct testlist_alias_t *cfg_aliases=NULL; 75 | 76 | enum outcome { SKIP=2, OK=1, FAIL=0 }; 77 | static enum outcome cur_test_outcome = FAIL; 78 | const char *cur_test_prefix = NULL; /**< prefix of the current test group */ 79 | /** Name of the current test, if we haven't logged is yet. Used for --quiet */ 80 | const char *cur_test_name = NULL; 81 | 82 | #ifdef _WIN32 83 | /* Copy of argv[0] for win32. */ 84 | static char commandname[MAX_PATH+1]; 85 | #endif 86 | 87 | static void usage(struct testgroup_t *groups, int list_groups) 88 | __attribute__((noreturn)); 89 | static int process_test_option(struct testgroup_t *groups, const char *test); 90 | 91 | static enum outcome 92 | testcase_run_bare_(const struct testcase_t *testcase) 93 | { 94 | void *env = NULL; 95 | enum outcome outcome; 96 | if (testcase->setup) { 97 | env = testcase->setup->setup_fn(testcase); 98 | if (!env) 99 | return FAIL; 100 | else if (env == (void*)TT_SKIP) 101 | return SKIP; 102 | } 103 | 104 | cur_test_outcome = OK; 105 | testcase->fn(env); 106 | outcome = cur_test_outcome; 107 | 108 | if (testcase->setup) { 109 | if (testcase->setup->cleanup_fn(testcase, env) == 0) 110 | outcome = FAIL; 111 | } 112 | 113 | return outcome; 114 | } 115 | 116 | #define MAGIC_EXITCODE 42 117 | 118 | #ifndef NO_FORKING 119 | 120 | static enum outcome 121 | testcase_run_forked_(const struct testgroup_t *group, 122 | const struct testcase_t *testcase) 123 | { 124 | #ifdef _WIN32 125 | /* Fork? On Win32? How primitive! We'll do what the smart kids do: 126 | we'll invoke our own exe (whose name we recall from the command 127 | line) with a command line that tells it to run just the test we 128 | want, and this time without forking. 129 | 130 | (No, threads aren't an option. The whole point of forking is to 131 | share no state between tests.) 132 | */ 133 | int ok; 134 | char buffer[LONGEST_TEST_NAME+256]; 135 | STARTUPINFOA si; 136 | PROCESS_INFORMATION info; 137 | DWORD exitcode; 138 | 139 | if (!in_tinytest_main) { 140 | printf("\nERROR. On Windows, testcase_run_forked_ must be" 141 | " called from within tinytest_main.\n"); 142 | abort(); 143 | } 144 | if (opt_verbosity>0) 145 | printf("[forking] "); 146 | 147 | snprintf(buffer, sizeof(buffer), "%s --RUNNING-FORKED %s %s%s", 148 | commandname, verbosity_flag, group->prefix, testcase->name); 149 | 150 | memset(&si, 0, sizeof(si)); 151 | memset(&info, 0, sizeof(info)); 152 | si.cb = sizeof(si); 153 | 154 | ok = CreateProcessA(commandname, buffer, NULL, NULL, 0, 155 | 0, NULL, NULL, &si, &info); 156 | if (!ok) { 157 | printf("CreateProcess failed!\n"); 158 | return 0; 159 | } 160 | WaitForSingleObject(info.hProcess, INFINITE); 161 | GetExitCodeProcess(info.hProcess, &exitcode); 162 | CloseHandle(info.hProcess); 163 | CloseHandle(info.hThread); 164 | if (exitcode == 0) 165 | return OK; 166 | else if (exitcode == MAGIC_EXITCODE) 167 | return SKIP; 168 | else 169 | return FAIL; 170 | #else 171 | int outcome_pipe[2]; 172 | pid_t pid; 173 | (void)group; 174 | 175 | if (pipe(outcome_pipe)) 176 | perror("opening pipe"); 177 | 178 | if (opt_verbosity>0) 179 | printf("[forking] "); 180 | pid = fork(); 181 | #ifdef FORK_BREAKS_GCOV 182 | vproc_transaction_begin(0); 183 | #endif 184 | if (!pid) { 185 | /* child. */ 186 | int test_r, write_r; 187 | char b[1]; 188 | close(outcome_pipe[0]); 189 | test_r = testcase_run_bare_(testcase); 190 | assert(0<=(int)test_r && (int)test_r<=2); 191 | b[0] = "NYS"[test_r]; 192 | write_r = (int)write(outcome_pipe[1], b, 1); 193 | if (write_r != 1) { 194 | perror("write outcome to pipe"); 195 | exit(1); 196 | } 197 | exit(0); 198 | return FAIL; /* unreachable */ 199 | } else { 200 | /* parent */ 201 | int status, r; 202 | char b[1]; 203 | /* Close this now, so that if the other side closes it, 204 | * our read fails. */ 205 | close(outcome_pipe[1]); 206 | r = (int)read(outcome_pipe[0], b, 1); 207 | if (r == 0) { 208 | printf("[Lost connection!] "); 209 | return FAIL; 210 | } else if (r != 1) { 211 | perror("read outcome from pipe"); 212 | } 213 | waitpid(pid, &status, 0); 214 | close(outcome_pipe[0]); 215 | return b[0]=='Y' ? OK : (b[0]=='S' ? SKIP : FAIL); 216 | } 217 | #endif 218 | } 219 | 220 | #endif /* !NO_FORKING */ 221 | 222 | int 223 | testcase_run_one(const struct testgroup_t *group, 224 | const struct testcase_t *testcase) 225 | { 226 | enum outcome outcome; 227 | 228 | if (testcase->flags & (TT_SKIP|TT_OFF_BY_DEFAULT)) { 229 | if (opt_verbosity>0) 230 | printf("%s%s: %s\n", 231 | group->prefix, testcase->name, 232 | (testcase->flags & TT_SKIP) ? "SKIPPED" : "DISABLED"); 233 | ++n_skipped; 234 | return SKIP; 235 | } 236 | 237 | if (opt_verbosity>0 && !opt_forked) { 238 | printf("%s%s: ", group->prefix, testcase->name); 239 | } else { 240 | if (opt_verbosity==0) printf("."); 241 | cur_test_prefix = group->prefix; 242 | cur_test_name = testcase->name; 243 | } 244 | 245 | #ifndef NO_FORKING 246 | if ((testcase->flags & TT_FORK) && !(opt_forked||opt_nofork)) { 247 | outcome = testcase_run_forked_(group, testcase); 248 | } else { 249 | #else 250 | { 251 | #endif 252 | outcome = testcase_run_bare_(testcase); 253 | } 254 | 255 | if (outcome == OK) { 256 | ++n_ok; 257 | if (opt_verbosity>0 && !opt_forked) 258 | puts(opt_verbosity==1?"OK":""); 259 | } else if (outcome == SKIP) { 260 | ++n_skipped; 261 | if (opt_verbosity>0 && !opt_forked) 262 | puts("SKIPPED"); 263 | } else { 264 | ++n_bad; 265 | if (!opt_forked) 266 | printf("\n [%s FAILED]\n", testcase->name); 267 | } 268 | 269 | if (opt_forked) { 270 | exit(outcome==OK ? 0 : (outcome==SKIP?MAGIC_EXITCODE : 1)); 271 | return 1; /* unreachable */ 272 | } else { 273 | return (int)outcome; 274 | } 275 | } 276 | 277 | int 278 | tinytest_set_flag_(struct testgroup_t *groups, const char *arg, int set, unsigned long flag) 279 | { 280 | int i, j; 281 | size_t length = LONGEST_TEST_NAME; 282 | char fullname[LONGEST_TEST_NAME]; 283 | int found=0; 284 | if (strstr(arg, "..")) 285 | length = strstr(arg,"..")-arg; 286 | for (i=0; groups[i].prefix; ++i) { 287 | for (j=0; groups[i].cases[j].name; ++j) { 288 | struct testcase_t *testcase = &groups[i].cases[j]; 289 | snprintf(fullname, sizeof(fullname), "%s%s", 290 | groups[i].prefix, testcase->name); 291 | if (!flag) { /* Hack! */ 292 | printf(" %s", fullname); 293 | if (testcase->flags & TT_OFF_BY_DEFAULT) 294 | puts(" (Off by default)"); 295 | else if (testcase->flags & TT_SKIP) 296 | puts(" (DISABLED)"); 297 | else 298 | puts(""); 299 | } 300 | if (!strncmp(fullname, arg, length)) { 301 | if (set) 302 | testcase->flags |= flag; 303 | else 304 | testcase->flags &= ~flag; 305 | ++found; 306 | } 307 | } 308 | } 309 | return found; 310 | } 311 | 312 | static void 313 | usage(struct testgroup_t *groups, int list_groups) 314 | { 315 | puts("Options are: [--verbose|--quiet|--terse] [--no-fork]"); 316 | puts(" Specify tests by name, or using a prefix ending with '..'"); 317 | puts(" To skip a test, prefix its name with a colon."); 318 | puts(" To enable a disabled test, prefix its name with a plus."); 319 | puts(" Use --list-tests for a list of tests."); 320 | if (list_groups) { 321 | puts("Known tests are:"); 322 | tinytest_set_flag_(groups, "..", 1, 0); 323 | } 324 | exit(0); 325 | } 326 | 327 | static int 328 | process_test_alias(struct testgroup_t *groups, const char *test) 329 | { 330 | int i, j, n, r; 331 | for (i=0; cfg_aliases && cfg_aliases[i].name; ++i) { 332 | if (!strcmp(cfg_aliases[i].name, test)) { 333 | n = 0; 334 | for (j = 0; cfg_aliases[i].tests[j]; ++j) { 335 | r = process_test_option(groups, cfg_aliases[i].tests[j]); 336 | if (r<0) 337 | return -1; 338 | n += r; 339 | } 340 | return n; 341 | } 342 | } 343 | printf("No such test alias as @%s!",test); 344 | return -1; 345 | } 346 | 347 | static int 348 | process_test_option(struct testgroup_t *groups, const char *test) 349 | { 350 | int flag = TT_ENABLED_; 351 | int n = 0; 352 | if (test[0] == '@') { 353 | return process_test_alias(groups, test + 1); 354 | } else if (test[0] == ':') { 355 | ++test; 356 | flag = TT_SKIP; 357 | } else if (test[0] == '+') { 358 | ++test; 359 | ++n; 360 | if (!tinytest_set_flag_(groups, test, 0, TT_OFF_BY_DEFAULT)) { 361 | printf("No such test as %s!\n", test); 362 | return -1; 363 | } 364 | } else { 365 | ++n; 366 | } 367 | if (!tinytest_set_flag_(groups, test, 1, flag)) { 368 | printf("No such test as %s!\n", test); 369 | return -1; 370 | } 371 | return n; 372 | } 373 | 374 | void 375 | tinytest_set_aliases(const struct testlist_alias_t *aliases) 376 | { 377 | cfg_aliases = aliases; 378 | } 379 | 380 | int 381 | tinytest_main(int c, const char **v, struct testgroup_t *groups) 382 | { 383 | int i, j, n=0; 384 | 385 | #ifdef _WIN32 386 | const char *sp = strrchr(v[0], '.'); 387 | const char *extension = ""; 388 | if (!sp || stricmp(sp, ".exe")) 389 | extension = ".exe"; /* Add an exe so CreateProcess will work */ 390 | snprintf(commandname, sizeof(commandname), "%s%s", v[0], extension); 391 | commandname[MAX_PATH]='\0'; 392 | #endif 393 | for (i=1; i= 1) 446 | printf("%d tests ok. (%d skipped)\n", n_ok, n_skipped); 447 | 448 | return (n_bad == 0) ? 0 : 1; 449 | } 450 | 451 | int 452 | tinytest_get_verbosity_(void) 453 | { 454 | return opt_verbosity; 455 | } 456 | 457 | void 458 | tinytest_set_test_failed_(void) 459 | { 460 | if (opt_verbosity <= 0 && cur_test_name) { 461 | if (opt_verbosity==0) puts(""); 462 | printf("%s%s: ", cur_test_prefix, cur_test_name); 463 | cur_test_name = NULL; 464 | } 465 | cur_test_outcome = FAIL; 466 | } 467 | 468 | void 469 | tinytest_set_test_skipped_(void) 470 | { 471 | if (cur_test_outcome==OK) 472 | cur_test_outcome = SKIP; 473 | } 474 | 475 | char * 476 | tinytest_format_hex_(const void *val_, unsigned long len) 477 | { 478 | const unsigned char *val = (unsigned char *) val_; 479 | char *result, *cp; 480 | size_t i; 481 | 482 | if (!val) 483 | return strdup("null"); 484 | if (!(result = (char *) malloc(len*2+1))) 485 | return strdup(""); 486 | cp = result; 487 | for (i=0;i> 4]; 489 | *cp++ = "0123456789ABCDEF"[val[i] & 0x0f]; 490 | } 491 | *cp = 0; 492 | return result; 493 | } 494 | -------------------------------------------------------------------------------- /tinytest.h: -------------------------------------------------------------------------------- 1 | /* tinytest.h -- 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 | #ifndef TINYTEST_H_INCLUDED_ 27 | #define TINYTEST_H_INCLUDED_ 28 | 29 | /** Flag for a test that needs to run in a subprocess. */ 30 | #define TT_FORK (1<<0) 31 | /** Runtime flag for a test we've decided to skip. */ 32 | #define TT_SKIP (1<<1) 33 | /** Internal runtime flag for a test we've decided to run. */ 34 | #define TT_ENABLED_ (1<<2) 35 | /** Flag for a test that's off by default. */ 36 | #define TT_OFF_BY_DEFAULT (1<<3) 37 | /** If you add your own flags, make them start at this point. */ 38 | #define TT_FIRST_USER_FLAG (1<<4) 39 | 40 | typedef void (*testcase_fn)(void *); 41 | 42 | struct testcase_t; 43 | 44 | /** Functions to initialize/teardown a structure for a testcase. */ 45 | struct testcase_setup_t { 46 | /** Return a new structure for use by a given testcase. */ 47 | void *(*setup_fn)(const struct testcase_t *); 48 | /** Clean/free a structure from setup_fn. Return 1 if ok, 0 on err. */ 49 | int (*cleanup_fn)(const struct testcase_t *, void *); 50 | }; 51 | 52 | /** A single test-case that you can run. */ 53 | struct testcase_t { 54 | const char *name; /**< An identifier for this case. */ 55 | testcase_fn fn; /**< The function to run to implement this case. */ 56 | unsigned long flags; /**< Bitfield of TT_* flags. */ 57 | const struct testcase_setup_t *setup; /**< Optional setup/cleanup fns*/ 58 | void *setup_data; /**< Extra data usable by setup function */ 59 | }; 60 | #define END_OF_TESTCASES { NULL, NULL, 0, NULL, NULL } 61 | 62 | /** A group of tests that are selectable together. */ 63 | struct testgroup_t { 64 | const char *prefix; /**< Prefix to prepend to testnames. */ 65 | struct testcase_t *cases; /** Array, ending with END_OF_TESTCASES */ 66 | }; 67 | #define END_OF_GROUPS { NULL, NULL} 68 | 69 | struct testlist_alias_t { 70 | const char *name; 71 | const char **tests; 72 | }; 73 | #define END_OF_ALIASES { NULL, NULL } 74 | 75 | /** Implementation: called from a test to indicate failure, before logging. */ 76 | void tinytest_set_test_failed_(void); 77 | /** Implementation: called from a test to indicate that we're skipping. */ 78 | void tinytest_set_test_skipped_(void); 79 | /** Implementation: return 0 for quiet, 1 for normal, 2 for loud. */ 80 | int tinytest_get_verbosity_(void); 81 | /** Implementation: Set a flag on tests matching a name; returns number 82 | * of tests that matched. */ 83 | int tinytest_set_flag_(struct testgroup_t *, const char *, int set, unsigned long); 84 | /** Implementation: Put a chunk of memory into hex. */ 85 | char *tinytest_format_hex_(const void *, unsigned long); 86 | 87 | /** Set all tests in 'groups' matching the name 'named' to be skipped. */ 88 | #define tinytest_skip(groups, named) \ 89 | tinytest_set_flag_(groups, named, 1, TT_SKIP) 90 | 91 | /** Run a single testcase in a single group. */ 92 | int testcase_run_one(const struct testgroup_t *,const struct testcase_t *); 93 | 94 | void tinytest_set_aliases(const struct testlist_alias_t *aliases); 95 | 96 | /** Run a set of testcases from an END_OF_GROUPS-terminated array of groups, 97 | as selected from the command line. */ 98 | int tinytest_main(int argc, const char **argv, struct testgroup_t *groups); 99 | 100 | #endif 101 | -------------------------------------------------------------------------------- /tinytest_demo.c: -------------------------------------------------------------------------------- 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 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | #ifdef _WIN32 41 | #include 42 | #else 43 | #include 44 | #endif 45 | 46 | /* ============================================================ */ 47 | 48 | /* First, let's see if strcmp is working. (All your test cases should be 49 | * functions declared to take a single void * as an argument.) */ 50 | void 51 | test_strcmp(void *data) 52 | { 53 | (void)data; /* This testcase takes no data. */ 54 | 55 | /* Let's make sure the empty string is equal to itself */ 56 | if (strcmp("","")) { 57 | /* This macro tells tinytest to stop the current test 58 | * and go straight to the "end" label. */ 59 | tt_abort_msg("The empty string was not equal to itself"); 60 | } 61 | 62 | /* Pretty often, calling tt_abort_msg to indicate failure is more 63 | heavy-weight than you want. Instead, just say: */ 64 | tt_assert(strcmp("testcase", "testcase") == 0); 65 | 66 | /* Occasionally, you don't want to stop the current testcase just 67 | because a single assertion has failed. In that case, use 68 | tt_want: */ 69 | tt_want(strcmp("tinytest", "testcase") > 0); 70 | 71 | /* You can use the tt_*_op family of macros to compare values and to 72 | fail unless they have the relationship you want. They produce 73 | more useful output than tt_assert, since they display the actual 74 | values of the failing things. 75 | 76 | Fail unless strcmp("abc, "abc") == 0 */ 77 | tt_int_op(strcmp("abc", "abc"), ==, 0); 78 | 79 | /* Fail unless strcmp("abc, "abcd") is less than 0 */ 80 | tt_int_op(strcmp("abc", "abcd"), < , 0); 81 | 82 | /* Incidentally, there's a test_str_op that uses strcmp internally. */ 83 | tt_str_op("abc", <, "abcd"); 84 | 85 | 86 | /* Every test-case function needs to finish with an "end:" 87 | label and (optionally) code to clean up local variables. */ 88 | end: 89 | ; 90 | } 91 | 92 | /* ============================================================ */ 93 | 94 | /* Now let's mess with setup and teardown functions! These are handy if 95 | you have a bunch of tests that all need a similar environment, and you 96 | want to reconstruct that environment freshly for each one. */ 97 | 98 | /* First you declare a type to hold the environment info, and functions to 99 | set it up and tear it down. */ 100 | struct data_buffer { 101 | /* We're just going to have couple of character buffer. Using 102 | setup/teardown functions is probably overkill for this case. 103 | 104 | You could also do file descriptors, complicated handles, temporary 105 | files, etc. */ 106 | char buffer1[512]; 107 | char buffer2[512]; 108 | }; 109 | /* The setup function needs to take a const struct testcase_t and return 110 | void* */ 111 | void * 112 | setup_data_buffer(const struct testcase_t *testcase) 113 | { 114 | struct data_buffer *db = malloc(sizeof(struct data_buffer)); 115 | 116 | /* If you had a complicated set of setup rules, you might behave 117 | differently here depending on testcase->flags or 118 | testcase->setup_data or even or testcase->name. */ 119 | 120 | /* Returning a NULL here would mean that we couldn't set up for this 121 | test, so we don't need to test db for null. */ 122 | return db; 123 | } 124 | /* The clean function deallocates storage carefully and returns true on 125 | success. */ 126 | int 127 | clean_data_buffer(const struct testcase_t *testcase, void *ptr) 128 | { 129 | struct data_buffer *db = ptr; 130 | 131 | if (db) { 132 | free(db); 133 | return 1; 134 | } 135 | return 0; 136 | } 137 | /* Finally, declare a testcase_setup_t with these functions. */ 138 | struct testcase_setup_t data_buffer_setup = { 139 | setup_data_buffer, clean_data_buffer 140 | }; 141 | 142 | 143 | /* Now let's write our test. */ 144 | void 145 | test_memcpy(void *ptr) 146 | { 147 | /* This time, we use the argument. */ 148 | struct data_buffer *db = ptr; 149 | 150 | /* We'll also introduce a local variable that might need cleaning up. */ 151 | char *mem = NULL; 152 | 153 | /* Let's make sure that memcpy does what we'd like. */ 154 | strcpy(db->buffer1, "String 0"); 155 | memcpy(db->buffer2, db->buffer1, sizeof(db->buffer1)); 156 | tt_str_op(db->buffer1, ==, db->buffer2); 157 | 158 | /* tt_mem_op() does a memcmp, as opposed to the strcmp in tt_str_op() */ 159 | db->buffer2[100] = 3; /* Make the buffers unequal */ 160 | tt_mem_op(db->buffer1, <, db->buffer2, sizeof(db->buffer1)); 161 | 162 | /* Now we've allocated memory that's referenced by a local variable. 163 | The end block of the function will clean it up. */ 164 | mem = strdup("Hello world."); 165 | tt_assert(mem); 166 | 167 | /* Another rather trivial test. */ 168 | tt_str_op(db->buffer1, !=, mem); 169 | 170 | end: 171 | /* This time our end block has something to do. */ 172 | if (mem) 173 | free(mem); 174 | } 175 | 176 | void 177 | test_timeout(void *ptr) 178 | { 179 | time_t t1, t2; 180 | (void)ptr; 181 | t1 = time(NULL); 182 | #ifdef _WIN32 183 | Sleep(5000); 184 | #else 185 | sleep(5); 186 | #endif 187 | t2 = time(NULL); 188 | 189 | tt_int_op(t2-t1, >=, 4); 190 | 191 | tt_int_op(t2-t1, <=, 6); 192 | 193 | end: 194 | ; 195 | } 196 | 197 | /* ============================================================ */ 198 | 199 | /* Now we need to make sure that our tests get invoked. First, you take 200 | a bunch of related tests and put them into an array of struct testcase_t. 201 | */ 202 | 203 | struct testcase_t demo_tests[] = { 204 | /* Here's a really simple test: it has a name you can refer to it 205 | with, and a function to invoke it. */ 206 | { "strcmp", test_strcmp, }, 207 | 208 | /* The second test has a flag, "TT_FORK", to make it run in a 209 | subprocess, and a pointer to the testcase_setup_t that configures 210 | its environment. */ 211 | { "memcpy", test_memcpy, TT_FORK, &data_buffer_setup }, 212 | 213 | /* This flag is off-by-default, since it takes a while to run. You 214 | * can enable it manually by passing +demo/timeout at the command line.*/ 215 | { "timeout", test_timeout, TT_OFF_BY_DEFAULT }, 216 | 217 | /* The array has to end with END_OF_TESTCASES. */ 218 | END_OF_TESTCASES 219 | }; 220 | 221 | /* Next, we make an array of testgroups. This is mandatory. Unlike more 222 | heavy-duty testing frameworks, groups can't nest. */ 223 | struct testgroup_t groups[] = { 224 | 225 | /* Every group has a 'prefix', and an array of tests. That's it. */ 226 | { "demo/", demo_tests }, 227 | 228 | END_OF_GROUPS 229 | }; 230 | 231 | /* We can also define test aliases. These can be used for types of tests that 232 | * cut across groups. */ 233 | const char *alltests[] = { "+..", NULL }; 234 | const char *slowtests[] = { "+demo/timeout", NULL }; 235 | struct testlist_alias_t aliases[] = { 236 | 237 | { "ALL", alltests }, 238 | { "SLOW", slowtests }, 239 | 240 | END_OF_ALIASES 241 | }; 242 | 243 | 244 | int 245 | main(int c, const char **v) 246 | { 247 | /* Finally, just call tinytest_main(). It lets you specify verbose 248 | or quiet output with --verbose and --quiet. You can list 249 | specific tests: 250 | 251 | tinytest-demo demo/memcpy 252 | 253 | or use a ..-wildcard to select multiple tests with a common 254 | prefix: 255 | 256 | tinytest-demo demo/.. 257 | 258 | If you list no tests, you get them all by default, so that 259 | "tinytest-demo" and "tinytest-demo .." mean the same thing. 260 | 261 | */ 262 | tinytest_set_aliases(aliases); 263 | return tinytest_main(c, v, groups); 264 | } 265 | -------------------------------------------------------------------------------- /tinytest_macros.h: -------------------------------------------------------------------------------- 1 | /* tinytest_macros.h -- 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 | #ifndef TINYTEST_MACROS_H_INCLUDED_ 27 | #define TINYTEST_MACROS_H_INCLUDED_ 28 | 29 | /* Helpers for defining statement-like macros */ 30 | #define TT_STMT_BEGIN do { 31 | #define TT_STMT_END } while (0) 32 | 33 | /* Redefine this if your test functions want to abort with something besides 34 | * "goto end;" */ 35 | #ifndef TT_EXIT_TEST_FUNCTION 36 | #define TT_EXIT_TEST_FUNCTION TT_STMT_BEGIN goto end; TT_STMT_END 37 | #endif 38 | 39 | /* Redefine this if you want to note success/failure in some different way. */ 40 | #ifndef TT_DECLARE 41 | #define TT_DECLARE(prefix, args) \ 42 | TT_STMT_BEGIN \ 43 | printf("\n %s %s:%d: ",prefix,__FILE__,__LINE__); \ 44 | printf args ; \ 45 | TT_STMT_END 46 | #endif 47 | 48 | /* Announce a failure. Args are parenthesized printf args. */ 49 | #define TT_GRIPE(args) TT_DECLARE("FAIL", args) 50 | 51 | /* Announce a non-failure if we're verbose. */ 52 | #define TT_BLATHER(args) \ 53 | TT_STMT_BEGIN \ 54 | if (tinytest_get_verbosity_()>1) TT_DECLARE(" OK", args); \ 55 | TT_STMT_END 56 | 57 | #define TT_DIE(args) \ 58 | TT_STMT_BEGIN \ 59 | tinytest_set_test_failed_(); \ 60 | TT_GRIPE(args); \ 61 | TT_EXIT_TEST_FUNCTION; \ 62 | TT_STMT_END 63 | 64 | #define TT_FAIL(args) \ 65 | TT_STMT_BEGIN \ 66 | tinytest_set_test_failed_(); \ 67 | TT_GRIPE(args); \ 68 | TT_STMT_END 69 | 70 | /* Fail and abort the current test for the reason in msg */ 71 | #define tt_abort_printf(msg) TT_DIE(msg) 72 | #define tt_abort_perror(op) TT_DIE(("%s: %s [%d]",(op),strerror(errno), errno)) 73 | #define tt_abort_msg(msg) TT_DIE(("%s", msg)) 74 | #define tt_abort() TT_DIE(("%s", "(Failed.)")) 75 | 76 | /* Fail but do not abort the current test for the reason in msg. */ 77 | #define tt_fail_printf(msg) TT_FAIL(msg) 78 | #define tt_fail_perror(op) TT_FAIL(("%s: %s [%d]",(op),strerror(errno), errno)) 79 | #define tt_fail_msg(msg) TT_FAIL(("%s", msg)) 80 | #define tt_fail() TT_FAIL(("%s", "(Failed.)")) 81 | 82 | /* End the current test, and indicate we are skipping it. */ 83 | #define tt_skip() \ 84 | TT_STMT_BEGIN \ 85 | tinytest_set_test_skipped_(); \ 86 | TT_EXIT_TEST_FUNCTION; \ 87 | TT_STMT_END 88 | 89 | #define tt_want_(b, msg, fail) \ 90 | TT_STMT_BEGIN \ 91 | if (!(b)) { \ 92 | tinytest_set_test_failed_(); \ 93 | TT_GRIPE(("%s",msg)); \ 94 | fail; \ 95 | } else { \ 96 | TT_BLATHER(("%s",msg)); \ 97 | } \ 98 | TT_STMT_END 99 | 100 | /* Assert b, but do not stop the test if b fails. Log msg on failure. */ 101 | #define tt_want_msg(b, msg) \ 102 | tt_want_(b, msg, ); 103 | 104 | /* Assert b and stop the test if b fails. Log msg on failure. */ 105 | #define tt_assert_msg(b, msg) \ 106 | tt_want_(b, msg, TT_EXIT_TEST_FUNCTION); 107 | 108 | /* Assert b, but do not stop the test if b fails. */ 109 | #define tt_want(b) tt_want_msg( (b), "want("#b")") 110 | /* Assert b, and stop the test if b fails. */ 111 | #define tt_assert(b) tt_assert_msg((b), "assert("#b")") 112 | 113 | #define tt_assert_test_fmt_type(a,b,str_test,type,test,printf_type,printf_fmt, \ 114 | setup_block,cleanup_block,die_on_fail) \ 115 | TT_STMT_BEGIN \ 116 | type val1_ = (a); \ 117 | type val2_ = (b); \ 118 | int tt_status_ = (test); \ 119 | if (!tt_status_ || tinytest_get_verbosity_()>1) { \ 120 | printf_type print_; \ 121 | printf_type print1_; \ 122 | printf_type print2_; \ 123 | type value_ = val1_; \ 124 | setup_block; \ 125 | print1_ = print_; \ 126 | value_ = val2_; \ 127 | setup_block; \ 128 | print2_ = print_; \ 129 | TT_DECLARE(tt_status_?" OK":"FAIL", \ 130 | ("assert(%s): " printf_fmt " vs " printf_fmt,\ 131 | str_test, print1_, print2_)); \ 132 | print_ = print1_; \ 133 | cleanup_block; \ 134 | print_ = print2_; \ 135 | cleanup_block; \ 136 | if (!tt_status_) { \ 137 | tinytest_set_test_failed_(); \ 138 | die_on_fail ; \ 139 | } \ 140 | } \ 141 | TT_STMT_END 142 | 143 | #define tt_assert_test_type(a,b,str_test,type,test,fmt,die_on_fail) \ 144 | tt_assert_test_fmt_type(a,b,str_test,type,test,type,fmt, \ 145 | {print_=value_;},{},die_on_fail) 146 | 147 | #define tt_assert_test_type_opt(a,b,str_test,type,test,fmt,die_on_fail) \ 148 | tt_assert_test_fmt_type(a,b,str_test,type,test,type,fmt, \ 149 | {print_=value_?value_:"";},{},die_on_fail) 150 | 151 | /* Helper: assert that a op b, when cast to type. Format the values with 152 | * printf format fmt on failure. */ 153 | #define tt_assert_op_type(a,op,b,type,fmt) \ 154 | tt_assert_test_type(a,b,#a" "#op" "#b,type,(val1_ op val2_),fmt, \ 155 | TT_EXIT_TEST_FUNCTION) 156 | 157 | #define tt_int_op(a,op,b) \ 158 | tt_assert_test_type(a,b,#a" "#op" "#b,long,(val1_ op val2_), \ 159 | "%ld",TT_EXIT_TEST_FUNCTION) 160 | 161 | #define tt_uint_op(a,op,b) \ 162 | tt_assert_test_type(a,b,#a" "#op" "#b,unsigned long, \ 163 | (val1_ op val2_),"%lu",TT_EXIT_TEST_FUNCTION) 164 | 165 | #define tt_ptr_op(a,op,b) \ 166 | tt_assert_test_type(a,b,#a" "#op" "#b,const void*, \ 167 | (val1_ op val2_),"%p",TT_EXIT_TEST_FUNCTION) 168 | 169 | #define tt_str_op(a,op,b) \ 170 | tt_assert_test_type_opt(a,b,#a" "#op" "#b,const char *, \ 171 | (val1_ && val2_ && strcmp(val1_,val2_) op 0),"<%s>", \ 172 | TT_EXIT_TEST_FUNCTION) 173 | 174 | #define tt_mem_op(expr1, op, expr2, len) \ 175 | tt_assert_test_fmt_type(expr1,expr2,#expr1" "#op" "#expr2, \ 176 | const void *, \ 177 | (val1_ && val2_ && memcmp(val1_, val2_, len) op 0), \ 178 | char *, "%s", \ 179 | { print_ = tinytest_format_hex_(value_, (len)); }, \ 180 | { if (print_) free(print_); }, \ 181 | TT_EXIT_TEST_FUNCTION \ 182 | ); 183 | 184 | #define tt_want_int_op(a,op,b) \ 185 | tt_assert_test_type(a,b,#a" "#op" "#b,long,(val1_ op val2_),"%ld",(void)0) 186 | 187 | #define tt_want_uint_op(a,op,b) \ 188 | tt_assert_test_type(a,b,#a" "#op" "#b,unsigned long, \ 189 | (val1_ op val2_),"%lu",(void)0) 190 | 191 | #define tt_want_ptr_op(a,op,b) \ 192 | tt_assert_test_type(a,b,#a" "#op" "#b,const void*, \ 193 | (val1_ op val2_),"%p",(void)0) 194 | 195 | #define tt_want_str_op(a,op,b) \ 196 | tt_assert_test_type(a,b,#a" "#op" "#b,const char *, \ 197 | (strcmp(val1_,val2_) op 0),"<%s>",(void)0) 198 | 199 | #define tt_want_mem_op(expr1, op, expr2, len) \ 200 | tt_assert_test_fmt_type(expr1,expr2,#expr1" "#op" "#expr2, \ 201 | const void *, \ 202 | (val1_ && val2_ && memcmp(val1_, val2_, len) op 0), \ 203 | char *, "%s", \ 204 | { print_ = tinytest_format_hex_(value_, (len)); }, \ 205 | { if (print_) free(print_); }, \ 206 | (void)0 \ 207 | ); 208 | 209 | #endif 210 | --------------------------------------------------------------------------------