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
36 static void TestTraceAPI(void);
37
38
39 void
40 addUTraceTest(TestNode** root);
41
42 void
addUTraceTest(TestNode ** root)43 addUTraceTest(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) \
53 if (!(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 */
test_format(const char * format,int32_t bufCap,int32_t indent,const char * result,int32_t line,...)72 static 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 */
111 static int gTraceEntryCount;
112 static int gTraceExitCount;
113 static int gTraceDataCount;
114 static UBool gFnNameError = FALSE;
115 static UBool gFnFormatError = FALSE;
116
testTraceEntry(const void * context,int32_t fnNumber)117 static 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
testTraceExit(const void * context,int32_t fnNumber,const char * fmt,va_list args)133 static 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
testTraceData(const void * context,int32_t fnNumber,int32_t level,const char * fmt,va_list args)159 static 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
psuedo_ucnv_open(const char * name,UErrorCode * err)184 static 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 }
psuedo_ucnv_close(UConverter * cnv)193 static 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 */
TestTraceAPI()204 static 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