OLD | NEW |
(Empty) | |
| 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 lib
rary. */ |
| 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, int3
2_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, &originalTExitFu
nc, |
| 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, testTrace
Data); |
| 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__, 0x1
234); |
| 308 test_format("a 32 bit val %d...", 50, 0, "a 32 bit val 6789abcd...", __L
INE__, 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", __LIN
E__, 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, 0x700
08000 }}; |
| 324 ptr = massiveBigEndianPtr.ptr; |
| 325 test_format("a 128 bit ptr %p", 50, 0, "a 128 bit ptr 10002000300040
005000600070008000", __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__, a
1, 2); |
| 334 |
| 335 test_format("%vb", 100, 0, "41 42 43 [00000003]", __LINE__, "\x41\x42\x4
3", 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 a
t 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 |
OLD | NEW |