1/********************************************************************
2 * COPYRIGHT:
3 * Copyright (c) 1997-2010, International Business Machines Corporation and
4 * others. All Rights Reserved.
5 ********************************************************************/
6/********************************************************************************
7*
8* File CINTLTST.C
9*
10* Modification History:
11*        Name                     Description
12*     Madhu Katragadda               Creation
13*********************************************************************************
14*/
15
16/*The main root for C API tests*/
17
18#include <stdlib.h>
19#include <stdio.h>
20#include <string.h>
21#include "unicode/utypes.h"
22#include "unicode/putil.h"
23#include "cstring.h"
24#include "cintltst.h"
25#include "umutex.h"
26#include "uassert.h"
27#include "cmemory.h"
28#include "unicode/uchar.h"
29#include "unicode/ustring.h"
30#include "unicode/ucnv.h"
31#include "unicode/ures.h"
32#include "unicode/uclean.h"
33#include "unicode/ucal.h"
34#include "uoptions.h"
35#include "putilimp.h" /* for uprv_getRawUTCtime() */
36#ifdef URES_DEBUG
37#include "uresimp.h" /* for ures_dumpCacheContents() */
38#endif
39
40#ifdef XP_MAC_CONSOLE
41#   include <console.h>
42#endif
43
44#define CTST_LEAK_CHECK 1
45#ifdef CTST_LEAK_CHECK
46U_CFUNC void ctst_freeAll(void);
47#endif
48
49static char* _testDataPath=NULL;
50
51/*
52 *  Forward Declarations
53 */
54void ctest_setICU_DATA(void);
55
56
57
58#if UCONFIG_NO_LEGACY_CONVERSION
59#   define TRY_CNV_1 "iso-8859-1"
60#   define TRY_CNV_2 "ibm-1208"
61#else
62#   define TRY_CNV_1 "iso-8859-7"
63#   define TRY_CNV_2 "sjis"
64#endif
65
66static int gOrigArgc;
67static const char* const * gOrigArgv;
68
69int main(int argc, const char* const argv[])
70{
71    int nerrors = 0;
72    UBool   defaultDataFound;
73    TestNode *root;
74    const char *warnOrErr = "Failure";
75    UDate startTime, endTime;
76    int32_t diffTime;
77
78    /* initial check for the default converter */
79    UErrorCode errorCode = U_ZERO_ERROR;
80    UResourceBundle *rb;
81    UConverter *cnv;
82
83    U_MAIN_INIT_ARGS(argc, argv);
84
85    startTime = uprv_getRawUTCtime();
86
87    gOrigArgc = argc;
88    gOrigArgv = argv;
89    if (!initArgs(argc, argv, NULL, NULL)) {
90        /* Error already displayed. */
91        return -1;
92    }
93
94    /* Check whether ICU will initialize without forcing the build data directory into
95     *  the ICU_DATA path.  Success here means either the data dll contains data, or that
96     *  this test program was run with ICU_DATA set externally.  Failure of this check
97     *  is normal when ICU data is not packaged into a shared library.
98     *
99     *  Whether or not this test succeeds, we want to cleanup and reinitialize
100     *  with a data path so that data loading from individual files can be tested.
101     */
102    defaultDataFound = TRUE;
103    u_init(&errorCode);
104    if (U_FAILURE(errorCode)) {
105        fprintf(stderr,
106            "#### Note:  ICU Init without build-specific setDataDirectory() failed. %s\n", u_errorName(errorCode));
107        defaultDataFound = FALSE;
108    }
109    u_cleanup();
110#ifdef URES_DEBUG
111    fprintf(stderr, "After initial u_cleanup: RB cache %s empty.\n", ures_dumpCacheContents()?"WAS NOT":"was");
112#endif
113
114    while (getTestOption(REPEAT_TESTS_OPTION) > 0) {   /* Loop runs once per complete execution of the tests
115                                  *   used for -r  (repeat) test option.                */
116        if (!initArgs(argc, argv, NULL, NULL)) {
117            /* Error already displayed. */
118            return -1;
119        }
120        errorCode = U_ZERO_ERROR;
121
122        /* Initialize ICU */
123        if (!defaultDataFound) {
124            ctest_setICU_DATA();    /* u_setDataDirectory() must happen Before u_init() */
125        }
126        u_init(&errorCode);
127        if (U_FAILURE(errorCode)) {
128            fprintf(stderr,
129                "#### ERROR! %s: u_init() failed with status = \"%s\".\n"
130                "*** Check the ICU_DATA environment variable and \n"
131                "*** check that the data files are present.\n", argv[0], u_errorName(errorCode));
132                if(!getTestOption(WARN_ON_MISSING_DATA_OPTION)) {
133                    fprintf(stderr, "*** Exiting.  Use the '-w' option if data files were\n*** purposely removed, to continue test anyway.\n");
134                    u_cleanup();
135                    return 1;
136                }
137        }
138
139
140
141        /* try more data */
142        cnv = ucnv_open(TRY_CNV_2, &errorCode);
143        if(cnv != 0) {
144            /* ok */
145            ucnv_close(cnv);
146        } else {
147            fprintf(stderr,
148                    "*** %s! The converter for " TRY_CNV_2 " cannot be opened.\n"
149                    "*** Check the ICU_DATA environment variable and \n"
150                    "*** check that the data files are present.\n", warnOrErr);
151            if(!getTestOption(WARN_ON_MISSING_DATA_OPTION)) {
152                fprintf(stderr, "*** Exitting.  Use the '-w' option if data files were\n*** purposely removed, to continue test anyway.\n");
153                u_cleanup();
154                return 1;
155            }
156        }
157
158        rb = ures_open(NULL, "en", &errorCode);
159        if(U_SUCCESS(errorCode)) {
160            /* ok */
161            ures_close(rb);
162        } else {
163            fprintf(stderr,
164                    "*** %s! The \"en\" locale resource bundle cannot be opened.\n"
165                    "*** Check the ICU_DATA environment variable and \n"
166                    "*** check that the data files are present.\n", warnOrErr);
167            if(!getTestOption(WARN_ON_MISSING_DATA_OPTION)) {
168                fprintf(stderr, "*** Exitting.  Use the '-w' option if data files were\n*** purposely removed, to continue test anyway.\n");
169                u_cleanup();
170                return 1;
171            }
172        }
173
174        errorCode = U_ZERO_ERROR;
175        rb = ures_open(NULL, NULL, &errorCode);
176        if(U_SUCCESS(errorCode)) {
177            /* ok */
178            if (errorCode == U_USING_DEFAULT_WARNING || errorCode == U_USING_FALLBACK_WARNING) {
179                fprintf(stderr,
180                        "#### Note: The default locale %s is not available\n", uloc_getDefault());
181            }
182            ures_close(rb);
183        } else {
184            fprintf(stderr,
185                    "*** %s! Can not open a resource bundle for the default locale %s\n", warnOrErr, uloc_getDefault());
186            if(!getTestOption(WARN_ON_MISSING_DATA_OPTION)) {
187                fprintf(stderr, "*** Exitting.  Use the '-w' option if data files were\n"
188                    "*** purposely removed, to continue test anyway.\n");
189                u_cleanup();
190                return 1;
191            }
192        }
193        fprintf(stdout, "Default locale for this run is %s\n", uloc_getDefault());
194
195        /* Build a tree of all tests.
196         *   Subsequently will be used to find / iterate the tests to run */
197        root = NULL;
198        addAllTests(&root);
199
200        /*  Tests acutally run HERE.   TODO:  separate command line option parsing & setting from test execution!! */
201        nerrors = runTestRequest(root, argc, argv);
202
203        setTestOption(REPEAT_TESTS_OPTION, DECREMENT_OPTION_VALUE);
204        if (getTestOption(REPEAT_TESTS_OPTION) > 0) {
205            printf("Repeating tests %d more time(s)\n", getTestOption(REPEAT_TESTS_OPTION));
206        }
207        cleanUpTestTree(root);
208
209#ifdef CTST_LEAK_CHECK
210        ctst_freeAll();
211        /* To check for leaks */
212        u_cleanup(); /* nuke the hashtable.. so that any still-open cnvs are leaked */
213#ifdef URES_DEBUG
214        if(ures_dumpCacheContents()) {
215          fprintf(stderr, "Error: After final u_cleanup, RB cache was not empty.\n");
216          nerrors++;
217        } else {
218          fprintf(stderr,"OK: After final u_cleanup, RB cache was empty.\n");
219        }
220#endif
221#endif
222
223    }  /* End of loop that repeats the entire test, if requested.  (Normally doesn't loop)  */
224
225    if (ALLOCATION_COUNT > 0) {
226        fprintf(stderr, "There were %d blocks leaked!\n", ALLOCATION_COUNT);
227        nerrors++;
228    }
229    endTime = uprv_getRawUTCtime();
230    diffTime = (int32_t)(endTime - startTime);
231    printf("Elapsed Time: %02d:%02d:%02d.%03d\n",
232        (int)((diffTime%U_MILLIS_PER_DAY)/U_MILLIS_PER_HOUR),
233        (int)((diffTime%U_MILLIS_PER_HOUR)/U_MILLIS_PER_MINUTE),
234        (int)((diffTime%U_MILLIS_PER_MINUTE)/U_MILLIS_PER_SECOND),
235        (int)(diffTime%U_MILLIS_PER_SECOND));
236
237    return nerrors ? 1 : 0;
238}
239
240/*
241static void ctest_appendToDataDirectory(const char *toAppend)
242{
243    const char *oldPath ="";
244    char newBuf [1024];
245    char *newPath = newBuf;
246    int32_t oldLen;
247    int32_t newLen;
248
249    if((toAppend == NULL) || (*toAppend == 0)) {
250        return;
251    }
252
253    oldPath = u_getDataDirectory();
254    if( (oldPath==NULL) || (*oldPath == 0)) {
255        u_setDataDirectory(toAppend);
256    } else {
257        oldLen = strlen(oldPath);
258        newLen = strlen(toAppend)+1+oldLen;
259
260        if(newLen > 1022)
261        {
262            newPath = (char *)ctst_malloc(newLen);
263        }
264
265        strcpy(newPath, oldPath);
266        strcpy(newPath+oldLen, U_PATH_SEP_STRING);
267        strcpy(newPath+oldLen+1, toAppend);
268
269        u_setDataDirectory(newPath);
270
271        if(newPath != newBuf)
272        {
273            free(newPath);
274        }
275    }
276}
277*/
278
279/* returns the path to icu/source/data */
280const char *  ctest_dataSrcDir()
281{
282    static const char *dataSrcDir = NULL;
283
284    if(dataSrcDir) {
285        return dataSrcDir;
286    }
287
288    /* U_TOPSRCDIR is set by the makefiles on UNIXes when building cintltst and intltst
289    //              to point to the top of the build hierarchy, which may or
290    //              may not be the same as the source directory, depending on
291    //              the configure options used.  At any rate,
292    //              set the data path to the built data from this directory.
293    //              The value is complete with quotes, so it can be used
294    //              as-is as a string constant.
295    */
296#if defined (U_TOPSRCDIR)
297    {
298        dataSrcDir = U_TOPSRCDIR  U_FILE_SEP_STRING "data" U_FILE_SEP_STRING;
299    }
300#else
301
302    /* On Windows, the file name obtained from __FILE__ includes a full path.
303     *             This file is "wherever\icu\source\test\cintltst\cintltst.c"
304     *             Change to    "wherever\icu\source\data"
305     */
306    {
307        static char p[sizeof(__FILE__) + 20];
308        char *pBackSlash;
309        int i;
310
311        strcpy(p, __FILE__);
312        /* We want to back over three '\' chars.                            */
313        /*   Only Windows should end up here, so looking for '\' is safe.   */
314        for (i=1; i<=3; i++) {
315            pBackSlash = strrchr(p, U_FILE_SEP_CHAR);
316            if (pBackSlash != NULL) {
317                *pBackSlash = 0;        /* Truncate the string at the '\'   */
318            }
319        }
320
321        if (pBackSlash != NULL) {
322            /* We found and truncated three names from the path.
323             *  Now append "source\data" and set the environment
324             */
325            strcpy(pBackSlash, U_FILE_SEP_STRING "data" U_FILE_SEP_STRING );
326            dataSrcDir = p;
327        }
328        else {
329            /* __FILE__ on MSVC7 does not contain the directory */
330            FILE *file = fopen(".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING "data" U_FILE_SEP_STRING "Makefile.in", "r");
331            if (file) {
332                fclose(file);
333                dataSrcDir = ".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING "data" U_FILE_SEP_STRING;
334            }
335            else {
336                dataSrcDir = ".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING "data" U_FILE_SEP_STRING;
337            }
338        }
339    }
340#endif
341
342    return dataSrcDir;
343
344}
345
346/* returns the path to icu/source/data/out */
347const char *ctest_dataOutDir()
348{
349    static const char *dataOutDir = NULL;
350
351    if(dataOutDir) {
352        return dataOutDir;
353    }
354
355    /* U_TOPBUILDDIR is set by the makefiles on UNIXes when building cintltst and intltst
356    //              to point to the top of the build hierarchy, which may or
357    //              may not be the same as the source directory, depending on
358    //              the configure options used.  At any rate,
359    //              set the data path to the built data from this directory.
360    //              The value is complete with quotes, so it can be used
361    //              as-is as a string constant.
362    */
363#if defined (U_TOPBUILDDIR)
364    {
365        dataOutDir = U_TOPBUILDDIR "data"U_FILE_SEP_STRING"out"U_FILE_SEP_STRING;
366    }
367#else
368
369    /* On Windows, the file name obtained from __FILE__ includes a full path.
370     *             This file is "wherever\icu\source\test\cintltst\cintltst.c"
371     *             Change to    "wherever\icu\source\data"
372     */
373    {
374        static char p[sizeof(__FILE__) + 20];
375        char *pBackSlash;
376        int i;
377
378        strcpy(p, __FILE__);
379        /* We want to back over three '\' chars.                            */
380        /*   Only Windows should end up here, so looking for '\' is safe.   */
381        for (i=1; i<=3; i++) {
382            pBackSlash = strrchr(p, U_FILE_SEP_CHAR);
383            if (pBackSlash != NULL) {
384                *pBackSlash = 0;        /* Truncate the string at the '\'   */
385            }
386        }
387
388        if (pBackSlash != NULL) {
389            /* We found and truncated three names from the path.
390             *  Now append "source\data" and set the environment
391             */
392            strcpy(pBackSlash, U_FILE_SEP_STRING "data" U_FILE_SEP_STRING "out" U_FILE_SEP_STRING);
393            dataOutDir = p;
394        }
395        else {
396            /* __FILE__ on MSVC7 does not contain the directory */
397            FILE *file = fopen(".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING "data" U_FILE_SEP_STRING "Makefile.in", "r");
398            if (file) {
399                fclose(file);
400                dataOutDir = ".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING "data" U_FILE_SEP_STRING "out" U_FILE_SEP_STRING;
401            }
402            else {
403                dataOutDir = ".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING "data" U_FILE_SEP_STRING "out" U_FILE_SEP_STRING;
404            }
405        }
406    }
407#endif
408
409    return dataOutDir;
410}
411
412/*  ctest_setICU_DATA  - if the ICU_DATA environment variable is not already
413 *                       set, try to deduce the directory in which ICU was built,
414 *                       and set ICU_DATA to "icu/source/data" in that location.
415 *                       The intent is to allow the tests to have a good chance
416 *                       of running without requiring that the user manually set
417 *                       ICU_DATA.  Common data isn't a problem, since it is
418 *                       picked up via a static (build time) reference, but the
419 *                       tests dynamically load some data.
420 */
421void ctest_setICU_DATA() {
422
423    /* No location for the data dir was identifiable.
424     *   Add other fallbacks for the test data location here if the need arises
425     */
426    if (getenv("ICU_DATA") == NULL) {
427        /* If ICU_DATA isn't set, set it to the usual location */
428        u_setDataDirectory(ctest_dataOutDir());
429    }
430}
431
432/*  These tests do cleanup and reinitialize ICU in the course of their operation.
433 *    The ICU data directory must be preserved across these operations.
434 *    Here is a helper function to assist with that.
435 */
436static char *safeGetICUDataDirectory() {
437    const char *dataDir = u_getDataDirectory();  /* Returned string vanashes with u_cleanup */
438    char *retStr = NULL;
439    if (dataDir != NULL) {
440        retStr = (char *)malloc(strlen(dataDir)+1);
441        strcpy(retStr, dataDir);
442    }
443    return retStr;
444}
445
446UBool ctest_resetICU() {
447    UErrorCode   status = U_ZERO_ERROR;
448    char         *dataDir = safeGetICUDataDirectory();
449
450    u_cleanup();
451    if (!initArgs(gOrigArgc, gOrigArgv, NULL, NULL)) {
452        /* Error already displayed. */
453        return FALSE;
454    }
455    u_setDataDirectory(dataDir);
456    free(dataDir);
457    u_init(&status);
458    if (U_FAILURE(status)) {
459        log_err_status(status, "u_init failed with %s\n", u_errorName(status));
460        return FALSE;
461    }
462    return TRUE;
463}
464
465UChar* CharsToUChars(const char* str) {
466    /* Might be faster to just use uprv_strlen() as the preflight len - liu */
467    int32_t len = u_unescape(str, 0, 0); /* preflight */
468    /* Do NOT use malloc() - we are supposed to be acting like user code! */
469    UChar *buf = (UChar*) malloc(sizeof(UChar) * (len + 1));
470    u_unescape(str, buf, len + 1);
471    return buf;
472}
473
474char *austrdup(const UChar* unichars)
475{
476    int   length;
477    char *newString;
478
479    length    = u_strlen ( unichars );
480    /*newString = (char*)malloc  ( sizeof( char ) * 4 * ( length + 1 ) );*/ /* this leaks for now */
481    newString = (char*)ctst_malloc  ( sizeof( char ) * 4 * ( length + 1 ) ); /* this shouldn't */
482
483    if ( newString == NULL )
484        return NULL;
485
486    u_austrcpy ( newString, unichars );
487
488    return newString;
489}
490
491char *aescstrdup(const UChar* unichars,int32_t length){
492    char *newString,*targetLimit,*target;
493    UConverterFromUCallback cb;
494    const void *p;
495    UErrorCode errorCode = U_ZERO_ERROR;
496#if U_CHARSET_FAMILY==U_EBCDIC_FAMILY
497#   ifdef OS390
498        static const char convName[] = "ibm-1047";
499#   else
500        static const char convName[] = "ibm-37";
501#   endif
502#else
503    static const char convName[] = "US-ASCII";
504#endif
505    UConverter* conv = ucnv_open(convName, &errorCode);
506    if(length==-1){
507        length = u_strlen( unichars);
508    }
509    newString = (char*)ctst_malloc ( sizeof(char) * 8 * (length +1));
510    target = newString;
511    targetLimit = newString+sizeof(char) * 8 * (length +1);
512    ucnv_setFromUCallBack(conv, UCNV_FROM_U_CALLBACK_ESCAPE, UCNV_ESCAPE_C, &cb, &p, &errorCode);
513    ucnv_fromUnicode(conv,&target,targetLimit, &unichars, (UChar*)(unichars+length),NULL,TRUE,&errorCode);
514    ucnv_close(conv);
515    *target = '\0';
516    return newString;
517}
518
519const char* loadTestData(UErrorCode* err){
520    if( _testDataPath == NULL){
521        const char*      directory=NULL;
522        UResourceBundle* test =NULL;
523        char* tdpath=NULL;
524        const char* tdrelativepath;
525#if defined (U_TOPBUILDDIR)
526        tdrelativepath = "test"U_FILE_SEP_STRING"testdata"U_FILE_SEP_STRING"out"U_FILE_SEP_STRING;
527        directory = U_TOPBUILDDIR;
528#else
529        tdrelativepath = ".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING"test"U_FILE_SEP_STRING"testdata"U_FILE_SEP_STRING"out"U_FILE_SEP_STRING;
530        directory= ctest_dataOutDir();
531#endif
532
533        tdpath = (char*) ctst_malloc(sizeof(char) *(( strlen(directory) * strlen(tdrelativepath)) + 10));
534
535
536        /* u_getDataDirectory shoul return \source\data ... set the
537         * directory to ..\source\data\..\test\testdata\out\testdata
538         *
539         * Fallback: When Memory mapped file is built
540         * ..\source\data\out\..\..\test\testdata\out\testdata
541         */
542        strcpy(tdpath, directory);
543        strcat(tdpath, tdrelativepath);
544        strcat(tdpath,"testdata");
545
546
547        test=ures_open(tdpath, "testtypes", err);
548
549        /* Fall back did not succeed either so return */
550        if(U_FAILURE(*err)){
551            *err = U_FILE_ACCESS_ERROR;
552            log_data_err("Could not load testtypes.res in testdata bundle with path %s - %s\n", tdpath, u_errorName(*err));
553            return "";
554        }
555        ures_close(test);
556        _testDataPath = tdpath;
557        return _testDataPath;
558    }
559    return _testDataPath;
560}
561
562#define CTEST_MAX_TIMEZONE_SIZE 256
563static UChar gOriginalTimeZone[CTEST_MAX_TIMEZONE_SIZE] = {0};
564
565/**
566 * Call this once to get a consistent timezone. Use ctest_resetTimeZone to set it back to the original value.
567 * @param optionalTimeZone Set this to a requested timezone.
568 *      Set to NULL to use the standard test timezone (Pacific Time)
569 */
570U_CFUNC void ctest_setTimeZone(const char *optionalTimeZone, UErrorCode *status) {
571#if !UCONFIG_NO_FORMATTING
572    UChar zoneID[CTEST_MAX_TIMEZONE_SIZE];
573
574    if (optionalTimeZone == NULL) {
575        optionalTimeZone = "America/Los_Angeles";
576    }
577    if (gOriginalTimeZone[0]) {
578        log_data_err("*** Error: time zone saved twice. New value will be %s (Are you missing data?)\n",
579               optionalTimeZone);
580    }
581    ucal_getDefaultTimeZone(gOriginalTimeZone, CTEST_MAX_TIMEZONE_SIZE, status);
582    if (U_FAILURE(*status)) {
583        log_err("*** Error: Failed to save default time zone: %s\n",
584               u_errorName(*status));
585        *status = U_ZERO_ERROR;
586    }
587
588    u_uastrncpy(zoneID, optionalTimeZone, CTEST_MAX_TIMEZONE_SIZE-1);
589    zoneID[CTEST_MAX_TIMEZONE_SIZE-1] = 0;
590    ucal_setDefaultTimeZone(zoneID, status);
591    if (U_FAILURE(*status)) {
592        log_err("*** Error: Failed to set default time zone to \"%s\": %s\n",
593               optionalTimeZone, u_errorName(*status));
594    }
595#endif
596}
597
598/**
599 * Call this once get back the original timezone
600 */
601U_CFUNC void ctest_resetTimeZone(void) {
602#if !UCONFIG_NO_FORMATTING
603    UErrorCode status = U_ZERO_ERROR;
604
605    ucal_setDefaultTimeZone(gOriginalTimeZone, &status);
606    if (U_FAILURE(status)) {
607        log_err("*** Error: Failed to reset default time zone: %s\n",
608               u_errorName(status));
609    }
610    /* Set to an empty state */
611    gOriginalTimeZone[0] = 0;
612#endif
613}
614
615#define CTST_MAX_ALLOC 8192
616/* Array used as a queue */
617static void * ctst_allocated_stuff[CTST_MAX_ALLOC] = {0};
618static int ctst_allocated = 0;
619static UBool ctst_free = FALSE;
620
621void *ctst_malloc(size_t size) {
622    if(ctst_allocated >= CTST_MAX_ALLOC - 1) {
623        ctst_allocated = 0;
624        ctst_free = TRUE;
625    }
626    if(ctst_allocated_stuff[ctst_allocated]) {
627        free(ctst_allocated_stuff[ctst_allocated]);
628    }
629    return ctst_allocated_stuff[ctst_allocated++] = malloc(size);
630}
631
632#ifdef CTST_LEAK_CHECK
633void ctst_freeAll() {
634    int i;
635    if(ctst_free == 0) {
636        for(i=0; i<ctst_allocated; i++) {
637            free(ctst_allocated_stuff[i]);
638            ctst_allocated_stuff[i] = NULL;
639        }
640    } else {
641        for(i=0; i<CTST_MAX_ALLOC; i++) {
642            free(ctst_allocated_stuff[i]);
643            ctst_allocated_stuff[i] = NULL;
644        }
645    }
646    ctst_allocated = 0;
647    _testDataPath=NULL;
648}
649
650#define VERBOSE_ASSERTIONS
651
652U_CFUNC UBool assertSuccess(const char* msg, UErrorCode* ec) {
653    U_ASSERT(ec!=NULL);
654    if (U_FAILURE(*ec)) {
655        log_err_status(*ec, "FAIL: %s (%s)\n", msg, u_errorName(*ec));
656        return FALSE;
657    }
658    return TRUE;
659}
660
661/* if 'condition' is a UBool, the compiler complains bitterly about
662   expressions like 'a > 0' which it evaluates as int */
663U_CFUNC UBool assertTrue(const char* msg, int /*not UBool*/ condition) {
664    if (!condition) {
665        log_err("FAIL: assertTrue() failed: %s\n", msg);
666    }
667#ifdef VERBOSE_ASSERTIONS
668    else {
669        log_verbose("Ok: %s\n", msg);
670    }
671#endif
672    return (UBool)condition;
673}
674
675U_CFUNC UBool assertEquals(const char* message, const char* expected,
676                           const char* actual) {
677    if (uprv_strcmp(expected, actual) != 0) {
678        log_err("FAIL: %s; got \"%s\"; expected \"%s\"\n",
679                message, actual, expected);
680        return FALSE;
681    }
682#ifdef VERBOSE_ASSERTIONS
683    else {
684        log_verbose("Ok: %s; got \"%s\"\n", message, actual);
685    }
686#endif
687    return TRUE;
688}
689/*--------------------------------------------------------------------
690 * Time bomb - allows temporary behavior that expires at a given
691 *             release
692 *--------------------------------------------------------------------
693 */
694
695U_CFUNC UBool isICUVersionAtLeast(const UVersionInfo x) {
696    UVersionInfo v;
697    u_getVersion(v);
698    return (uprv_memcmp(v, x, U_MAX_VERSION_LENGTH) >= 0);
699}
700#endif
701