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