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