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