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