Home | History | Annotate | Download | only in cintltst
      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
     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  */
     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 
    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 
    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 
    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 
    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 }
    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  */
    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