• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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