1 /* 2 * sput - Simple, Portable Unit Testing Framework for C/C++ v1.2.0 3 * 4 * Copyright (c) 2011-2012 Lingua-Systems Software GmbH 5 * 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions are 10 * met: 11 * 12 * * Redistributions of source code must retain the above copyright notice, 13 * this list of conditions and the following disclaimer. 14 * * Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 22 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 23 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 25 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 26 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 27 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 32 #ifndef HAVE_SPUT_H 33 #define HAVE_SPUT_H 34 35 36 #ifdef __cplusplus 37 extern "C" { 38 #endif 39 40 41 #include <stdio.h> 42 #include <stdlib.h> 43 #include <string.h> 44 #include <time.h> 45 46 47 /* ======================================================================= 48 * definitions 49 * ======================================================================= */ 50 51 #define SPUT_VERSION_MAJOR 1 52 #define SPUT_VERSION_MINOR 2 53 #define SPUT_VERSION_PATCH 0 54 #define SPUT_VERSION_STRING "1.2.0" 55 56 #define SPUT_DEFAULT_SUITE_NAME "Unlabeled Suite" 57 #define SPUT_DEFAULT_CHECK_NAME "Unlabeled Check" 58 59 #define SPUT_INITIALIZED 0x06 /* ACK */ 60 61 62 /* ======================================================================= 63 * sput global variable 64 * ======================================================================= */ 65 66 static struct 67 { 68 FILE *out; 69 char initialized; 70 71 struct 72 { 73 unsigned long checks; 74 unsigned long suites; 75 unsigned long ok; 76 unsigned long nok; 77 } overall; 78 79 struct 80 { 81 const char *name; 82 unsigned long nr; 83 unsigned long checks; 84 unsigned long ok; 85 unsigned long nok; 86 } suite; 87 88 struct 89 { 90 const char *name; 91 unsigned long nr; 92 } test; 93 94 struct 95 { 96 const char *name; 97 const char *cond; 98 const char *type; 99 unsigned long line; 100 } check; 101 102 struct 103 { 104 time_t start; 105 time_t end; 106 } time; 107 } __sput; 108 109 110 /* ======================================================================= 111 * sput internal macros 112 * ======================================================================= */ 113 114 #define _sput_die_unless_initialized() \ 115 if (__sput.initialized != SPUT_INITIALIZED) \ 116 { \ 117 fputs("sput_start_testing() omitted\n", stderr); \ 118 exit(EXIT_FAILURE); \ 119 } 120 121 122 #define _sput_die_unless_suite_set() \ 123 if (! __sput.suite.name) \ 124 { \ 125 fputs("sput_enter_suite() omitted\n", __sput.out); \ 126 exit(EXIT_FAILURE); \ 127 } 128 129 130 #define _sput_die_unless_test_set() \ 131 if (! __sput.test.name) \ 132 { \ 133 fputs("sput_run_test() omitted\n", __sput.out); \ 134 exit(EXIT_FAILURE); \ 135 } 136 137 138 #define _sput_check_failed() \ 139 { \ 140 _sput_die_unless_initialized(); \ 141 _sput_die_unless_suite_set(); \ 142 \ 143 __sput.suite.nok++; \ 144 \ 145 fprintf(__sput.out, \ 146 "[%lu:%lu] %s:#%lu \"%s\" FAIL\n" \ 147 "! Type: %s\n" \ 148 "! Condition: %s\n" \ 149 "! Line: %lu\n", \ 150 __sput.suite.nr, __sput.suite.checks, __sput.test.name, \ 151 __sput.test.nr, __sput.check.name, __sput.check.type, \ 152 __sput.check.cond, __sput.check.line); \ 153 } 154 155 156 #define _sput_check_succeeded() \ 157 { \ 158 _sput_die_unless_initialized(); \ 159 _sput_die_unless_suite_set(); \ 160 \ 161 __sput.suite.ok++; \ 162 \ 163 fprintf(__sput.out, \ 164 "[%lu:%lu] %s:#%lu \"%s\" pass\n", \ 165 __sput.suite.nr, __sput.suite.checks, \ 166 __sput.test.name, \ 167 __sput.test.nr, \ 168 __sput.check.name); \ 169 } 170 171 172 /* ======================================================================= 173 * user macros 174 * ======================================================================= */ 175 176 #define sput_start_testing() \ 177 do { \ 178 memset(&__sput, 0, sizeof(__sput)); \ 179 \ 180 __sput.out = stdout; \ 181 __sput.time.start = time(NULL); \ 182 __sput.initialized = SPUT_INITIALIZED; \ 183 } while (0) 184 185 186 #define sput_leave_suite() \ 187 do { \ 188 float failp = 0.0f; \ 189 \ 190 _sput_die_unless_initialized(); \ 191 _sput_die_unless_suite_set(); \ 192 \ 193 failp = __sput.suite.checks ? (float) \ 194 ((__sput.suite.nok * 100.0) / __sput.suite.checks) : \ 195 0.0f; \ 196 \ 197 fprintf(__sput.out, \ 198 "\n--> %lu check(s), %lu ok, %lu failed (%.2f%%)\n", \ 199 __sput.suite.checks, __sput.suite.ok, __sput.suite.nok, \ 200 failp); \ 201 \ 202 __sput.overall.checks += __sput.suite.checks; \ 203 __sput.overall.ok += __sput.suite.ok; \ 204 __sput.overall.nok += __sput.suite.nok; \ 205 \ 206 memset(&__sput.suite, 0, sizeof(__sput.suite)); \ 207 } while (0) 208 209 210 #define sput_get_return_value() \ 211 (__sput.overall.nok > 0 ? EXIT_FAILURE : EXIT_SUCCESS) 212 213 214 #define sput_enter_suite(_name) \ 215 do { \ 216 _sput_die_unless_initialized(); \ 217 \ 218 if (__sput.suite.name) \ 219 { \ 220 sput_leave_suite(); \ 221 } \ 222 \ 223 __sput.suite.name = _name ? _name : SPUT_DEFAULT_SUITE_NAME; \ 224 \ 225 __sput.suite.nr = ++__sput.overall.suites; \ 226 \ 227 fprintf(__sput.out, "\n== Entering suite #%lu, \"%s\" ==\n\n", \ 228 __sput.suite.nr, __sput.suite.name); \ 229 } while (0) 230 231 232 #define sput_finish_testing() \ 233 do { \ 234 float failp = 0.0f; \ 235 \ 236 _sput_die_unless_initialized(); \ 237 \ 238 if (__sput.suite.name) \ 239 { \ 240 sput_leave_suite(); \ 241 } \ 242 \ 243 failp = __sput.overall.checks ? (float) \ 244 ((__sput.overall.nok * 100.0) / __sput.overall.checks) : \ 245 0.0f; \ 246 \ 247 __sput.time.end = time(NULL); \ 248 \ 249 fprintf(__sput.out, \ 250 "\n==> %lu check(s) in %lu suite(s) finished after %.2f " \ 251 "second(s),\n" \ 252 " %lu succeeded, %lu failed (%.2f%%)\n" \ 253 "\n[%s]\n", \ 254 __sput.overall.checks, __sput.overall.suites, \ 255 difftime(__sput.time.end, __sput.time.start), \ 256 __sput.overall.ok, __sput.overall.nok, failp, \ 257 (sput_get_return_value() == EXIT_SUCCESS) ? \ 258 "SUCCESS" : "FAILURE"); \ 259 } while (0) 260 261 262 #define sput_set_output_stream(_fp) \ 263 do { \ 264 __sput.out = _fp ? _fp : stdout; \ 265 } while (0) 266 267 268 #define sput_fail_if(_cond, _name) \ 269 do { \ 270 _sput_die_unless_initialized(); \ 271 _sput_die_unless_suite_set(); \ 272 _sput_die_unless_test_set(); \ 273 \ 274 __sput.check.name = _name ? _name : SPUT_DEFAULT_CHECK_NAME; \ 275 __sput.check.line = __LINE__; \ 276 __sput.check.cond = #_cond; \ 277 __sput.check.type = "fail-if"; \ 278 __sput.test.nr++; \ 279 __sput.suite.checks++; \ 280 \ 281 if ((_cond)) \ 282 { \ 283 _sput_check_failed(); \ 284 } \ 285 else \ 286 { \ 287 _sput_check_succeeded(); \ 288 } \ 289 } while (0) 290 291 292 #define sput_fail_unless(_cond, _name) \ 293 do { \ 294 _sput_die_unless_initialized(); \ 295 _sput_die_unless_suite_set(); \ 296 _sput_die_unless_test_set(); \ 297 \ 298 __sput.check.name = _name ? _name : SPUT_DEFAULT_CHECK_NAME; \ 299 __sput.check.line = __LINE__; \ 300 __sput.check.cond = #_cond; \ 301 __sput.check.type = "fail-unless"; \ 302 __sput.test.nr++; \ 303 __sput.suite.checks++; \ 304 \ 305 if (! (_cond)) \ 306 { \ 307 _sput_check_failed(); \ 308 } \ 309 else \ 310 { \ 311 _sput_check_succeeded(); \ 312 } \ 313 } while (0) 314 315 316 #define sput_run_test(_func) \ 317 do { \ 318 _sput_die_unless_initialized(); \ 319 _sput_die_unless_suite_set(); \ 320 \ 321 memset(&__sput.test, 0, sizeof(__sput.test)); \ 322 __sput.test.name = #_func; \ 323 \ 324 _func(); \ 325 } while (0) 326 327 328 #ifdef __cplusplus 329 } 330 #endif 331 332 333 #endif /* HAVE_SPUT_H */ 334 335 336 /* 337 vim: sts=4 sw=4 ts=4 ai et ft=c 338 */ 339