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