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