tinytest_demo.c 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  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. /* Welcome to the example file for tinytest! I'll show you how to set up
  26. * some simple and not-so-simple testcases. */
  27. /* Make sure you include these headers. */
  28. #include "tinytest.h"
  29. #include "tinytest_macros.h"
  30. #include <stdio.h>
  31. #include <stdlib.h>
  32. #include <string.h>
  33. #include <errno.h>
  34. #include <time.h>
  35. #ifndef _WIN32
  36. #include <unistd.h>
  37. #endif
  38. /* ============================================================ */
  39. /* First, let's see if strcmp is working. (All your test cases should be
  40. * functions declared to take a single void * as an argument.) */
  41. void
  42. test_strcmp(void *data)
  43. {
  44. (void)data; /* This testcase takes no data. */
  45. /* Let's make sure the empty string is equal to itself */
  46. if (strcmp("","")) {
  47. /* This macro tells tinytest to stop the current test
  48. * and go straight to the "end" label. */
  49. tt_abort_msg("The empty string was not equal to itself");
  50. }
  51. /* Pretty often, calling tt_abort_msg to indicate failure is more
  52. heavy-weight than you want. Instead, just say: */
  53. tt_assert(strcmp("testcase", "testcase") == 0);
  54. /* Occasionally, you don't want to stop the current testcase just
  55. because a single assertion has failed. In that case, use
  56. tt_want: */
  57. tt_want(strcmp("tinytest", "testcase") > 0);
  58. /* You can use the tt_*_op family of macros to compare values and to
  59. fail unless they have the relationship you want. They produce
  60. more useful output than tt_assert, since they display the actual
  61. values of the failing things.
  62. Fail unless strcmp("abc, "abc") == 0 */
  63. tt_int_op(strcmp("abc", "abc"), ==, 0);
  64. /* Fail unless strcmp("abc, "abcd") is less than 0 */
  65. tt_int_op(strcmp("abc", "abcd"), < , 0);
  66. /* Incidentally, there's a test_str_op that uses strcmp internally. */
  67. tt_str_op("abc", <, "abcd");
  68. /* Every test-case function needs to finish with an "end:"
  69. label and (optionally) code to clean up local variables. */
  70. end:
  71. ;
  72. }
  73. /* ============================================================ */
  74. /* Now let's mess with setup and teardown functions! These are handy if
  75. you have a bunch of tests that all need a similar environment, and you
  76. want to reconstruct that environment freshly for each one. */
  77. /* First you declare a type to hold the environment info, and functions to
  78. set it up and tear it down. */
  79. struct data_buffer {
  80. /* We're just going to have couple of character buffer. Using
  81. setup/teardown functions is probably overkill for this case.
  82. You could also do file descriptors, complicated handles, temporary
  83. files, etc. */
  84. char buffer1[512];
  85. char buffer2[512];
  86. };
  87. /* The setup function needs to take a const struct testcase_t and return
  88. void* */
  89. void *
  90. setup_data_buffer(const struct testcase_t *testcase)
  91. {
  92. struct data_buffer *db = malloc(sizeof(struct data_buffer));
  93. /* If you had a complicated set of setup rules, you might behave
  94. differently here depending on testcase->flags or
  95. testcase->setup_data or even or testcase->name. */
  96. /* Returning a NULL here would mean that we couldn't set up for this
  97. test, so we don't need to test db for null. */
  98. return db;
  99. }
  100. /* The clean function deallocates storage carefully and returns true on
  101. success. */
  102. int
  103. clean_data_buffer(const struct testcase_t *testcase, void *ptr)
  104. {
  105. struct data_buffer *db = ptr;
  106. if (db) {
  107. free(db);
  108. return 1;
  109. }
  110. return 0;
  111. }
  112. /* Finally, declare a testcase_setup_t with these functions. */
  113. struct testcase_setup_t data_buffer_setup = {
  114. setup_data_buffer, clean_data_buffer
  115. };
  116. /* Now let's write our test. */
  117. void
  118. test_memcpy(void *ptr)
  119. {
  120. /* This time, we use the argument. */
  121. struct data_buffer *db = ptr;
  122. /* We'll also introduce a local variable that might need cleaning up. */
  123. char *mem = NULL;
  124. /* Let's make sure that memcpy does what we'd like. */
  125. strcpy(db->buffer1, "String 0");
  126. memcpy(db->buffer2, db->buffer1, sizeof(db->buffer1));
  127. tt_str_op(db->buffer1, ==, db->buffer2);
  128. /* This one works if there's an internal NUL. */
  129. tt_mem_op(db->buffer1, <, db->buffer2, sizeof(db->buffer1));
  130. /* Now we've allocated memory that's referenced by a local variable.
  131. The end block of the function will clean it up. */
  132. mem = strdup("Hello world.");
  133. tt_assert(mem);
  134. /* Another rather trivial test. */
  135. tt_str_op(db->buffer1, !=, mem);
  136. end:
  137. /* This time our end block has something to do. */
  138. if (mem)
  139. free(mem);
  140. }
  141. void
  142. test_timeout(void *ptr)
  143. {
  144. time_t t1, t2;
  145. (void)ptr;
  146. t1 = time(NULL);
  147. #ifdef _WIN32
  148. Sleep(5000);
  149. #else
  150. sleep(5);
  151. #endif
  152. t2 = time(NULL);
  153. tt_int_op(t2-t1, >=, 4);
  154. tt_int_op(t2-t1, <=, 6);
  155. end:
  156. ;
  157. }
  158. /* ============================================================ */
  159. /* Now we need to make sure that our tests get invoked. First, you take
  160. a bunch of related tests and put them into an array of struct testcase_t.
  161. */
  162. struct testcase_t demo_tests[] = {
  163. /* Here's a really simple test: it has a name you can refer to it
  164. with, and a function to invoke it. */
  165. { "strcmp", test_strcmp, },
  166. /* The second test has a flag, "TT_FORK", to make it run in a
  167. subprocess, and a pointer to the testcase_setup_t that configures
  168. its environment. */
  169. { "memcpy", test_memcpy, TT_FORK, &data_buffer_setup },
  170. /* This flag is off-by-default, since it takes a while to run. You
  171. * can enable it manually by passing +demo/timeout at the command line.*/
  172. { "timeout", test_timeout, TT_OFF_BY_DEFAULT },
  173. /* The array has to end with END_OF_TESTCASES. */
  174. END_OF_TESTCASES
  175. };
  176. /* Next, we make an array of testgroups. This is mandatory. Unlike more
  177. heavy-duty testing frameworks, groups can't nest. */
  178. struct testgroup_t groups[] = {
  179. /* Every group has a 'prefix', and an array of tests. That's it. */
  180. { "demo/", demo_tests },
  181. END_OF_GROUPS
  182. };
  183. /* We can also define test aliases. These can be used for types of tests that
  184. * cut across groups. */
  185. const char *alltests[] = { "+..", NULL };
  186. const char *slowtests[] = { "+demo/timeout", NULL };
  187. struct testlist_alias_t aliases[] = {
  188. { "ALL", alltests },
  189. { "SLOW", slowtests },
  190. END_OF_ALIASES
  191. };
  192. int
  193. main(int c, const char **v)
  194. {
  195. /* Finally, just call tinytest_main(). It lets you specify verbose
  196. or quiet output with --verbose and --quiet. You can list
  197. specific tests:
  198. tinytest-demo demo/memcpy
  199. or use a ..-wildcard to select multiple tests with a common
  200. prefix:
  201. tinytest-demo demo/..
  202. If you list no tests, you get them all by default, so that
  203. "tinytest-demo" and "tinytest-demo .." mean the same thing.
  204. */
  205. tinytest_set_aliases(aliases);
  206. return tinytest_main(c, v, groups);
  207. }