1/********************************************************************
2 * COPYRIGHT:
3 * Copyright (c) 1997-2013, International Business Machines Corporation and
4 * others. All Rights Reserved.
5 ********************************************************************/
6
7
8#include "unicode/utypes.h"
9
10/**
11 * IntlTest is a base class for tests.
12 */
13
14#include <stdio.h>
15#include <string.h>
16#include <assert.h>
17#include <stdarg.h>
18#include <stdlib.h>
19
20#include "unicode/unistr.h"
21#include "unicode/ures.h"
22#include "unicode/smpdtfmt.h"
23#include "unicode/ucnv.h"
24#include "unicode/uclean.h"
25#include "unicode/timezone.h"
26#include "unicode/curramt.h"
27#include "unicode/putil.h"
28
29#include "intltest.h"
30#include "caltztst.h"
31#include "itmajor.h"
32#include "cstring.h"
33#include "umutex.h"
34#include "uassert.h"
35#include "cmemory.h"
36#include "uoptions.h"
37
38#include "putilimp.h" // for uprv_getRawUTCtime()
39#include "unicode/locid.h"
40#include "unicode/ctest.h" // for str_timeDelta
41
42#ifdef XP_MAC_CONSOLE
43#include <console.h>
44#include "Files.h"
45#endif
46
47
48static char* _testDataPath=NULL;
49
50// Static list of errors found
51static UnicodeString errorList;
52
53//-----------------------------------------------------------------------------
54//convenience classes to ease porting code that uses the Java
55//string-concatenation operator (moved from findword test by rtg)
56
57// [LIU] Just to get things working
58UnicodeString
59UCharToUnicodeString(UChar c)
60{ return UnicodeString(c); }
61
62// [rtg] Just to get things working
63UnicodeString
64operator+(const UnicodeString& left,
65      long num)
66{
67    char buffer[64];    // nos changed from 10 to 64
68    char danger = 'p';  // guard against overrunning the buffer (rtg)
69
70    sprintf(buffer, "%ld", num);
71    assert(danger == 'p');
72
73    return left + buffer;
74}
75
76UnicodeString
77operator+(const UnicodeString& left,
78      unsigned long num)
79{
80    char buffer[64];    // nos changed from 10 to 64
81    char danger = 'p';  // guard against overrunning the buffer (rtg)
82
83    sprintf(buffer, "%lu", num);
84    assert(danger == 'p');
85
86    return left + buffer;
87}
88
89UnicodeString
90Int64ToUnicodeString(int64_t num)
91{
92    char buffer[64];    // nos changed from 10 to 64
93    char danger = 'p';  // guard against overrunning the buffer (rtg)
94
95#if defined(_MSC_VER)
96    sprintf(buffer, "%I64d", num);
97#else
98    sprintf(buffer, "%lld", (long long)num);
99#endif
100    assert(danger == 'p');
101
102    return buffer;
103}
104
105// [LIU] Just to get things working
106UnicodeString
107operator+(const UnicodeString& left,
108      double num)
109{
110    char buffer[64];   // was 32, made it arbitrarily bigger (rtg)
111    char danger = 'p'; // guard against overrunning the buffer (rtg)
112
113    // IEEE floating point has 52 bits of mantissa, plus one assumed bit
114    //  53*log(2)/log(10) = 15.95
115    // so there is no need to show more than 16 digits. [alan]
116
117    sprintf(buffer, "%.17g", num);
118    assert(danger == 'p');
119
120    return left + buffer;
121}
122
123#if !UCONFIG_NO_FORMATTING
124
125/**
126 * Return a string display for this, without surrounding braces.
127 */
128UnicodeString _toString(const Formattable& f) {
129    UnicodeString s;
130    switch (f.getType()) {
131    case Formattable::kDate:
132        {
133            UErrorCode status = U_ZERO_ERROR;
134            SimpleDateFormat fmt(status);
135            if (U_SUCCESS(status)) {
136                FieldPosition pos;
137                fmt.format(f.getDate(), s, pos);
138                s.insert(0, "Date:");
139            } else {
140                s = UnicodeString("Error creating date format]");
141            }
142        }
143        break;
144    case Formattable::kDouble:
145        s = UnicodeString("double:") + f.getDouble();
146        break;
147    case Formattable::kLong:
148        s = UnicodeString("long:") + f.getLong();
149        break;
150
151    case Formattable::kInt64:
152        s = UnicodeString("int64:") + Int64ToUnicodeString(f.getInt64());
153        break;
154
155    case Formattable::kString:
156        f.getString(s);
157        s.insert(0, "String:");
158        break;
159    case Formattable::kArray:
160        {
161            int32_t i, n;
162            const Formattable* array = f.getArray(n);
163            s.insert(0, UnicodeString("Array:"));
164            UnicodeString delim(", ");
165            for (i=0; i<n; ++i) {
166                if (i > 0) {
167                    s.append(delim);
168                }
169                s = s + _toString(array[i]);
170            }
171        }
172        break;
173    case Formattable::kObject: {
174        const CurrencyAmount* c = dynamic_cast<const CurrencyAmount*>(f.getObject());
175        if (c != NULL) {
176            s = _toString(c->getNumber()) + " " + UnicodeString(c->getISOCurrency());
177        } else {
178            s = UnicodeString("Unknown UObject");
179        }
180        break;
181    }
182    default:
183        s = UnicodeString("Unknown Formattable type=") + (int32_t)f.getType();
184        break;
185    }
186    return s;
187}
188
189/**
190 * Originally coded this as operator+, but that makes the expression
191 * + char* ambiguous. - liu
192 */
193UnicodeString toString(const Formattable& f) {
194    UnicodeString s((UChar)91/*[*/);
195    s.append(_toString(f));
196    s.append((UChar)0x5d/*]*/);
197    return s;
198}
199
200#endif
201
202// useful when operator+ won't cooperate
203UnicodeString toString(int32_t n) {
204    return UnicodeString() + (long)n;
205}
206
207// stephen - cleaned up 05/05/99
208UnicodeString operator+(const UnicodeString& left, char num)
209{ return left + (long)num; }
210UnicodeString operator+(const UnicodeString& left, short num)
211{ return left + (long)num; }
212UnicodeString operator+(const UnicodeString& left, int num)
213{ return left + (long)num; }
214UnicodeString operator+(const UnicodeString& left, unsigned char num)
215{ return left + (unsigned long)num; }
216UnicodeString operator+(const UnicodeString& left, unsigned short num)
217{ return left + (unsigned long)num; }
218UnicodeString operator+(const UnicodeString& left, unsigned int num)
219{ return left + (unsigned long)num; }
220UnicodeString operator+(const UnicodeString& left, float num)
221{ return left + (double)num; }
222
223//------------------
224
225// Append a hex string to the target
226UnicodeString&
227IntlTest::appendHex(uint32_t number,
228            int32_t digits,
229            UnicodeString& target)
230{
231    static const UChar digitString[] = {
232        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
233        0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0
234    }; /* "0123456789ABCDEF" */
235
236    if (digits < 0) {  // auto-digits
237        digits = 2;
238        uint32_t max = 0xff;
239        while (number > max) {
240            digits += 2;
241            max = (max << 8) | 0xff;
242        }
243    }
244    switch (digits)
245    {
246    case 8:
247        target += digitString[(number >> 28) & 0xF];
248    case 7:
249        target += digitString[(number >> 24) & 0xF];
250    case 6:
251        target += digitString[(number >> 20) & 0xF];
252    case 5:
253        target += digitString[(number >> 16) & 0xF];
254    case 4:
255        target += digitString[(number >> 12) & 0xF];
256    case 3:
257        target += digitString[(number >>  8) & 0xF];
258    case 2:
259        target += digitString[(number >>  4) & 0xF];
260    case 1:
261        target += digitString[(number >>  0) & 0xF];
262        break;
263    default:
264        target += "**";
265    }
266    return target;
267}
268
269UnicodeString
270IntlTest::toHex(uint32_t number, int32_t digits) {
271    UnicodeString result;
272    appendHex(number, digits, result);
273    return result;
274}
275
276static inline UBool isPrintable(UChar32 c) {
277    return c <= 0x7E && (c >= 0x20 || c == 9 || c == 0xA || c == 0xD);
278}
279
280// Replace nonprintable characters with unicode escapes
281UnicodeString&
282IntlTest::prettify(const UnicodeString &source,
283           UnicodeString &target)
284{
285    int32_t i;
286
287    target.remove();
288    target += "\"";
289
290    for (i = 0; i < source.length(); )
291    {
292        UChar32 ch = source.char32At(i);
293        i += U16_LENGTH(ch);
294
295        if (!isPrintable(ch))
296        {
297            if (ch <= 0xFFFF) {
298                target += "\\u";
299                appendHex(ch, 4, target);
300            } else {
301                target += "\\U";
302                appendHex(ch, 8, target);
303            }
304        }
305        else
306        {
307            target += ch;
308        }
309    }
310
311    target += "\"";
312
313    return target;
314}
315
316// Replace nonprintable characters with unicode escapes
317UnicodeString
318IntlTest::prettify(const UnicodeString &source, UBool parseBackslash)
319{
320    int32_t i;
321    UnicodeString target;
322    target.remove();
323    target += "\"";
324
325    for (i = 0; i < source.length();)
326    {
327        UChar32 ch = source.char32At(i);
328        i += U16_LENGTH(ch);
329
330        if (!isPrintable(ch))
331        {
332            if (parseBackslash) {
333                // If we are preceded by an odd number of backslashes,
334                // then this character has already been backslash escaped.
335                // Delete a backslash.
336                int32_t backslashCount = 0;
337                for (int32_t j=target.length()-1; j>=0; --j) {
338                    if (target.charAt(j) == (UChar)92) {
339                        ++backslashCount;
340                    } else {
341                        break;
342                    }
343                }
344                if ((backslashCount % 2) == 1) {
345                    target.truncate(target.length() - 1);
346                }
347            }
348            if (ch <= 0xFFFF) {
349                target += "\\u";
350                appendHex(ch, 4, target);
351            } else {
352                target += "\\U";
353                appendHex(ch, 8, target);
354            }
355        }
356        else
357        {
358            target += ch;
359        }
360    }
361
362    target += "\"";
363
364    return target;
365}
366
367/*  IntlTest::setICU_DATA  - if the ICU_DATA environment variable is not already
368 *                       set, try to deduce the directory in which ICU was built,
369 *                       and set ICU_DATA to "icu/source/data" in that location.
370 *                       The intent is to allow the tests to have a good chance
371 *                       of running without requiring that the user manually set
372 *                       ICU_DATA.  Common data isn't a problem, since it is
373 *                       picked up via a static (build time) reference, but the
374 *                       tests dynamically load some data.
375 */
376void IntlTest::setICU_DATA() {
377    const char *original_ICU_DATA = getenv("ICU_DATA");
378
379    if (original_ICU_DATA != NULL && *original_ICU_DATA != 0) {
380        /*  If the user set ICU_DATA, don't second-guess the person. */
381        return;
382    }
383
384    // U_TOPBUILDDIR is set by the makefiles on UNIXes when building cintltst and intltst
385    //              to point to the top of the build hierarchy, which may or
386    //              may not be the same as the source directory, depending on
387    //              the configure options used.  At any rate,
388    //              set the data path to the built data from this directory.
389    //              The value is complete with quotes, so it can be used
390    //              as-is as a string constant.
391
392#if defined (U_TOPBUILDDIR)
393    {
394        static char env_string[] = U_TOPBUILDDIR "data" U_FILE_SEP_STRING "out" U_FILE_SEP_STRING;
395        u_setDataDirectory(env_string);
396        return;
397    }
398
399#else
400    // Use #else so we don't get compiler warnings due to the return above.
401
402    /* On Windows, the file name obtained from __FILE__ includes a full path.
403     *             This file is "wherever\icu\source\test\cintltst\cintltst.c"
404     *             Change to    "wherever\icu\source\data"
405     */
406    {
407        char p[sizeof(__FILE__) + 10];
408        char *pBackSlash;
409        int i;
410
411        strcpy(p, __FILE__);
412        /* We want to back over three '\' chars.                            */
413        /*   Only Windows should end up here, so looking for '\' is safe.   */
414        for (i=1; i<=3; i++) {
415            pBackSlash = strrchr(p, U_FILE_SEP_CHAR);
416            if (pBackSlash != NULL) {
417                *pBackSlash = 0;        /* Truncate the string at the '\'   */
418            }
419        }
420
421        if (pBackSlash != NULL) {
422            /* We found and truncated three names from the path.
423             *  Now append "source\data" and set the environment
424             */
425            strcpy(pBackSlash, U_FILE_SEP_STRING "data" U_FILE_SEP_STRING "out" U_FILE_SEP_STRING);
426            u_setDataDirectory(p);     /*  p is "ICU_DATA=wherever\icu\source\data"    */
427            return;
428        }
429        else {
430            /* __FILE__ on MSVC7 does not contain the directory */
431            u_setDataDirectory(".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING "data" U_FILE_SEP_STRING "out" U_FILE_SEP_STRING);
432            return;
433        }
434    }
435#endif
436
437    /* No location for the data dir was identifiable.
438     *   Add other fallbacks for the test data location here if the need arises
439     */
440}
441
442
443//--------------------------------------------------------------------------------------
444
445static const int32_t indentLevel_offset = 3;
446static const char delim = '/';
447
448IntlTest* IntlTest::gTest = NULL;
449
450static int32_t execCount = 0;
451
452void it_log( UnicodeString message )
453{
454    if (IntlTest::gTest)
455        IntlTest::gTest->log( message );
456}
457
458void it_logln( UnicodeString message )
459{
460    if (IntlTest::gTest)
461        IntlTest::gTest->logln( message );
462}
463
464void it_logln( void )
465{
466    if (IntlTest::gTest)
467        IntlTest::gTest->logln();
468}
469
470void it_info( UnicodeString message )
471{
472    if (IntlTest::gTest)
473        IntlTest::gTest->info( message );
474}
475
476void it_infoln( UnicodeString message )
477{
478    if (IntlTest::gTest)
479        IntlTest::gTest->infoln( message );
480}
481
482void it_infoln( void )
483{
484    if (IntlTest::gTest)
485        IntlTest::gTest->infoln();
486}
487
488void it_err()
489{
490    if (IntlTest::gTest)
491        IntlTest::gTest->err();
492}
493
494void it_err( UnicodeString message )
495{
496    if (IntlTest::gTest)
497        IntlTest::gTest->err( message );
498}
499
500void it_errln( UnicodeString message )
501{
502    if (IntlTest::gTest)
503        IntlTest::gTest->errln( message );
504}
505
506void it_dataerr( UnicodeString message )
507{
508    if (IntlTest::gTest)
509        IntlTest::gTest->dataerr( message );
510}
511
512void it_dataerrln( UnicodeString message )
513{
514    if (IntlTest::gTest)
515        IntlTest::gTest->dataerrln( message );
516}
517
518IntlTest::IntlTest()
519{
520    caller = NULL;
521    testPath = NULL;
522    LL_linestart = TRUE;
523    errorCount = 0;
524    dataErrorCount = 0;
525    verbose = FALSE;
526    no_time = FALSE;
527    no_err_msg = FALSE;
528    warn_on_missing_data = FALSE;
529    quick = FALSE;
530    leaks = FALSE;
531    threadCount = 1;
532    testoutfp = stdout;
533    LL_indentlevel = indentLevel_offset;
534    numProps = 0;
535    strcpy(basePath, "/");
536}
537
538void IntlTest::setCaller( IntlTest* callingTest )
539{
540    caller = callingTest;
541    if (caller) {
542        warn_on_missing_data = caller->warn_on_missing_data;
543        verbose = caller->verbose;
544        no_err_msg = caller->no_err_msg;
545        quick = caller->quick;
546        testoutfp = caller->testoutfp;
547        LL_indentlevel = caller->LL_indentlevel + indentLevel_offset;
548        numProps = caller->numProps;
549        for (int32_t i = 0; i < numProps; i++) {
550            proplines[i] = caller->proplines[i];
551        }
552    }
553}
554
555UBool IntlTest::callTest( IntlTest& testToBeCalled, char* par )
556{
557    execCount--; // correct a previously assumed test-exec, as this only calls a subtest
558    testToBeCalled.setCaller( this );
559    strcpy(testToBeCalled.basePath, this->basePath );
560    UBool result = testToBeCalled.runTest( testPath, par, testToBeCalled.basePath );
561    strcpy(testToBeCalled.basePath, this->basePath ); // reset it.
562    return result;
563}
564
565void IntlTest::setPath( char* pathVal )
566{
567    this->testPath = pathVal;
568}
569
570UBool IntlTest::setVerbose( UBool verboseVal )
571{
572    UBool rval = this->verbose;
573    this->verbose = verboseVal;
574    return rval;
575}
576
577UBool IntlTest::setNotime( UBool no_time )
578{
579    UBool rval = this->no_time;
580    this->no_time = no_time;
581    return rval;
582}
583
584UBool IntlTest::setWarnOnMissingData( UBool warn_on_missing_dataVal )
585{
586    UBool rval = this->warn_on_missing_data;
587    this->warn_on_missing_data = warn_on_missing_dataVal;
588    return rval;
589}
590
591UBool IntlTest::setNoErrMsg( UBool no_err_msgVal )
592{
593    UBool rval = this->no_err_msg;
594    this->no_err_msg = no_err_msgVal;
595    return rval;
596}
597
598UBool IntlTest::setQuick( UBool quickVal )
599{
600    UBool rval = this->quick;
601    this->quick = quickVal;
602    return rval;
603}
604
605UBool IntlTest::setLeaks( UBool leaksVal )
606{
607    UBool rval = this->leaks;
608    this->leaks = leaksVal;
609    return rval;
610}
611
612int32_t IntlTest::setThreadCount( int32_t count )
613{
614    int32_t rval = this->threadCount;
615    this->threadCount = count;
616    return rval;
617}
618
619int32_t IntlTest::getErrors( void )
620{
621    return errorCount;
622}
623
624int32_t IntlTest::getDataErrors( void )
625{
626    return dataErrorCount;
627}
628
629UBool IntlTest::runTest( char* name, char* par, char *baseName )
630{
631    UBool rval;
632    char* pos = NULL;
633
634    char* baseNameBuffer = NULL;
635
636    if(baseName == NULL) {
637      baseNameBuffer = (char*)malloc(1024);
638      baseName=baseNameBuffer;
639      strcpy(baseName, "/");
640    }
641
642    if (name)
643        pos = strchr( name, delim ); // check if name contains path (by looking for '/')
644    if (pos) {
645        testPath = pos+1;   // store subpath for calling subtest
646        *pos = 0;       // split into two strings
647    }else{
648        testPath = NULL;
649    }
650
651    if (!name || (name[0] == 0) || (strcmp(name, "*") == 0)) {
652      rval = runTestLoop( NULL, par, baseName );
653
654    }else if (strcmp( name, "LIST" ) == 0) {
655        this->usage();
656        rval = TRUE;
657
658    }else{
659      rval = runTestLoop( name, par, baseName );
660    }
661
662    if (pos)
663        *pos = delim;  // restore original value at pos
664    if(baseNameBuffer!=NULL) {
665      free(baseNameBuffer);
666    }
667    return rval;
668}
669
670// call individual tests, to be overriden to call implementations
671void IntlTest::runIndexedTest( int32_t /*index*/, UBool /*exec*/, const char* & /*name*/, char* /*par*/ )
672{
673    // to be overriden by a method like:
674    /*
675    switch (index) {
676        case 0: name = "First Test"; if (exec) FirstTest( par ); break;
677        case 1: name = "Second Test"; if (exec) SecondTest( par ); break;
678        default: name = ""; break;
679    }
680    */
681    this->errln("*** runIndexedTest needs to be overriden! ***");
682}
683
684
685UBool IntlTest::runTestLoop( char* testname, char* par, char *baseName )
686{
687    int32_t    index = 0;
688    const char*   name;
689    UBool  run_this_test;
690    int32_t    lastErrorCount;
691    UBool  rval = FALSE;
692    UBool   lastTestFailed;
693
694    if(baseName == NULL) {
695      printf("ERROR: baseName can't be null.\n");
696      return FALSE;
697    } else {
698      if ((char *)this->basePath != baseName) {
699        strcpy(this->basePath, baseName);
700      }
701    }
702
703    char * saveBaseLoc = baseName+strlen(baseName);
704
705    IntlTest* saveTest = gTest;
706    gTest = this;
707    do {
708        this->runIndexedTest( index, FALSE, name, par );
709        if (strcmp(name,"skip") == 0) {
710            run_this_test = FALSE;
711        } else {
712            if (!name || (name[0] == 0))
713                break;
714            if (!testname) {
715                run_this_test = TRUE;
716            }else{
717                run_this_test = (UBool) (strcmp( name, testname ) == 0);
718            }
719        }
720        if (run_this_test) {
721            lastErrorCount = errorCount;
722            execCount++;
723            char msg[256];
724            sprintf(msg, "%s {", name);
725            LL_message(msg, TRUE);
726            UDate timeStart = uprv_getRawUTCtime();
727            strcpy(saveBaseLoc,name);
728            strcat(saveBaseLoc,"/");
729
730            this->runIndexedTest( index, TRUE, name, par );
731
732            UDate timeStop = uprv_getRawUTCtime();
733            rval = TRUE; // at least one test has been called
734            char secs[256];
735            if(!no_time) {
736              sprintf(secs, "%f", (timeStop-timeStart)/1000.0);
737            } else {
738              secs[0]=0;
739            }
740
741
742            strcpy(saveBaseLoc,name);
743
744
745            ctest_xml_testcase(baseName, name, secs, (lastErrorCount!=errorCount)?"err":NULL);
746
747
748            saveBaseLoc[0]=0; /* reset path */
749
750            if (lastErrorCount == errorCount) {
751                sprintf( msg, "   } OK:   %s ", name );
752                if(!no_time) str_timeDelta(msg+strlen(msg),timeStop-timeStart);
753                lastTestFailed = FALSE;
754            }else{
755                sprintf(msg,  "   } ERRORS (%li) in %s", (long)(errorCount-lastErrorCount), name);
756                if(!no_time) str_timeDelta(msg+strlen(msg),timeStop-timeStart);
757
758                for(int i=0;i<LL_indentlevel;i++) {
759                    errorList += " ";
760                }
761                errorList += name;
762                errorList += "\n";
763                lastTestFailed = TRUE;
764            }
765            LL_indentlevel -= 3;
766            if (lastTestFailed) {
767                LL_message( "", TRUE);
768            }
769            LL_message( msg, TRUE);
770            if (lastTestFailed) {
771                LL_message( "", TRUE);
772            }
773            LL_indentlevel += 3;
774        }
775        index++;
776    }while(name);
777
778    *saveBaseLoc = 0;
779
780    gTest = saveTest;
781    return rval;
782}
783
784
785/**
786* Adds given string to the log if we are in verbose mode.
787*/
788void IntlTest::log( const UnicodeString &message )
789{
790    if( verbose ) {
791        LL_message( message, FALSE );
792    }
793}
794
795/**
796* Adds given string to the log if we are in verbose mode. Adds a new line to
797* the given message.
798*/
799void IntlTest::logln( const UnicodeString &message )
800{
801    if( verbose ) {
802        LL_message( message, TRUE );
803    }
804}
805
806void IntlTest::logln( void )
807{
808    if( verbose ) {
809        LL_message( "", TRUE );
810    }
811}
812
813/**
814* Unconditionally adds given string to the log.
815*/
816void IntlTest::info( const UnicodeString &message )
817{
818  LL_message( message, FALSE );
819}
820
821/**
822* Unconditionally adds given string to the log. Adds a new line to
823* the given message.
824*/
825void IntlTest::infoln( const UnicodeString &message )
826{
827  LL_message( message, TRUE );
828}
829
830void IntlTest::infoln( void )
831{
832  LL_message( "", TRUE );
833}
834
835int32_t IntlTest::IncErrorCount( void )
836{
837    errorCount++;
838    if (caller) caller->IncErrorCount();
839    return errorCount;
840}
841
842int32_t IntlTest::IncDataErrorCount( void )
843{
844    dataErrorCount++;
845    if (caller) caller->IncDataErrorCount();
846    return dataErrorCount;
847}
848
849void IntlTest::err()
850{
851    IncErrorCount();
852}
853
854void IntlTest::err( const UnicodeString &message )
855{
856    IncErrorCount();
857    if (!no_err_msg) LL_message( message, FALSE );
858}
859
860void IntlTest::errln( const UnicodeString &message )
861{
862    IncErrorCount();
863    if (!no_err_msg) LL_message( message, TRUE );
864}
865
866void IntlTest::dataerr( const UnicodeString &message )
867{
868    IncDataErrorCount();
869
870    if (!warn_on_missing_data) {
871        IncErrorCount();
872    }
873
874    if (!no_err_msg) LL_message( message, FALSE );
875}
876
877void IntlTest::dataerrln( const UnicodeString &message )
878{
879    IncDataErrorCount();
880    UnicodeString msg;
881    if (!warn_on_missing_data) {
882        IncErrorCount();
883        msg = message;
884    } else {
885        msg = UnicodeString("[DATA] " + message);
886    }
887
888    if (!no_err_msg) LL_message( msg + " - (Are you missing data?)", TRUE );
889}
890
891void IntlTest::errcheckln(UErrorCode status, const UnicodeString &message ) {
892    if (status == U_FILE_ACCESS_ERROR || status == U_MISSING_RESOURCE_ERROR) {
893        dataerrln(message);
894    } else {
895        errln(message);
896    }
897}
898
899/* convenience functions that include sprintf formatting */
900void IntlTest::log(const char *fmt, ...)
901{
902    char buffer[4000];
903    va_list ap;
904
905    va_start(ap, fmt);
906    /* sprintf it just to make sure that the information is valid */
907    vsprintf(buffer, fmt, ap);
908    va_end(ap);
909    if( verbose ) {
910        log(UnicodeString(buffer, ""));
911    }
912}
913
914void IntlTest::logln(const char *fmt, ...)
915{
916    char buffer[4000];
917    va_list ap;
918
919    va_start(ap, fmt);
920    /* sprintf it just to make sure that the information is valid */
921    vsprintf(buffer, fmt, ap);
922    va_end(ap);
923    if( verbose ) {
924        logln(UnicodeString(buffer, ""));
925    }
926}
927
928/* convenience functions that include sprintf formatting */
929void IntlTest::info(const char *fmt, ...)
930{
931    char buffer[4000];
932    va_list ap;
933
934    va_start(ap, fmt);
935    /* sprintf it just to make sure that the information is valid */
936    vsprintf(buffer, fmt, ap);
937    va_end(ap);
938    info(UnicodeString(buffer, ""));
939}
940
941void IntlTest::infoln(const char *fmt, ...)
942{
943    char buffer[4000];
944    va_list ap;
945
946    va_start(ap, fmt);
947    /* sprintf it just to make sure that the information is valid */
948    vsprintf(buffer, fmt, ap);
949    va_end(ap);
950    infoln(UnicodeString(buffer, ""));
951}
952
953void IntlTest::err(const char *fmt, ...)
954{
955    char buffer[4000];
956    va_list ap;
957
958    va_start(ap, fmt);
959    vsprintf(buffer, fmt, ap);
960    va_end(ap);
961    err(UnicodeString(buffer, ""));
962}
963
964void IntlTest::errln(const char *fmt, ...)
965{
966    char buffer[4000];
967    va_list ap;
968
969    va_start(ap, fmt);
970    vsprintf(buffer, fmt, ap);
971    va_end(ap);
972    errln(UnicodeString(buffer, ""));
973}
974
975void IntlTest::dataerrln(const char *fmt, ...)
976{
977    char buffer[4000];
978    va_list ap;
979
980    va_start(ap, fmt);
981    vsprintf(buffer, fmt, ap);
982    va_end(ap);
983    dataerrln(UnicodeString(buffer, ""));
984}
985
986void IntlTest::errcheckln(UErrorCode status, const char *fmt, ...)
987{
988    char buffer[4000];
989    va_list ap;
990
991    va_start(ap, fmt);
992    vsprintf(buffer, fmt, ap);
993    va_end(ap);
994
995    if (status == U_FILE_ACCESS_ERROR || status == U_MISSING_RESOURCE_ERROR) {
996        dataerrln(UnicodeString(buffer, ""));
997    } else {
998        errln(UnicodeString(buffer, ""));
999    }
1000}
1001
1002void IntlTest::printErrors()
1003{
1004     IntlTest::LL_message(errorList, TRUE);
1005}
1006
1007void IntlTest::LL_message( UnicodeString message, UBool newline )
1008{
1009    // string that starts with a LineFeed character and continues
1010    // with spaces according to the current indentation
1011    static const UChar indentUChars[] = {
1012        '\n',
1013        32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1014        32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1015        32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1016        32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1017        32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1018        32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1019        32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1020        32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1021        32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1022        32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32
1023    };
1024    UnicodeString indent(FALSE, indentUChars, 1 + LL_indentlevel);
1025
1026    char buffer[10000];
1027    int32_t length;
1028
1029    // stream out the indentation string first if necessary
1030    length = indent.extract(1, indent.length(), buffer, sizeof(buffer));
1031    if (length > 0) {
1032        fwrite(buffer, sizeof(*buffer), length, (FILE *)testoutfp);
1033    }
1034
1035    // replace each LineFeed by the indentation string
1036    message.findAndReplace(UnicodeString((UChar)'\n'), indent);
1037
1038    // stream out the message
1039    length = message.extract(0, message.length(), buffer, sizeof(buffer));
1040    if (length > 0) {
1041        length = length > 10000 ? 10000 : length;
1042        fwrite(buffer, sizeof(*buffer), length, (FILE *)testoutfp);
1043    }
1044
1045    if (newline) {
1046        char newLine = '\n';
1047        fwrite(&newLine, sizeof(newLine), 1, (FILE *)testoutfp);
1048    }
1049
1050    // A newline usually flushes the buffer, but
1051    // flush the message just in case of a core dump.
1052    fflush((FILE *)testoutfp);
1053}
1054
1055/**
1056* Print a usage message for this test class.
1057*/
1058void IntlTest::usage( void )
1059{
1060    UBool save_verbose = setVerbose( TRUE );
1061    logln("Test names:");
1062    logln("-----------");
1063
1064    int32_t index = 0;
1065    const char* name = NULL;
1066    do{
1067        this->runIndexedTest( index, FALSE, name );
1068        if (!name) break;
1069        logln(name);
1070        index++;
1071    }while (name && (name[0] != 0));
1072    setVerbose( save_verbose );
1073}
1074
1075
1076// memory leak reporting software will be able to take advantage of the testsuite
1077// being run a second time local to a specific method in order to report only actual leaks
1078UBool
1079IntlTest::run_phase2( char* name, char* par ) // supports reporting memory leaks
1080{
1081    UnicodeString* strLeak = new UnicodeString("forced leak"); // for verifying purify filter
1082    strLeak->append(" for verifying purify filter");
1083    return this->runTest( name, par );
1084}
1085
1086
1087#if UCONFIG_NO_LEGACY_CONVERSION
1088#   define TRY_CNV_1 "iso-8859-1"
1089#   define TRY_CNV_2 "ibm-1208"
1090#else
1091#   define TRY_CNV_1 "iso-8859-7"
1092#   define TRY_CNV_2 "sjis"
1093#endif
1094
1095int
1096main(int argc, char* argv[])
1097{
1098    UBool syntax = FALSE;
1099    UBool all = FALSE;
1100    UBool verbose = FALSE;
1101    UBool no_err_msg = FALSE;
1102    UBool no_time = FALSE;
1103    UBool quick = TRUE;
1104    UBool name = FALSE;
1105    UBool leaks = FALSE;
1106    UBool warnOnMissingData = FALSE;
1107    UBool defaultDataFound = FALSE;
1108    int32_t threadCount = 1;
1109    UErrorCode errorCode = U_ZERO_ERROR;
1110    UConverter *cnv = NULL;
1111    const char *warnOrErr = "Failure";
1112    UDate startTime, endTime;
1113    int32_t diffTime;
1114    const char *props[IntlTest::kMaxProps];
1115    int32_t nProps = 0;
1116
1117    U_MAIN_INIT_ARGS(argc, argv);
1118
1119    startTime = uprv_getRawUTCtime();
1120
1121    for (int i = 1; i < argc; ++i) {
1122        if (argv[i][0] == '-') {
1123            const char* str = argv[i] + 1;
1124            if (strcmp("verbose", str) == 0 ||
1125                strcmp("v", str) == 0)
1126                verbose = TRUE;
1127            else if (strcmp("noerrormsg", str) == 0 ||
1128                     strcmp("n", str) == 0)
1129                no_err_msg = TRUE;
1130            else if (strcmp("exhaustive", str) == 0 ||
1131                     strcmp("e", str) == 0)
1132                quick = FALSE;
1133            else if (strcmp("all", str) == 0 ||
1134                     strcmp("a", str) == 0)
1135                all = TRUE;
1136            else if (strcmp("leaks", str) == 0 ||
1137                     strcmp("l", str) == 0)
1138                leaks = TRUE;
1139            else if (strcmp("notime", str) == 0 ||
1140                     strcmp("T", str) == 0)
1141                no_time = TRUE;
1142            else if (strcmp("x", str)==0) {
1143              if(++i>=argc) {
1144                printf("* Error: '-x' option requires an argument. usage: '-x outfile.xml'.\n");
1145                syntax = TRUE;
1146              }
1147              if(ctest_xml_setFileName(argv[i])) { /* set the name */
1148                return 1; /* error */
1149              }
1150            } else if (strcmp("w", str) == 0) {
1151              warnOnMissingData = TRUE;
1152              warnOrErr = "WARNING";
1153            }
1154            else if (strncmp("threads:", str, 8) == 0) {
1155                threadCount = atoi(str + 8);
1156            }
1157            else if (strncmp("prop:", str, 5) == 0) {
1158                if (nProps < IntlTest::kMaxProps) {
1159                    props[nProps] = str + 5;
1160                }
1161                nProps++;
1162            }
1163            else {
1164                syntax = TRUE;
1165            }
1166        }else{
1167            name = TRUE;
1168        }
1169    }
1170
1171    if (!all && !name) {
1172        all = TRUE;
1173    } else if (all && name) {
1174        syntax = TRUE;
1175    }
1176
1177    if (syntax) {
1178        fprintf(stdout,
1179                "### Syntax:\n"
1180                "### IntlTest [-option1 -option2 ...] [testname1 testname2 ...] \n"
1181                "### \n"
1182                "### Options are: verbose (v), all (a), noerrormsg (n), \n"
1183                "### exhaustive (e), leaks (l), -x xmlfile.xml, prop:<propery>=<value>, \n"
1184                "### notime (T), \n"
1185                "### threads:<threadCount> (Mulithreading must first be \n"
1186                "###     enabled otherwise this will be ignored. \n"
1187                "###     The default thread count is 1.),\n"
1188                "### (Specify either -all (shortcut -a) or a test name). \n"
1189                "### -all will run all of the tests.\n"
1190                "### \n"
1191                "### To get a list of the test names type: intltest LIST \n"
1192                "### To run just the utility tests type: intltest utility \n"
1193                "### \n"
1194                "### Test names can be nested using slashes (\"testA/subtest1\") \n"
1195                "### For example to list the utility tests type: intltest utility/LIST \n"
1196                "### To run just the Locale test type: intltest utility/LocaleTest \n"
1197                "### \n"
1198                "### A parameter can be specified for a test by appending '@' and the value \n"
1199                "### to the testname. \n\n");
1200        return 1;
1201    }
1202
1203    if (nProps > IntlTest::kMaxProps) {
1204        fprintf(stdout, "### Too many properties.  Exiting.\n");
1205    }
1206
1207    UBool all_tests_exist = TRUE;
1208    MajorTestLevel major;
1209    major.setVerbose( verbose );
1210    major.setNoErrMsg( no_err_msg );
1211    major.setQuick( quick );
1212    major.setLeaks( leaks );
1213    major.setThreadCount( threadCount );
1214    major.setWarnOnMissingData( warnOnMissingData );
1215    major.setNotime (no_time);
1216    for (int32_t i = 0; i < nProps; i++) {
1217        major.setProperty(props[i]);
1218    }
1219
1220
1221    fprintf(stdout, "-----------------------------------------------\n");
1222    fprintf(stdout, " IntlTest (C++) Test Suite for                 \n");
1223    fprintf(stdout, "   International Components for Unicode %s\n", U_ICU_VERSION);
1224
1225
1226    {
1227	const char *charsetFamily = "Unknown";
1228        int32_t voidSize = (int32_t)sizeof(void*);
1229        int32_t bits = voidSize * 8;
1230        if(U_CHARSET_FAMILY==U_ASCII_FAMILY) {
1231           charsetFamily="ASCII";
1232        } else if(U_CHARSET_FAMILY==U_EBCDIC_FAMILY) {
1233           charsetFamily="EBCDIC";
1234        }
1235        fprintf(stdout,
1236                    "   Bits: %d, Byte order: %s, Chars: %s\n",
1237                     bits, U_IS_BIG_ENDIAN?"Big endian":"Little endian",
1238                     charsetFamily);
1239    }
1240    fprintf(stdout, "-----------------------------------------------\n");
1241    fprintf(stdout, " Options:                                       \n");
1242    fprintf(stdout, "   all (a)                  : %s\n", (all?               "On" : "Off"));
1243    fprintf(stdout, "   Verbose (v)              : %s\n", (verbose?           "On" : "Off"));
1244    fprintf(stdout, "   No error messages (n)    : %s\n", (no_err_msg?        "On" : "Off"));
1245    fprintf(stdout, "   Exhaustive (e)           : %s\n", (!quick?            "On" : "Off"));
1246    fprintf(stdout, "   Leaks (l)                : %s\n", (leaks?             "On" : "Off"));
1247    fprintf(stdout, "   notime (T)               : %s\n", (no_time?             "On" : "Off"));
1248    fprintf(stdout, "   Warn on missing data (w) : %s\n", (warnOnMissingData? "On" : "Off"));
1249#if (ICU_USE_THREADS==0)
1250    fprintf(stdout, "   Threads                  : Disabled\n");
1251#else
1252    fprintf(stdout, "   Threads                  : %d\n", threadCount);
1253#endif
1254    for (int32_t i = 0; i < nProps; i++) {
1255        fprintf(stdout, "   Custom property (prop:)  : %s\n", props[i]);
1256    }
1257    fprintf(stdout, "-----------------------------------------------\n");
1258
1259    /* Check whether ICU will initialize without forcing the build data directory into
1260     *  the ICU_DATA path.  Success here means either the data dll contains data, or that
1261     *  this test program was run with ICU_DATA set externally.  Failure of this check
1262     *  is normal when ICU data is not packaged into a shared library.
1263     *
1264     *  Whether or not this test succeeds, we want to cleanup and reinitialize
1265     *  with a data path so that data loading from individual files can be tested.
1266     */
1267    u_init(&errorCode);
1268    if (U_FAILURE(errorCode)) {
1269        fprintf(stderr,
1270            "#### Note:  ICU Init without build-specific setDataDirectory() failed.\n");
1271        defaultDataFound = FALSE;
1272    }
1273    else {
1274        defaultDataFound = TRUE;
1275    }
1276    u_cleanup();
1277    errorCode = U_ZERO_ERROR;
1278
1279    /* Initialize ICU */
1280    if (!defaultDataFound) {
1281        IntlTest::setICU_DATA();   // Must set data directory before u_init() is called.
1282    }
1283    u_init(&errorCode);
1284    if (U_FAILURE(errorCode)) {
1285        fprintf(stderr,
1286            "#### ERROR! %s: u_init() failed with status = \"%s\".\n"
1287            "*** Check the ICU_DATA environment variable and \n"
1288            "*** check that the data files are present.\n", argv[0], u_errorName(errorCode));
1289            if(warnOnMissingData == 0) {
1290                fprintf(stderr, "*** Exiting.  Use the '-w' option if data files were\n*** purposely removed, to continue test anyway.\n");
1291                u_cleanup();
1292                return 1;
1293            }
1294    }
1295
1296
1297    // initial check for the default converter
1298    errorCode = U_ZERO_ERROR;
1299    cnv = ucnv_open(0, &errorCode);
1300    if(cnv != 0) {
1301        // ok
1302        ucnv_close(cnv);
1303    } else {
1304        fprintf(stdout,
1305                "*** %s! The default converter [%s] cannot be opened.\n"
1306                "*** Check the ICU_DATA environment variable and\n"
1307                "*** check that the data files are present.\n",
1308                warnOrErr, ucnv_getDefaultName());
1309        if(!warnOnMissingData) {
1310          fprintf(stdout, "*** Exiting.  Use the '-w' option if data files were\n*** purposely removed, to continue test anyway.\n");
1311          return 1;
1312        }
1313    }
1314
1315    // try more data
1316    cnv = ucnv_open(TRY_CNV_2, &errorCode);
1317    if(cnv != 0) {
1318        // ok
1319        ucnv_close(cnv);
1320    } else {
1321        fprintf(stdout,
1322                "*** %s! The converter for " TRY_CNV_2 " cannot be opened.\n"
1323                "*** Check the ICU_DATA environment variable and \n"
1324                "*** check that the data files are present.\n", warnOrErr);
1325        if(!warnOnMissingData) {
1326          fprintf(stdout, "*** Exiting.  Use the '-w' option if data files were\n*** purposely removed, to continue test anyway.\n");
1327          return 1;
1328        }
1329    }
1330
1331    UResourceBundle *rb = ures_open(0, "en", &errorCode);
1332    ures_close(rb);
1333    if(U_FAILURE(errorCode)) {
1334        fprintf(stdout,
1335                "*** %s! The \"en\" locale resource bundle cannot be opened.\n"
1336                "*** Check the ICU_DATA environment variable and \n"
1337                "*** check that the data files are present.\n", warnOrErr);
1338        if(!warnOnMissingData) {
1339          fprintf(stdout, "*** Exiting.  Use the '-w' option if data files were\n*** purposely removed, to continue test anyway.\n");
1340          return 1;
1341        }
1342    }
1343
1344    Locale originalLocale;  // Save the default locale for comparison later on.
1345
1346    if(ctest_xml_init("intltest"))
1347      return 1;
1348
1349
1350    /* TODO: Add option to call u_cleanup and rerun tests. */
1351    if (all) {
1352        major.runTest();
1353        if (leaks) {
1354            major.run_phase2( NULL, NULL );
1355        }
1356    }else{
1357        for (int i = 1; i < argc; ++i) {
1358            if (argv[i][0] != '-') {
1359                char* name = argv[i];
1360                fprintf(stdout, "\n=== Handling test: %s: ===\n", name);
1361
1362                char baseName[1024];
1363                sprintf(baseName, "/%s/", name);
1364
1365                char* parameter = strchr( name, '@' );
1366                if (parameter) {
1367                    *parameter = 0;
1368                    parameter += 1;
1369                }
1370                execCount = 0;
1371                UBool res = major.runTest( name, parameter, baseName );
1372                if (leaks && res) {
1373                    major.run_phase2( name, parameter );
1374                }
1375                if (!res || (execCount <= 0)) {
1376                    fprintf(stdout, "\n---ERROR: Test doesn't exist: %s!\n", name);
1377                    all_tests_exist = FALSE;
1378                }
1379            } else if(!strcmp(argv[i],"-x")) {
1380              i++;
1381            }
1382        }
1383    }
1384
1385
1386#if !UCONFIG_NO_FORMATTING
1387    CalendarTimeZoneTest::cleanup();
1388#endif
1389
1390    free(_testDataPath);
1391    _testDataPath = 0;
1392
1393    Locale lastDefaultLocale;
1394    if (originalLocale != lastDefaultLocale) {
1395        major.errln("FAILURE: A test changed the default locale without resetting it.");
1396    }
1397
1398    fprintf(stdout, "\n--------------------------------------\n");
1399    if (major.getErrors() == 0) {
1400        /* Call it twice to make sure that the defaults were reset. */
1401        /* Call it before the OK message to verify proper cleanup. */
1402        u_cleanup();
1403        u_cleanup();
1404
1405        fprintf(stdout, "OK: All tests passed without error.\n");
1406
1407        if (major.getDataErrors() != 0) {
1408            fprintf(stdout, "\t*WARNING* some data-loading errors were ignored by the -w option.\n");
1409        }
1410    }else{
1411        fprintf(stdout, "Errors in total: %ld.\n", (long)major.getErrors());
1412        major.printErrors();
1413
1414
1415        if (major.getDataErrors() != 0) {
1416            fprintf(stdout, "\t*Note* some errors are data-loading related. If the data used is not the \n"
1417                    "\tstock ICU data (i.e some have been added or removed), consider using\n"
1418                    "\tthe '-w' option to turn these errors into warnings.\n");
1419        }
1420
1421        /* Call afterwards to display errors. */
1422        u_cleanup();
1423    }
1424
1425    fprintf(stdout, "--------------------------------------\n");
1426
1427    if (execCount <= 0) {
1428        fprintf(stdout, "***** Not all called tests actually exist! *****\n");
1429    }
1430    if(!no_time) {
1431      endTime = uprv_getRawUTCtime();
1432      diffTime = (int32_t)(endTime - startTime);
1433      printf("Elapsed Time: %02d:%02d:%02d.%03d\n",
1434             (int)((diffTime%U_MILLIS_PER_DAY)/U_MILLIS_PER_HOUR),
1435             (int)((diffTime%U_MILLIS_PER_HOUR)/U_MILLIS_PER_MINUTE),
1436             (int)((diffTime%U_MILLIS_PER_MINUTE)/U_MILLIS_PER_SECOND),
1437             (int)(diffTime%U_MILLIS_PER_SECOND));
1438    }
1439
1440    if(ctest_xml_fini())
1441      return 1;
1442
1443    return major.getErrors();
1444}
1445
1446const char* IntlTest::loadTestData(UErrorCode& err){
1447    if( _testDataPath == NULL){
1448        const char*      directory=NULL;
1449        UResourceBundle* test =NULL;
1450        char* tdpath=NULL;
1451        const char* tdrelativepath;
1452
1453#if defined (U_TOPBUILDDIR)
1454        tdrelativepath = "test" U_FILE_SEP_STRING "testdata" U_FILE_SEP_STRING "out" U_FILE_SEP_STRING;
1455        directory = U_TOPBUILDDIR;
1456#else
1457        tdrelativepath = ".." U_FILE_SEP_STRING "test" U_FILE_SEP_STRING "testdata" U_FILE_SEP_STRING "out" U_FILE_SEP_STRING;
1458        directory = pathToDataDirectory();
1459#endif
1460
1461        tdpath = (char*) malloc(sizeof(char) *(( strlen(directory) * strlen(tdrelativepath)) + 100));
1462
1463
1464        /* u_getDataDirectory shoul return \source\data ... set the
1465         * directory to ..\source\data\..\test\testdata\out\testdata
1466         */
1467        strcpy(tdpath, directory);
1468        strcat(tdpath, tdrelativepath);
1469        strcat(tdpath,"testdata");
1470
1471        test=ures_open(tdpath, "testtypes", &err);
1472
1473        if(U_FAILURE(err)){
1474            err = U_FILE_ACCESS_ERROR;
1475            it_dataerrln((UnicodeString)"Could not load testtypes.res in testdata bundle with path " + tdpath + (UnicodeString)" - " + u_errorName(err));
1476            return "";
1477        }
1478        ures_close(test);
1479        _testDataPath = tdpath;
1480        return _testDataPath;
1481    }
1482    return _testDataPath;
1483}
1484
1485const char* IntlTest::getTestDataPath(UErrorCode& err) {
1486    return loadTestData(err);
1487}
1488
1489/* Returns the path to icu/source/test/testdata/ */
1490const char *IntlTest::getSourceTestData(UErrorCode& /*err*/) {
1491    const char *srcDataDir = NULL;
1492#ifdef U_TOPSRCDIR
1493    srcDataDir = U_TOPSRCDIR U_FILE_SEP_STRING"test" U_FILE_SEP_STRING "testdata" U_FILE_SEP_STRING;
1494#else
1495    srcDataDir = ".." U_FILE_SEP_STRING ".." U_FILE_SEP_STRING "test" U_FILE_SEP_STRING "testdata" U_FILE_SEP_STRING;
1496    FILE *f = fopen(".." U_FILE_SEP_STRING ".." U_FILE_SEP_STRING "test" U_FILE_SEP_STRING "testdata" U_FILE_SEP_STRING "rbbitst.txt", "r");
1497    if (f) {
1498        /* We're in icu/source/test/intltest/ */
1499        fclose(f);
1500    }
1501    else {
1502        /* We're in icu/source/test/intltest/Platform/(Debug|Release) */
1503        srcDataDir = ".." U_FILE_SEP_STRING ".." U_FILE_SEP_STRING ".." U_FILE_SEP_STRING ".." U_FILE_SEP_STRING "test" U_FILE_SEP_STRING "testdata"U_FILE_SEP_STRING;
1504    }
1505#endif
1506    return srcDataDir;
1507}
1508
1509const char* IntlTest::fgDataDir = NULL;
1510
1511/* returns the path to icu/source/data */
1512const char *  IntlTest::pathToDataDirectory()
1513{
1514
1515    if(fgDataDir != NULL) {
1516        return fgDataDir;
1517    }
1518
1519    /* U_TOPSRCDIR is set by the makefiles on UNIXes when building cintltst and intltst
1520    //              to point to the top of the build hierarchy, which may or
1521    //              may not be the same as the source directory, depending on
1522    //              the configure options used.  At any rate,
1523    //              set the data path to the built data from this directory.
1524    //              The value is complete with quotes, so it can be used
1525    //              as-is as a string constant.
1526    */
1527#if defined (U_TOPSRCDIR)
1528    {
1529        fgDataDir = U_TOPSRCDIR  U_FILE_SEP_STRING "data" U_FILE_SEP_STRING;
1530    }
1531#else
1532
1533    /* On Windows, the file name obtained from __FILE__ includes a full path.
1534     *             This file is "wherever\icu\source\test\cintltst\cintltst.c"
1535     *             Change to    "wherever\icu\source\data"
1536     */
1537    {
1538        static char p[sizeof(__FILE__) + 10];
1539        char *pBackSlash;
1540        int i;
1541
1542        strcpy(p, __FILE__);
1543        /* We want to back over three '\' chars.                            */
1544        /*   Only Windows should end up here, so looking for '\' is safe.   */
1545        for (i=1; i<=3; i++) {
1546            pBackSlash = strrchr(p, U_FILE_SEP_CHAR);
1547            if (pBackSlash != NULL) {
1548                *pBackSlash = 0;        /* Truncate the string at the '\'   */
1549            }
1550        }
1551
1552        if (pBackSlash != NULL) {
1553            /* We found and truncated three names from the path.
1554            *  Now append "source\data" and set the environment
1555            */
1556            strcpy(pBackSlash, U_FILE_SEP_STRING "data" U_FILE_SEP_STRING );
1557            fgDataDir = p;
1558        }
1559        else {
1560            /* __FILE__ on MSVC7 does not contain the directory */
1561            FILE *file = fopen(".." U_FILE_SEP_STRING ".."U_FILE_SEP_STRING "data" U_FILE_SEP_STRING "Makefile.in", "r");
1562            if (file) {
1563                fclose(file);
1564                fgDataDir = ".." U_FILE_SEP_STRING ".."U_FILE_SEP_STRING "data" U_FILE_SEP_STRING;
1565            }
1566            else {
1567                fgDataDir = ".." U_FILE_SEP_STRING ".." U_FILE_SEP_STRING ".." U_FILE_SEP_STRING ".."U_FILE_SEP_STRING "data" U_FILE_SEP_STRING;
1568            }
1569        }
1570    }
1571#endif
1572
1573    return fgDataDir;
1574
1575}
1576
1577/*
1578 * This is a variant of cintltst/ccolltst.c:CharsToUChars().
1579 * It converts an invariant-character string into a UnicodeString, with
1580 * unescaping \u sequences.
1581 */
1582UnicodeString CharsToUnicodeString(const char* chars){
1583    return UnicodeString(chars, -1, US_INV).unescape();
1584}
1585
1586UnicodeString ctou(const char* chars) {
1587    return CharsToUnicodeString(chars);
1588}
1589
1590#define RAND_M  (714025)
1591#define RAND_IA (1366)
1592#define RAND_IC (150889)
1593
1594static int32_t RAND_SEED;
1595
1596/**
1597 * Returns a uniform random value x, with 0.0 <= x < 1.0.  Use
1598 * with care: Does not return all possible values; returns one of
1599 * 714,025 values, uniformly spaced.  However, the period is
1600 * effectively infinite.  See: Numerical Recipes, section 7.1.
1601 *
1602 * @param seedp pointer to seed. Set *seedp to any negative value
1603 * to restart the sequence.
1604 */
1605float IntlTest::random(int32_t* seedp) {
1606    static int32_t iy, ir[98];
1607    static UBool first=TRUE;
1608    int32_t j;
1609    if (*seedp < 0 || first) {
1610        first = FALSE;
1611        if ((*seedp=(RAND_IC-(*seedp)) % RAND_M) < 0) *seedp = -(*seedp);
1612        for (j=1;j<=97;++j) {
1613            *seedp=(RAND_IA*(*seedp)+RAND_IC) % RAND_M;
1614            ir[j]=(*seedp);
1615        }
1616        *seedp=(RAND_IA*(*seedp)+RAND_IC) % RAND_M;
1617        iy=(*seedp);
1618    }
1619    j=(int32_t)(1 + 97.0*iy/RAND_M);
1620    U_ASSERT(j>=1 && j<=97);
1621    iy=ir[j];
1622    *seedp=(RAND_IA*(*seedp)+RAND_IC) % RAND_M;
1623    ir[j]=(*seedp);
1624    return (float) iy/RAND_M;
1625}
1626
1627/**
1628 * Convenience method using a global seed.
1629 */
1630float IntlTest::random() {
1631    return random(&RAND_SEED);
1632}
1633
1634static inline UChar toHex(int32_t i) {
1635    return (UChar)(i + (i < 10 ? 0x30 : (0x41 - 10)));
1636}
1637
1638static UnicodeString& escape(const UnicodeString& s, UnicodeString& result) {
1639    for (int32_t i=0; i<s.length(); ++i) {
1640        UChar c = s[i];
1641        if (c <= (UChar)0x7F) {
1642            result += c;
1643        } else {
1644            result += (UChar)0x5c;
1645            result += (UChar)0x75;
1646            result += toHex((c >> 12) & 0xF);
1647            result += toHex((c >>  8) & 0xF);
1648            result += toHex((c >>  4) & 0xF);
1649            result += toHex( c        & 0xF);
1650        }
1651    }
1652    return result;
1653}
1654
1655#define VERBOSE_ASSERTIONS
1656
1657UBool IntlTest::assertTrue(const char* message, UBool condition, UBool quiet, UBool possibleDataError, const char *file, int line) {
1658    if (file != NULL) {
1659        if (!condition) {
1660            if (possibleDataError) {
1661                dataerrln("%s:%d: FAIL: assertTrue() failed: %s", file, line, message);
1662            } else {
1663                errln("%s:%d: FAIL: assertTrue() failed: %s", file, line, message);
1664            }
1665        } else if (!quiet) {
1666            logln("%s:%d: Ok: %s", file, line, message);
1667        }
1668    } else {
1669        if (!condition) {
1670            if (possibleDataError) {
1671                dataerrln("FAIL: assertTrue() failed: %s", message);
1672            } else {
1673                errln("FAIL: assertTrue() failed: %s", message);
1674            }
1675        } else if (!quiet) {
1676            logln("Ok: %s", message);
1677        }
1678
1679    }
1680    return condition;
1681}
1682
1683UBool IntlTest::assertFalse(const char* message, UBool condition, UBool quiet) {
1684    if (condition) {
1685        errln("FAIL: assertFalse() failed: %s", message);
1686    } else if (!quiet) {
1687        logln("Ok: %s", message);
1688    }
1689    return !condition;
1690}
1691
1692UBool IntlTest::assertSuccess(const char* message, UErrorCode ec, UBool possibleDataError) {
1693    if (U_FAILURE(ec)) {
1694        if (possibleDataError) {
1695            dataerrln("FAIL: %s (%s)", message, u_errorName(ec));
1696        } else {
1697            errcheckln(ec, "FAIL: %s (%s)", message, u_errorName(ec));
1698        }
1699
1700        return FALSE;
1701    }
1702    return TRUE;
1703}
1704
1705UBool IntlTest::assertEquals(const char* message,
1706                             const UnicodeString& expected,
1707                             const UnicodeString& actual,
1708                             UBool possibleDataError) {
1709    if (expected != actual) {
1710        if (possibleDataError) {
1711            dataerrln((UnicodeString)"FAIL: " + message + "; got " +
1712                  prettify(actual) +
1713                  "; expected " + prettify(expected));
1714        } else {
1715            errln((UnicodeString)"FAIL: " + message + "; got " +
1716                  prettify(actual) +
1717                  "; expected " + prettify(expected));
1718        }
1719        return FALSE;
1720    }
1721#ifdef VERBOSE_ASSERTIONS
1722    else {
1723        logln((UnicodeString)"Ok: " + message + "; got " + prettify(actual));
1724    }
1725#endif
1726    return TRUE;
1727}
1728
1729UBool IntlTest::assertEquals(const char* message,
1730                             const char* expected,
1731                             const char* actual) {
1732    if (uprv_strcmp(expected, actual) != 0) {
1733        errln((UnicodeString)"FAIL: " + message + "; got \"" +
1734              actual +
1735              "\"; expected \"" + expected + "\"");
1736        return FALSE;
1737    }
1738#ifdef VERBOSE_ASSERTIONS
1739    else {
1740        logln((UnicodeString)"Ok: " + message + "; got \"" + actual + "\"");
1741    }
1742#endif
1743    return TRUE;
1744}
1745
1746UBool IntlTest::assertEquals(const char* message,
1747                             int32_t expected,
1748                             int32_t actual) {
1749    if (expected != actual) {
1750        errln((UnicodeString)"FAIL: " + message + "; got " +
1751              actual + "=0x" + toHex(actual) +
1752              "; expected " + expected + "=0x" + toHex(expected));
1753        return FALSE;
1754    }
1755#ifdef VERBOSE_ASSERTIONS
1756    else {
1757        logln((UnicodeString)"Ok: " + message + "; got " + actual + "=0x" + toHex(actual));
1758    }
1759#endif
1760    return TRUE;
1761}
1762
1763#if !UCONFIG_NO_FORMATTING
1764UBool IntlTest::assertEquals(const char* message,
1765                             const Formattable& expected,
1766                             const Formattable& actual) {
1767    if (expected != actual) {
1768        errln((UnicodeString)"FAIL: " + message + "; got " +
1769              toString(actual) +
1770              "; expected " + toString(expected));
1771        return FALSE;
1772    }
1773#ifdef VERBOSE_ASSERTIONS
1774    else {
1775        logln((UnicodeString)"Ok: " + message + "; got " + toString(actual));
1776    }
1777#endif
1778    return TRUE;
1779}
1780#endif
1781
1782static char ASSERT_BUF[256];
1783
1784static const char* extractToAssertBuf(const UnicodeString& message) {
1785    UnicodeString buf;
1786    escape(message, buf);
1787    buf.extract(0, 0x7FFFFFFF, ASSERT_BUF, sizeof(ASSERT_BUF)-1, 0);
1788    ASSERT_BUF[sizeof(ASSERT_BUF)-1] = 0;
1789    return ASSERT_BUF;
1790}
1791
1792UBool IntlTest::assertTrue(const UnicodeString& message, UBool condition, UBool quiet) {
1793    return assertTrue(extractToAssertBuf(message), condition, quiet);
1794}
1795
1796UBool IntlTest::assertFalse(const UnicodeString& message, UBool condition, UBool quiet) {
1797    return assertFalse(extractToAssertBuf(message), condition, quiet);
1798}
1799
1800UBool IntlTest::assertSuccess(const UnicodeString& message, UErrorCode ec) {
1801    return assertSuccess(extractToAssertBuf(message), ec);
1802}
1803
1804UBool IntlTest::assertEquals(const UnicodeString& message,
1805                             const UnicodeString& expected,
1806                             const UnicodeString& actual) {
1807    return assertEquals(extractToAssertBuf(message), expected, actual);
1808}
1809
1810UBool IntlTest::assertEquals(const UnicodeString& message,
1811                             const char* expected,
1812                             const char* actual) {
1813    return assertEquals(extractToAssertBuf(message), expected, actual);
1814}
1815//--------------------------------------------------------------------
1816// Time bomb - allows temporary behavior that expires at a given
1817//             release
1818//--------------------------------------------------------------------
1819
1820UBool IntlTest::isICUVersionBefore(int major, int minor, int milli) {
1821    UVersionInfo iv;
1822    UVersionInfo ov = { (uint8_t)major, (uint8_t)minor, (uint8_t)milli, 0 };
1823    u_getVersion(iv);
1824    return uprv_memcmp(iv, ov, U_MAX_VERSION_LENGTH) < 0;
1825}
1826
1827#if !UCONFIG_NO_FORMATTING
1828UBool IntlTest::assertEquals(const UnicodeString& message,
1829                             const Formattable& expected,
1830                             const Formattable& actual) {
1831    return assertEquals(extractToAssertBuf(message), expected, actual);
1832}
1833#endif
1834
1835void IntlTest::setProperty(const char* propline) {
1836    if (numProps < kMaxProps) {
1837        proplines[numProps] = propline;
1838    }
1839    numProps++;
1840}
1841
1842const char* IntlTest::getProperty(const char* prop) {
1843    const char* val = NULL;
1844    for (int32_t i = 0; i < numProps; i++) {
1845        int32_t plen = uprv_strlen(prop);
1846        if ((int32_t)uprv_strlen(proplines[i]) > plen + 1
1847                && proplines[i][plen] == '='
1848                && uprv_strncmp(proplines[i], prop, plen) == 0) {
1849            val = &(proplines[i][plen+1]);
1850            break;
1851        }
1852    }
1853    return val;
1854}
1855
1856/*
1857 * Hey, Emacs, please set the following:
1858 *
1859 * Local Variables:
1860 * indent-tabs-mode: nil
1861 * End:
1862 *
1863 */
1864