• 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 <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