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