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