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