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