1 /********************************************************************
2 * COPYRIGHT:
3 * Copyright (c) 2003-2013, 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
addUTraceTest(TestNode ** root)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 */
test_format(const char * format,int32_t bufCap,int32_t indent,const char * result,int32_t line,...)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 (void)len; /* Suppress set but not used warning. */
96
97 /* Check results. */
98 if (strcmp(expectedResult, buf) != 0) {
99 log_err("At file:line %s:%d Expected \"%s\", got \"%s\" \n",
100 __FILE__, line, expectedResult, buf);
101 }
102 va_end(args);
103 }
104
105
106 /*
107 * define trace functions for use in this test.
108 */
109 static int gTraceEntryCount;
110 static int gTraceExitCount;
111 static int gTraceDataCount;
112 static UBool gFnNameError = FALSE;
113 static UBool gFnFormatError = FALSE;
114
testTraceEntry(const void * context,int32_t fnNumber)115 static void U_CALLCONV testTraceEntry(const void *context, int32_t fnNumber) {
116 const char *fnName;
117 const char *bogusFnName;
118
119 gTraceEntryCount++;
120
121 /* Verify that a name is available for the fnNumber passed to us */
122 bogusFnName = utrace_functionName(-1);
123 fnName = utrace_functionName(fnNumber);
124 if (strcmp(fnName, bogusFnName) == 0) {
125 gFnNameError = TRUE;
126 }
127 /* printf("%s() Enter\n", fnName); */
128
129 }
130
testTraceExit(const void * context,int32_t fnNumber,const char * fmt,va_list args)131 static void U_CALLCONV testTraceExit(const void *context, int32_t fnNumber,
132 const char *fmt, va_list args) {
133 char buf[1000];
134 const char *fnName;
135 const char *bogusFnName;
136
137 gTraceExitCount++;
138
139 /* Verify that a name is available for the fnNumber passed to us */
140 bogusFnName = utrace_functionName(-1);
141 fnName = utrace_functionName(fnNumber);
142 if (strcmp(fnName, bogusFnName) == 0) {
143 gFnNameError = TRUE;
144 }
145
146 /* Verify that the format can be used. */
147 buf[0] = 0;
148 utrace_vformat(buf, sizeof(buf), 0, fmt, args);
149 if (strlen(buf) == 0) {
150 gFnFormatError = TRUE;
151 }
152
153 /* printf("%s() %s\n", fnName, buf); */
154
155 }
156
testTraceData(const void * context,int32_t fnNumber,int32_t level,const char * fmt,va_list args)157 static void U_CALLCONV testTraceData(const void *context, int32_t fnNumber, int32_t level,
158 const char *fmt, va_list args) {
159 char buf[1000];
160 const char *fnName;
161 const char *bogusFnName;
162
163 gTraceDataCount++;
164
165 /* Verify that a name is available for the fnNumber passed to us */
166 bogusFnName = utrace_functionName(-1);
167 fnName = utrace_functionName(fnNumber);
168 if (strcmp(fnName, bogusFnName) == 0) {
169 gFnNameError = TRUE;
170 }
171
172 /* Verify that the format can be used. */
173 buf[0] = 0;
174 utrace_vformat(buf, sizeof(buf), 0, fmt, args);
175 if (strlen(buf) == 0) {
176 gFnFormatError = TRUE;
177 }
178
179 /* printf(" %s() %s\n", fnName, buf); */
180 }
181
psuedo_ucnv_open(const char * name,UErrorCode * err)182 static UConverter * psuedo_ucnv_open(const char *name, UErrorCode * err)
183 {
184 UTRACE_ENTRY_OC(UTRACE_UCNV_LOAD);
185
186 UTRACE_DATA2(UTRACE_OPEN_CLOSE, "error code is %s for %s", u_errorName(*err), name);
187
188 UTRACE_EXIT_PTR_STATUS(NULL, *err);
189 return NULL;
190 }
psuedo_ucnv_close(UConverter * cnv)191 static void psuedo_ucnv_close(UConverter * cnv)
192 {
193 UTRACE_ENTRY_OC(UTRACE_UCNV_UNLOAD);
194 UTRACE_DATA1(UTRACE_OPEN_CLOSE, "unload converter %p", cnv);
195 UTRACE_EXIT_VALUE((int32_t)TRUE);
196 }
197
198
199 /*
200 * TestTraceAPI
201 */
TestTraceAPI()202 static void TestTraceAPI() {
203
204
205 UTraceEntry *originalTEntryFunc;
206 UTraceExit *originalTExitFunc;
207 UTraceData *originalTDataFunc;
208 const void *originalTContext;
209 int32_t originalLevel;
210
211 /*
212 * Save the original tracing state so that we can restore it after the test.
213 */
214 utrace_getFunctions(&originalTContext, &originalTEntryFunc, &originalTExitFunc,
215 &originalTDataFunc);
216 originalLevel = utrace_getLevel();
217
218
219 /* verify that set/get of tracing functions returns what was set. */
220 {
221 UTraceEntry *e;
222 UTraceExit *x;
223 UTraceData *d;
224 const void *context;
225 const void *newContext = (const char *)originalTContext + 1;
226
227 TEST_ASSERT(originalTEntryFunc != testTraceEntry);
228 TEST_ASSERT(originalTExitFunc != testTraceExit);
229 TEST_ASSERT(originalTDataFunc != testTraceData);
230
231 utrace_setFunctions(newContext, testTraceEntry, testTraceExit, testTraceData);
232 utrace_getFunctions(&context, &e, &x, &d);
233 TEST_ASSERT(e == testTraceEntry);
234 TEST_ASSERT(x == testTraceExit);
235 TEST_ASSERT(d == testTraceData);
236 TEST_ASSERT(context == newContext);
237 }
238
239 /* verify that set/get level work as a pair, and that the level
240 * identifiers all exist.
241 */
242
243 {
244 int32_t level;
245
246 utrace_setLevel(UTRACE_OFF);
247 level = utrace_getLevel();
248 TEST_ASSERT(level==UTRACE_OFF);
249 utrace_setLevel(UTRACE_VERBOSE);
250 level = utrace_getLevel();
251 TEST_ASSERT(level==UTRACE_VERBOSE);
252 utrace_setLevel(UTRACE_ERROR);
253 utrace_setLevel(UTRACE_WARNING);
254 utrace_setLevel(UTRACE_OPEN_CLOSE);
255 utrace_setLevel(UTRACE_INFO);
256 }
257
258 /*
259 * Open and close a converter with tracing enabled.
260 * Verify that our tracing callback functions get called.
261 */
262 {
263 UErrorCode status = U_ZERO_ERROR;
264 UConverter *cnv;
265
266 gTraceEntryCount = 0;
267 gTraceExitCount = 0;
268 gTraceDataCount = 0;
269 gFnNameError = FALSE;
270 gFnFormatError = FALSE;
271 utrace_setLevel(UTRACE_OPEN_CLOSE);
272 #if ENABLE_TRACING_ORIG_VAL
273 cnv = ucnv_open(NULL, &status);
274 TEST_ASSERT(U_SUCCESS(status));
275 ucnv_close(cnv);
276 #else
277 cnv = psuedo_ucnv_open(NULL, &status);
278 TEST_ASSERT(U_SUCCESS(status));
279 psuedo_ucnv_close(cnv);
280 #endif
281 TEST_ASSERT(gTraceEntryCount > 0);
282 TEST_ASSERT(gTraceExitCount > 0);
283 TEST_ASSERT(gTraceDataCount > 0);
284 TEST_ASSERT(gFnNameError == FALSE);
285 TEST_ASSERT(gFnFormatError == FALSE);
286 }
287
288
289
290 /*
291 * trace data formatter operation.
292 */
293 {
294 UChar s1[] = {0x41fe, 0x42, 0x43, 00};
295 const char *a1[] = {"s1", "s2", "s3"};
296 void *ptr;
297
298 test_format("hello, world", 50, 0, "hello, world", __LINE__);
299 test_format("hello, world", 50, 4, " hello, world", __LINE__);
300 test_format("hello, world", 3, 0, "hello, world", __LINE__);
301
302 test_format("a character %c", 50, 0, "a character x", __LINE__, 'x');
303 test_format("a string %s ", 50, 0, "a string hello ", __LINE__, "hello");
304 test_format("uchars %S ", 50, 0, "uchars 41fe 0042 0043 0000 ", __LINE__, s1, -1);
305 test_format("uchars %S ", 50, 0, "uchars 41fe 0042 ", __LINE__, s1, 2);
306
307 test_format("a byte %b--", 50, 0, "a byte dd--", __LINE__, 0xdd);
308 test_format("a 16 bit val %h", 50, 0, "a 16 bit val 1234", __LINE__, 0x1234);
309 test_format("a 32 bit val %d...", 50, 0, "a 32 bit val 6789abcd...", __LINE__, 0x6789abcd);
310 test_format("a 64 bit val %l", 50, 0, "a 64 bit val 123456780abcdef0"
311 , __LINE__, INT64_C(0x123456780abcdef0));
312
313 if (sizeof(void *) == 4) {
314 ptr = (void *)0xdeadbeef;
315 test_format("a 32 bit ptr %p", 50, 0, "a 32 bit ptr deadbeef", __LINE__, ptr);
316 } else if (sizeof(void *) == 8) {
317 ptr = (void *) INT64_C(0x1000200030004000);
318 test_format("a 64 bit ptr %p", 50, 0, "a 64 bit ptr 1000200030004000", __LINE__, ptr);
319 } else if (sizeof(void *) == 16) {
320 /* iSeries */
321 union {
322 int32_t arr[4];
323 void *ptr;
324 } massiveBigEndianPtr = {{ 0x10002000, 0x30004000, 0x50006000, 0x70008000 }};
325 ptr = massiveBigEndianPtr.ptr;
326 test_format("a 128 bit ptr %p", 50, 0, "a 128 bit ptr 10002000300040005000600070008000", __LINE__, ptr);
327 } else {
328 TEST_ASSERT(FALSE);
329 /* TODO: others? */
330 }
331
332 test_format("%vc", 100, 0, "abc[ffffffff]", __LINE__, "abc", -1);
333 test_format("%vs", 100, 0, "s1\ns2\n[00000002]", __LINE__, a1, 2);
334 test_format("%vs", 100, 4, " s1\n s2\n [00000002]", __LINE__, a1, 2);
335
336 test_format("%vb", 100, 0, "41 42 43 [00000003]", __LINE__, "\x41\x42\x43", 3);
337
338 /* Null ptrs for strings, vectors */
339 test_format("Null string - %s", 50, 0, "Null string - *NULL*", __LINE__, NULL);
340 test_format("Null string - %S", 50, 0, "Null string - *NULL*", __LINE__, NULL);
341 test_format("Null vector - %vc", 50, 0, "Null vector - *NULL* [00000002]", __LINE__, NULL, 2);
342 test_format("Null vector - %vC", 50, 0, "Null vector - *NULL* [00000002]", __LINE__, NULL, 2);
343 test_format("Null vector - %vd", 50, 0, "Null vector - *NULL* [00000002]", __LINE__, NULL, 2);
344
345 }
346
347 /*
348 * utrace_format. Only need a minimal test to see that the function works at all.
349 * Full functionality is tested via utrace_vformat.
350 */
351 {
352 char buf[100];
353 int32_t x;
354 x = utrace_format(buf, 100, 0, "%s", "Hello, World.");
355 TEST_ASSERT(strcmp(buf, "Hello, World.") == 0);
356 TEST_ASSERT(x == 14);
357 }
358
359 /*
360 * utrace_functionName. Just spot-check a couple of them.
361 */
362 {
363 const char *name;
364 name = utrace_functionName(UTRACE_U_INIT);
365 TEST_ASSERT(strcmp(name, "u_init") == 0);
366 name = utrace_functionName(UTRACE_UCNV_OPEN);
367 TEST_ASSERT(strcmp(name, "ucnv_open") == 0);
368 name = utrace_functionName(UTRACE_UCOL_GET_SORTKEY);
369 TEST_ASSERT(strcmp(name, "ucol_getSortKey") == 0);
370 }
371
372
373
374 /* Restore the trace function settings to their original values. */
375 utrace_setFunctions(originalTContext, originalTEntryFunc, originalTExitFunc, originalTDataFunc);
376 utrace_setLevel(originalLevel);
377 }
378
379
380
381