1 /*********************************************************************************************************************************** 2 C Test Harness 3 ***********************************************************************************************************************************/ 4 #ifndef TEST_COMMON_HARNESS_H 5 #define TEST_COMMON_HARNESS_H 6 7 #include <inttypes.h> 8 9 #include "common/debug.h" 10 #include "common/error.h" 11 12 #include "common/harnessTest.intern.h" 13 14 /*********************************************************************************************************************************** 15 Constants 16 ***********************************************************************************************************************************/ 17 #define BOGUS_STR "BOGUS" 18 19 /*********************************************************************************************************************************** 20 Functions 21 ***********************************************************************************************************************************/ 22 // Begin a test if this function returns true, otherwise the user has skipped it 23 bool testBegin(const char *name); 24 25 // Read a file (max 256k) into a buffer 26 void hrnFileRead(const char *fileName, unsigned char *buffer, size_t bufferSize); 27 28 // Write a buffer to a file 29 void hrnFileWrite(const char *fileName, const unsigned char *buffer, size_t bufferSize); 30 31 // Diff two strings using command-line diff tool 32 const char *hrnDiff(const char *actual, const char *expected); 33 34 /*********************************************************************************************************************************** 35 Getters/Setters 36 ***********************************************************************************************************************************/ 37 // Time in MS 38 uint64_t testTimeMSec(void); 39 40 // Time in MS at the beginning of the test run (since testBegin() was called) 41 uint64_t testTimeMSecBegin(void); 42 43 // The path and name of the test executable 44 const char *testExe(void); 45 46 // Is this test running in a container? 47 bool testContainer(void); 48 49 // Get the 0-based index of the test. Useful for modifying resources like port numbers to avoid conflicts when running tests in 50 // parallel. 51 unsigned int testIdx(void); 52 53 /*********************************************************************************************************************************** 54 Test that an expected error is actually thrown and error when it isn't 55 ***********************************************************************************************************************************/ 56 #define TEST_ERROR(statement, errorTypeExpected, errorMessageExpected) \ 57 { \ 58 bool TEST_ERROR_catch = false; \ 59 \ 60 /* Set the line number for the current function in the stack trace */ \ 61 FUNCTION_HARNESS_STACK_TRACE_LINE_SET(__LINE__); \ 62 \ 63 hrnTestLogPrefix(__LINE__); \ 64 printf("expect %s: %s\n", errorTypeName(&errorTypeExpected), errorMessageExpected); \ 65 fflush(stdout); \ 66 \ 67 TRY_BEGIN() \ 68 { \ 69 statement; \ 70 } \ 71 CATCH_ANY() \ 72 { \ 73 TEST_ERROR_catch = true; \ 74 \ 75 if (strcmp(errorMessage(), errorMessageExpected) != 0 || errorType() != &errorTypeExpected) \ 76 THROW_FMT( \ 77 TestError, "EXPECTED %s: %s\n\n BUT GOT %s: %s\n\nTHROWN AT:\n%s", errorTypeName(&errorTypeExpected), \ 78 errorMessageExpected, errorName(), errorMessage(), errorStackTrace()); \ 79 } \ 80 TRY_END(); \ 81 \ 82 if (!TEST_ERROR_catch) \ 83 THROW_FMT( \ 84 TestError, "statement '%s' returned but error %s, '%s' was expected", #statement, errorTypeName(&errorTypeExpected), \ 85 errorMessageExpected); \ 86 \ 87 FUNCTION_HARNESS_STACK_TRACE_LINE_SET(0); \ 88 } 89 90 /*********************************************************************************************************************************** 91 Test error with a formatted expected message 92 ***********************************************************************************************************************************/ 93 #define TEST_ERROR_FMT(statement, errorTypeExpected, ...) \ 94 { \ 95 char TEST_ERROR_FMT_buffer[8192]; \ 96 \ 97 if (snprintf(TEST_ERROR_FMT_buffer, sizeof(TEST_ERROR_FMT_buffer), __VA_ARGS__) >= (int)sizeof(TEST_ERROR_FMT_buffer)) \ 98 THROW_FMT(AssertError, "error message needs more than the %zu characters available", sizeof(TEST_ERROR_FMT_buffer)); \ 99 \ 100 TEST_ERROR(statement, errorTypeExpected, TEST_ERROR_FMT_buffer); \ 101 } 102 103 /*********************************************************************************************************************************** 104 Output information about the test 105 ***********************************************************************************************************************************/ 106 #define TEST_RESULT_INFO(comment) \ 107 hrnTestLogPrefix(__LINE__); \ 108 puts(comment); \ 109 fflush(stdout); 110 111 /*********************************************************************************************************************************** 112 Test that a void statement returns and does not throw an error 113 ***********************************************************************************************************************************/ 114 #define TEST_RESULT_VOID(statement, comment) \ 115 { \ 116 TEST_RESULT_INFO(comment); \ 117 hrnTestResultBegin(#statement, false); \ 118 statement; \ 119 hrnTestResultEnd(); \ 120 } 121 122 /*********************************************************************************************************************************** 123 Test that a statement does not error and assign it to the specified variable if not 124 ***********************************************************************************************************************************/ 125 #define TEST_ASSIGN(lValue, statement, comment) \ 126 { \ 127 TEST_RESULT_INFO(comment); \ 128 hrnTestResultBegin(#statement, true); \ 129 lValue = statement; \ 130 hrnTestResultEnd(); \ 131 } 132 133 /*********************************************************************************************************************************** 134 Macros to compare results of common data types 135 ***********************************************************************************************************************************/ 136 #define TEST_RESULT_BOOL_PARAM(statement, expected, comment) \ 137 do \ 138 { \ 139 TEST_RESULT_INFO(comment); \ 140 hrnTestResultBegin(#statement, true); \ 141 hrnTestResultBool(statement, expected); \ 142 } \ 143 while (0) 144 145 #define TEST_RESULT_BOOL(statement, expected, comment) \ 146 TEST_RESULT_BOOL_PARAM(statement, expected, comment) 147 148 #define TEST_RESULT_DOUBLE_PARAM(statement, expected, comment) \ 149 do \ 150 { \ 151 TEST_RESULT_INFO(comment); \ 152 hrnTestResultBegin(#statement, true); \ 153 hrnTestResultDouble(statement, expected); \ 154 } \ 155 while (0) 156 157 #define TEST_RESULT_DOUBLE(statement, expected, comment) \ 158 TEST_RESULT_DOUBLE_PARAM(statement, expected, comment) 159 160 #define TEST_RESULT_INT_PARAM(statement, expected, operation, comment) \ 161 do \ 162 { \ 163 TEST_RESULT_INFO(comment); \ 164 hrnTestResultBegin(#statement, true); \ 165 hrnTestResultInt64(statement, expected, operation); \ 166 } \ 167 while (0) 168 169 #define TEST_RESULT_INT(statement, expected, comment) \ 170 TEST_RESULT_INT_PARAM(statement, expected, harnessTestResultOperationEq, comment) 171 #define TEST_RESULT_INT_NE(statement, expected, comment) \ 172 TEST_RESULT_INT_PARAM(statement, expected, harnessTestResultOperationNe, comment) 173 174 #define TEST_RESULT_PTR_PARAM(statement, expected, operation, comment) \ 175 do \ 176 { \ 177 TEST_RESULT_INFO(comment); \ 178 hrnTestResultBegin(#statement, true); \ 179 hrnTestResultPtr(statement, expected, operation); \ 180 } \ 181 while (0) 182 183 // Compare raw pointers. When checking for NULL use the type-specific macro when available, e.g. TEST_RESULT_STR(). This is more 184 // type-safe and makes it clearer what is being tested. 185 #define TEST_RESULT_PTR(statement, expected, comment) \ 186 TEST_RESULT_PTR_PARAM(statement, expected, harnessTestResultOperationEq, comment) 187 #define TEST_RESULT_PTR_NE(statement, expected, comment) \ 188 TEST_RESULT_PTR_PARAM(statement, expected, harnessTestResultOperationNe, comment) 189 190 #define TEST_RESULT_Z_PARAM(statement, expected, operation, comment) \ 191 do \ 192 { \ 193 TEST_RESULT_INFO(comment); \ 194 hrnTestResultBegin(#statement, true); \ 195 hrnTestResultZ(statement, expected, operation); \ 196 } \ 197 while (0) 198 199 #define TEST_RESULT_Z(statement, expected, comment) \ 200 TEST_RESULT_Z_PARAM(statement, expected, harnessTestResultOperationEq, comment) 201 #define TEST_RESULT_Z_NE(statement, expected, comment) \ 202 TEST_RESULT_Z_PARAM(statement, expected, harnessTestResultOperationNe, comment) 203 204 #define TEST_RESULT_STR(statement, resultExpected, comment) \ 205 TEST_RESULT_Z(strZNull(statement), strZNull(resultExpected), comment) 206 #define TEST_RESULT_STR_Z(statement, resultExpected, comment) \ 207 TEST_RESULT_Z(strZNull(statement), resultExpected, comment) 208 #define TEST_RESULT_Z_STR(statement, resultExpected, comment) \ 209 TEST_RESULT_Z(statement, strZNull(resultExpected), comment) 210 211 // Compare a string list to a \n delimited string 212 #define TEST_RESULT_STRLST_Z(statement, resultExpected, comment) \ 213 do \ 214 { \ 215 TEST_RESULT_INFO(comment); \ 216 hrnTestResultBegin(#statement, true); \ 217 hrnTestResultStringList(statement, resultExpected, harnessTestResultOperationEq); \ 218 } \ 219 while (0) 220 221 #define TEST_RESULT_STRLST_STR(statement, resultExpected, comment) \ 222 TEST_RESULT_STRLST_Z(statement, strZNull(resultExpected), comment) 223 224 #define TEST_RESULT_UINT_PARAM(statement, expected, operation, comment) \ 225 do \ 226 { \ 227 TEST_RESULT_INFO(comment); \ 228 hrnTestResultBegin(#statement, true); \ 229 hrnTestResultUInt64(statement, expected, operation); \ 230 } \ 231 while (0) 232 233 #define TEST_RESULT_UINT(statement, expected, comment) \ 234 TEST_RESULT_UINT_PARAM(statement, expected, harnessTestResultOperationEq, comment) 235 236 #define TEST_RESULT_UINT_INT_PARAM(statement, expected, operation, comment) \ 237 do \ 238 { \ 239 TEST_RESULT_INFO(comment); \ 240 hrnTestResultBegin(#statement, true); \ 241 hrnTestResultUInt64Int64(statement, expected, operation); \ 242 } \ 243 while (0) 244 245 #define TEST_RESULT_UINT_INT(statement, expected, comment) \ 246 TEST_RESULT_UINT_INT_PARAM(statement, expected, harnessTestResultOperationEq, comment) 247 248 /*********************************************************************************************************************************** 249 System call harness 250 ***********************************************************************************************************************************/ 251 #define HRN_SYSTEM(command) \ 252 do \ 253 { \ 254 int TEST_SYSTEM_FMT_result = system(command); \ 255 \ 256 if (TEST_SYSTEM_FMT_result != 0) \ 257 { \ 258 THROW_FMT( \ 259 AssertError, "SYSTEM COMMAND: %s\n\nFAILED WITH CODE %d\n\nTHROWN AT:\n%s", command, TEST_SYSTEM_FMT_result, \ 260 errorStackTrace()); \ 261 } \ 262 } while (0) 263 264 #define HRN_SYSTEM_FMT(...) \ 265 do \ 266 { \ 267 char TEST_SYSTEM_FMT_buffer[8192]; \ 268 \ 269 if (snprintf(TEST_SYSTEM_FMT_buffer, sizeof(TEST_SYSTEM_FMT_buffer), __VA_ARGS__) >= (int)sizeof(TEST_SYSTEM_FMT_buffer)) \ 270 THROW_FMT(AssertError, "command needs more than the %zu characters available", sizeof(TEST_SYSTEM_FMT_buffer)); \ 271 \ 272 HRN_SYSTEM(TEST_SYSTEM_FMT_buffer); \ 273 } while (0) 274 275 /*********************************************************************************************************************************** 276 Test log result 277 ***********************************************************************************************************************************/ 278 #define TEST_RESULT_LOG(expected) \ 279 do \ 280 { \ 281 TRY_BEGIN() \ 282 { \ 283 harnessLogResult(expected); \ 284 } \ 285 CATCH_ANY() \ 286 { \ 287 THROW_FMT(AssertError, "LOG RESULT FAILED WITH:\n%s", errorMessage()); \ 288 } \ 289 TRY_END(); \ 290 } while (0) 291 292 #define TEST_RESULT_LOG_FMT(...) \ 293 do \ 294 { \ 295 char TEST_RESULT_LOG_FMT_buffer[65536]; \ 296 \ 297 if (snprintf(TEST_RESULT_LOG_FMT_buffer, sizeof(TEST_RESULT_LOG_FMT_buffer), __VA_ARGS__) >= \ 298 (int)sizeof(TEST_RESULT_LOG_FMT_buffer)) \ 299 { \ 300 THROW_FMT( \ 301 AssertError, "expected result needs more than the %zu characters available", sizeof(TEST_RESULT_LOG_FMT_buffer)); \ 302 } \ 303 \ 304 TEST_RESULT_LOG(TEST_RESULT_LOG_FMT_buffer); \ 305 } while (0) 306 307 /*********************************************************************************************************************************** 308 Logging macros 309 ***********************************************************************************************************************************/ 310 #define TEST_LOG(message) \ 311 do \ 312 { \ 313 hrnTestLogPrefix(__LINE__); \ 314 printf("%s\n", message); \ 315 fflush(stdout); \ 316 } while (0) 317 318 #define TEST_LOG_FMT(format, ...) \ 319 do \ 320 { \ 321 hrnTestLogPrefix(__LINE__); \ 322 printf(format "\n", __VA_ARGS__); \ 323 fflush(stdout); \ 324 } while (0) 325 326 /*********************************************************************************************************************************** 327 Test title macro 328 ***********************************************************************************************************************************/ 329 #define TEST_TITLE(message) \ 330 do \ 331 { \ 332 hrnTestLogTitle(__LINE__); \ 333 printf(" %s\n", message); \ 334 fflush(stdout); \ 335 } while (0) 336 337 #define TEST_TITLE_FMT(format, ...) \ 338 do \ 339 { \ 340 hrnTestLogTitle(__LINE__); \ 341 printf(" " format "\n", __VA_ARGS__); \ 342 fflush(stdout); \ 343 } while (0) 344 345 /*********************************************************************************************************************************** 346 Is this a 64-bit system? If not then it is 32-bit since 16-bit systems are not supported. 347 ***********************************************************************************************************************************/ 348 #define TEST_64BIT() \ 349 (sizeof(size_t) == 8) 350 351 /*********************************************************************************************************************************** 352 Is this a big-endian system? 353 ***********************************************************************************************************************************/ 354 #define TEST_BIG_ENDIAN() (!*(unsigned char *)&(uint16_t){1}) 355 356 #endif 357