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