1 /******************************************************************** 2 * COPYRIGHT: 3 * Copyright (c) 2003-2007, International Business Machines Corporation and 4 * others. All Rights Reserved. 5 ********************************************************************/ 6 /* 7 * File tracetst.c 8 * 9 */ 10 11 12 #include "unicode/utypes.h" 13 #include "unicode/utrace.h" 14 #include "unicode/uclean.h" 15 #include "unicode/uchar.h" 16 #include "unicode/ures.h" 17 #include "unicode/ucnv.h" 18 #include "cintltst.h" 19 #include <stdlib.h> 20 #include <stdio.h> 21 #include <string.h> 22 23 /* We define the following to always test tracing, even when it's off in the library. */ 24 #if U_ENABLE_TRACING 25 #define ENABLE_TRACING_ORIG_VAL 1 26 #else 27 #define ENABLE_TRACING_ORIG_VAL 0 28 #endif 29 #undef U_ENABLE_TRACING 30 #define U_ENABLE_TRACING 1 31 #include "utracimp.h" 32 33 34 static void TestTraceAPI(void); 35 36 37 void 38 addUTraceTest(TestNode** root); 39 40 void 41 addUTraceTest(TestNode** root) 42 { 43 addTest(root, &TestTraceAPI, "tsutil/TraceTest/TestTraceAPI" ); 44 } 45 46 47 /* 48 * Macro for assert style tests. 49 */ 50 #define TEST_ASSERT(expr) \ 51 if (!(expr)) { \ 52 log_err("FAILED Assertion \"" #expr "\" at %s:%d.\n", __FILE__, __LINE__); \ 53 } 54 55 56 /* 57 * test_format. Helper function for checking the results of a formatting 58 * operation. Executes the format op and compares actual 59 * results with the expected results. 60 * 61 * params: format: the format to be applied. 62 * bufCap buffer size to pass to formatter. 63 * indent: indent value to give to formatter 64 * result expected result. Do not truncate for short bufCap - 65 * this function will do it. 66 * line __LINE__, so we can report where failure happened. 67 * ... variable args to pass to formatter 68 * 69 */ 70 static void test_format(const char *format, int32_t bufCap, int32_t indent, 71 const char *result, int32_t line, ...) { 72 int32_t len; 73 va_list args; 74 char buf[300]; 75 char expectedResult[300]; 76 77 /* check that local buffers are big enough for the test case */ 78 if (sizeof(buf) <= bufCap) { 79 log_err("At file:line %s:%d, requested bufCap too large.\n"); 80 return; 81 } 82 if (strlen(result) >= sizeof(expectedResult)) { 83 log_err("At file:line %s:%d, expected result too large.\n"); 84 return; 85 } 86 87 /* Guarantee a nul term if buffer is smaller than output */ 88 strcpy(expectedResult, result); 89 expectedResult[bufCap] = 0; 90 91 /* run the formatter */ 92 va_start(args, line); 93 memset(buf, 0, sizeof(buf)); 94 len = utrace_vformat(buf, bufCap, indent, format, args); 95 96 /* Check results. */ 97 if (strcmp(expectedResult, buf) != 0) { 98 log_err("At file:line %s:%d Expected \"%s\", got \"%s\" \n", 99 __FILE__, line, expectedResult, buf); 100 } 101 va_end(args); 102 } 103 104 105 /* 106 * define trace functions for use in this test. 107 */ 108 static int gTraceEntryCount; 109 static int gTraceExitCount; 110 static int gTraceDataCount; 111 static UBool gFnNameError = FALSE; 112 static UBool gFnFormatError = FALSE; 113 114 static void U_CALLCONV testTraceEntry(const void *context, int32_t fnNumber) { 115 const char *fnName; 116 const char *bogusFnName; 117 118 gTraceEntryCount++; 119 120 /* Verify that a name is available for the fnNumber passed to us */ 121 bogusFnName = utrace_functionName(-1); 122 fnName = utrace_functionName(fnNumber); 123 if (strcmp(fnName, bogusFnName) == 0) { 124 gFnNameError = TRUE; 125 } 126 /* printf("%s() Enter\n", fnName); */ 127 128 } 129 130 static void U_CALLCONV testTraceExit(const void *context, int32_t fnNumber, 131 const char *fmt, va_list args) { 132 char buf[1000]; 133 const char *fnName; 134 const char *bogusFnName; 135 136 gTraceExitCount++; 137 138 /* Verify that a name is available for the fnNumber passed to us */ 139 bogusFnName = utrace_functionName(-1); 140 fnName = utrace_functionName(fnNumber); 141 if (strcmp(fnName, bogusFnName) == 0) { 142 gFnNameError = TRUE; 143 } 144 145 /* Verify that the format can be used. */ 146 buf[0] = 0; 147 utrace_vformat(buf, sizeof(buf), 0, fmt, args); 148 if (strlen(buf) == 0) { 149 gFnFormatError = TRUE; 150 } 151 152 /* printf("%s() %s\n", fnName, buf); */ 153 154 } 155 156 static void U_CALLCONV testTraceData(const void *context, int32_t fnNumber, int32_t level, 157 const char *fmt, va_list args) { 158 char buf[1000]; 159 const char *fnName; 160 const char *bogusFnName; 161 162 gTraceDataCount++; 163 164 /* Verify that a name is available for the fnNumber passed to us */ 165 bogusFnName = utrace_functionName(-1); 166 fnName = utrace_functionName(fnNumber); 167 if (strcmp(fnName, bogusFnName) == 0) { 168 gFnNameError = TRUE; 169 } 170 171 /* Verify that the format can be used. */ 172 buf[0] = 0; 173 utrace_vformat(buf, sizeof(buf), 0, fmt, args); 174 if (strlen(buf) == 0) { 175 gFnFormatError = TRUE; 176 } 177 178 /* printf(" %s() %s\n", fnName, buf); */ 179 } 180 181 static UConverter * psuedo_ucnv_open(const char *name, UErrorCode * err) 182 { 183 UTRACE_ENTRY_OC(UTRACE_UCNV_LOAD); 184 185 UTRACE_DATA2(UTRACE_OPEN_CLOSE, "error code is %s for %s", u_errorName(*err), name); 186 187 UTRACE_EXIT_PTR_STATUS(NULL, *err); 188 return NULL; 189 } 190 static void psuedo_ucnv_close(UConverter * cnv) 191 { 192 UTRACE_ENTRY_OC(UTRACE_UCNV_UNLOAD); 193 UTRACE_DATA1(UTRACE_OPEN_CLOSE, "unload converter %p", cnv); 194 UTRACE_EXIT_VALUE((int32_t)TRUE); 195 } 196 197 198 /* 199 * TestTraceAPI 200 */ 201 static void TestTraceAPI() { 202 203 204 UTraceEntry *originalTEntryFunc; 205 UTraceExit *originalTExitFunc; 206 UTraceData *originalTDataFunc; 207 const void *originalTContext; 208 int32_t originalLevel; 209 210 /* 211 * Save the original tracing state so that we can restore it after the test. 212 */ 213 utrace_getFunctions(&originalTContext, &originalTEntryFunc, &originalTExitFunc, 214 &originalTDataFunc); 215 originalLevel = utrace_getLevel(); 216 217 218 /* verify that set/get of tracing functions returns what was set. */ 219 { 220 UTraceEntry *e; 221 UTraceExit *x; 222 UTraceData *d; 223 const void *context; 224 const void *newContext = (const char *)originalTContext + 1; 225 226 TEST_ASSERT(originalTEntryFunc != testTraceEntry); 227 TEST_ASSERT(originalTExitFunc != testTraceExit); 228 TEST_ASSERT(originalTDataFunc != testTraceData); 229 230 utrace_setFunctions(newContext, testTraceEntry, testTraceExit, testTraceData); 231 utrace_getFunctions(&context, &e, &x, &d); 232 TEST_ASSERT(e == testTraceEntry); 233 TEST_ASSERT(x == testTraceExit); 234 TEST_ASSERT(d == testTraceData); 235 TEST_ASSERT(context == newContext); 236 } 237 238 /* verify that set/get level work as a pair, and that the level 239 * identifiers all exist. 240 */ 241 242 { 243 int32_t level; 244 245 utrace_setLevel(UTRACE_OFF); 246 level = utrace_getLevel(); 247 TEST_ASSERT(level==UTRACE_OFF); 248 utrace_setLevel(UTRACE_VERBOSE); 249 level = utrace_getLevel(); 250 TEST_ASSERT(level==UTRACE_VERBOSE); 251 utrace_setLevel(UTRACE_ERROR); 252 utrace_setLevel(UTRACE_WARNING); 253 utrace_setLevel(UTRACE_OPEN_CLOSE); 254 utrace_setLevel(UTRACE_INFO); 255 } 256 257 /* 258 * Open and close a converter with tracing enabled. 259 * Verify that our tracing callback functions get called. 260 */ 261 { 262 UErrorCode status = U_ZERO_ERROR; 263 UConverter *cnv; 264 265 gTraceEntryCount = 0; 266 gTraceExitCount = 0; 267 gTraceDataCount = 0; 268 gFnNameError = FALSE; 269 gFnFormatError = FALSE; 270 utrace_setLevel(UTRACE_OPEN_CLOSE); 271 #if ENABLE_TRACING_ORIG_VAL 272 cnv = ucnv_open(NULL, &status); 273 TEST_ASSERT(U_SUCCESS(status)); 274 ucnv_close(cnv); 275 #else 276 cnv = psuedo_ucnv_open(NULL, &status); 277 TEST_ASSERT(U_SUCCESS(status)); 278 psuedo_ucnv_close(cnv); 279 #endif 280 TEST_ASSERT(gTraceEntryCount > 0); 281 TEST_ASSERT(gTraceExitCount > 0); 282 TEST_ASSERT(gTraceDataCount > 0); 283 TEST_ASSERT(gFnNameError == FALSE); 284 TEST_ASSERT(gFnFormatError == FALSE); 285 } 286 287 288 289 /* 290 * trace data formatter operation. 291 */ 292 { 293 UChar s1[] = {0x41fe, 0x42, 0x43, 00}; 294 const char *a1[] = {"s1", "s2", "s3"}; 295 void *ptr; 296 297 test_format("hello, world", 50, 0, "hello, world", __LINE__); 298 test_format("hello, world", 50, 4, " hello, world", __LINE__); 299 test_format("hello, world", 3, 0, "hello, world", __LINE__); 300 301 test_format("a character %c", 50, 0, "a character x", __LINE__, 'x'); 302 test_format("a string %s ", 50, 0, "a string hello ", __LINE__, "hello"); 303 test_format("uchars %S ", 50, 0, "uchars 41fe 0042 0043 0000 ", __LINE__, s1, -1); 304 test_format("uchars %S ", 50, 0, "uchars 41fe 0042 ", __LINE__, s1, 2); 305 306 test_format("a byte %b--", 50, 0, "a byte dd--", __LINE__, 0xdd); 307 test_format("a 16 bit val %h", 50, 0, "a 16 bit val 1234", __LINE__, 0x1234); 308 test_format("a 32 bit val %d...", 50, 0, "a 32 bit val 6789abcd...", __LINE__, 0x6789abcd); 309 test_format("a 64 bit val %l", 50, 0, "a 64 bit val 123456780abcdef0" 310 , __LINE__, INT64_C(0x123456780abcdef0)); 311 312 if (sizeof(void *) == 4) { 313 ptr = (void *)0xdeadbeef; 314 test_format("a 32 bit ptr %p", 50, 0, "a 32 bit ptr deadbeef", __LINE__, ptr); 315 } else if (sizeof(void *) == 8) { 316 ptr = (void *) INT64_C(0x1000200030004000); 317 test_format("a 64 bit ptr %p", 50, 0, "a 64 bit ptr 1000200030004000", __LINE__, ptr); 318 } else if (sizeof(void *) == 16) { 319 /* iSeries */ 320 union { 321 int32_t arr[4]; 322 void *ptr; 323 } massiveBigEndianPtr = {{ 0x10002000, 0x30004000, 0x50006000, 0x70008000 }}; 324 ptr = massiveBigEndianPtr.ptr; 325 test_format("a 128 bit ptr %p", 50, 0, "a 128 bit ptr 10002000300040005000600070008000", __LINE__, ptr); 326 } else { 327 TEST_ASSERT(FALSE); 328 /* TODO: others? */ 329 } 330 331 test_format("%vc", 100, 0, "abc[ffffffff]", __LINE__, "abc", -1); 332 test_format("%vs", 100, 0, "s1\ns2\n[00000002]", __LINE__, a1, 2); 333 test_format("%vs", 100, 4, " s1\n s2\n [00000002]", __LINE__, a1, 2); 334 335 test_format("%vb", 100, 0, "41 42 43 [00000003]", __LINE__, "\x41\x42\x43", 3); 336 337 /* Null ptrs for strings, vectors */ 338 test_format("Null string - %s", 50, 0, "Null string - *NULL*", __LINE__, NULL); 339 test_format("Null string - %S", 50, 0, "Null string - *NULL*", __LINE__, NULL); 340 test_format("Null vector - %vc", 50, 0, "Null vector - *NULL* [00000002]", __LINE__, NULL, 2); 341 test_format("Null vector - %vC", 50, 0, "Null vector - *NULL* [00000002]", __LINE__, NULL, 2); 342 test_format("Null vector - %vd", 50, 0, "Null vector - *NULL* [00000002]", __LINE__, NULL, 2); 343 344 } 345 346 /* 347 * utrace_format. Only need a minimal test to see that the function works at all. 348 * Full functionality is tested via utrace_vformat. 349 */ 350 { 351 char buf[100]; 352 int32_t x; 353 x = utrace_format(buf, 100, 0, "%s", "Hello, World."); 354 TEST_ASSERT(strcmp(buf, "Hello, World.") == 0); 355 TEST_ASSERT(x == 14); 356 } 357 358 /* 359 * utrace_functionName. Just spot-check a couple of them. 360 */ 361 { 362 const char *name; 363 name = utrace_functionName(UTRACE_U_INIT); 364 TEST_ASSERT(strcmp(name, "u_init") == 0); 365 name = utrace_functionName(UTRACE_UCNV_OPEN); 366 TEST_ASSERT(strcmp(name, "ucnv_open") == 0); 367 name = utrace_functionName(UTRACE_UCOL_GET_SORTKEY); 368 TEST_ASSERT(strcmp(name, "ucol_getSortKey") == 0); 369 } 370 371 372 373 /* Restore the trace function settings to their original values. */ 374 utrace_setFunctions(originalTContext, originalTEntryFunc, originalTExitFunc, originalTDataFunc); 375 utrace_setLevel(originalLevel); 376 } 377 378 379 380