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