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
34static void TestTraceAPI(void);
35
36
37void
38addUTraceTest(TestNode** root);
39
40void
41addUTraceTest(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) \
51if (!(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 */
70static 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 */
109static int    gTraceEntryCount;
110static int    gTraceExitCount;
111static int    gTraceDataCount;
112static UBool  gFnNameError   = FALSE;
113static UBool  gFnFormatError = FALSE;
114
115static 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
131static 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
157static 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
182static 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}
191static 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 */
202static 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