1 /********************************************************************
2 * COPYRIGHT:
3 * Copyright (c) 1997-2013, 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,const char * file,int line)1657 UBool IntlTest::assertTrue(const char* message, UBool condition, UBool quiet, UBool possibleDataError, const char *file, int line) {
1658 if (file != NULL) {
1659 if (!condition) {
1660 if (possibleDataError) {
1661 dataerrln("%s:%d: FAIL: assertTrue() failed: %s", file, line, message);
1662 } else {
1663 errln("%s:%d: FAIL: assertTrue() failed: %s", file, line, message);
1664 }
1665 } else if (!quiet) {
1666 logln("%s:%d: Ok: %s", file, line, message);
1667 }
1668 } else {
1669 if (!condition) {
1670 if (possibleDataError) {
1671 dataerrln("FAIL: assertTrue() failed: %s", message);
1672 } else {
1673 errln("FAIL: assertTrue() failed: %s", message);
1674 }
1675 } else if (!quiet) {
1676 logln("Ok: %s", message);
1677 }
1678
1679 }
1680 return condition;
1681 }
1682
assertFalse(const char * message,UBool condition,UBool quiet)1683 UBool IntlTest::assertFalse(const char* message, UBool condition, UBool quiet) {
1684 if (condition) {
1685 errln("FAIL: assertFalse() failed: %s", message);
1686 } else if (!quiet) {
1687 logln("Ok: %s", message);
1688 }
1689 return !condition;
1690 }
1691
assertSuccess(const char * message,UErrorCode ec,UBool possibleDataError)1692 UBool IntlTest::assertSuccess(const char* message, UErrorCode ec, UBool possibleDataError) {
1693 if (U_FAILURE(ec)) {
1694 if (possibleDataError) {
1695 dataerrln("FAIL: %s (%s)", message, u_errorName(ec));
1696 } else {
1697 errcheckln(ec, "FAIL: %s (%s)", message, u_errorName(ec));
1698 }
1699
1700 return FALSE;
1701 }
1702 return TRUE;
1703 }
1704
assertEquals(const char * message,const UnicodeString & expected,const UnicodeString & actual,UBool possibleDataError)1705 UBool IntlTest::assertEquals(const char* message,
1706 const UnicodeString& expected,
1707 const UnicodeString& actual,
1708 UBool possibleDataError) {
1709 if (expected != actual) {
1710 if (possibleDataError) {
1711 dataerrln((UnicodeString)"FAIL: " + message + "; got " +
1712 prettify(actual) +
1713 "; expected " + prettify(expected));
1714 } else {
1715 errln((UnicodeString)"FAIL: " + message + "; got " +
1716 prettify(actual) +
1717 "; expected " + prettify(expected));
1718 }
1719 return FALSE;
1720 }
1721 #ifdef VERBOSE_ASSERTIONS
1722 else {
1723 logln((UnicodeString)"Ok: " + message + "; got " + prettify(actual));
1724 }
1725 #endif
1726 return TRUE;
1727 }
1728
assertEquals(const char * message,const char * expected,const char * actual)1729 UBool IntlTest::assertEquals(const char* message,
1730 const char* expected,
1731 const char* actual) {
1732 if (uprv_strcmp(expected, actual) != 0) {
1733 errln((UnicodeString)"FAIL: " + message + "; got \"" +
1734 actual +
1735 "\"; expected \"" + expected + "\"");
1736 return FALSE;
1737 }
1738 #ifdef VERBOSE_ASSERTIONS
1739 else {
1740 logln((UnicodeString)"Ok: " + message + "; got \"" + actual + "\"");
1741 }
1742 #endif
1743 return TRUE;
1744 }
1745
assertEquals(const char * message,int32_t expected,int32_t actual)1746 UBool IntlTest::assertEquals(const char* message,
1747 int32_t expected,
1748 int32_t actual) {
1749 if (expected != actual) {
1750 errln((UnicodeString)"FAIL: " + message + "; got " +
1751 actual + "=0x" + toHex(actual) +
1752 "; expected " + expected + "=0x" + toHex(expected));
1753 return FALSE;
1754 }
1755 #ifdef VERBOSE_ASSERTIONS
1756 else {
1757 logln((UnicodeString)"Ok: " + message + "; got " + actual + "=0x" + toHex(actual));
1758 }
1759 #endif
1760 return TRUE;
1761 }
1762
1763 #if !UCONFIG_NO_FORMATTING
assertEquals(const char * message,const Formattable & expected,const Formattable & actual)1764 UBool IntlTest::assertEquals(const char* message,
1765 const Formattable& expected,
1766 const Formattable& actual) {
1767 if (expected != actual) {
1768 errln((UnicodeString)"FAIL: " + message + "; got " +
1769 toString(actual) +
1770 "; expected " + toString(expected));
1771 return FALSE;
1772 }
1773 #ifdef VERBOSE_ASSERTIONS
1774 else {
1775 logln((UnicodeString)"Ok: " + message + "; got " + toString(actual));
1776 }
1777 #endif
1778 return TRUE;
1779 }
1780 #endif
1781
1782 static char ASSERT_BUF[256];
1783
extractToAssertBuf(const UnicodeString & message)1784 static const char* extractToAssertBuf(const UnicodeString& message) {
1785 UnicodeString buf;
1786 escape(message, buf);
1787 buf.extract(0, 0x7FFFFFFF, ASSERT_BUF, sizeof(ASSERT_BUF)-1, 0);
1788 ASSERT_BUF[sizeof(ASSERT_BUF)-1] = 0;
1789 return ASSERT_BUF;
1790 }
1791
assertTrue(const UnicodeString & message,UBool condition,UBool quiet)1792 UBool IntlTest::assertTrue(const UnicodeString& message, UBool condition, UBool quiet) {
1793 return assertTrue(extractToAssertBuf(message), condition, quiet);
1794 }
1795
assertFalse(const UnicodeString & message,UBool condition,UBool quiet)1796 UBool IntlTest::assertFalse(const UnicodeString& message, UBool condition, UBool quiet) {
1797 return assertFalse(extractToAssertBuf(message), condition, quiet);
1798 }
1799
assertSuccess(const UnicodeString & message,UErrorCode ec)1800 UBool IntlTest::assertSuccess(const UnicodeString& message, UErrorCode ec) {
1801 return assertSuccess(extractToAssertBuf(message), ec);
1802 }
1803
assertEquals(const UnicodeString & message,const UnicodeString & expected,const UnicodeString & actual)1804 UBool IntlTest::assertEquals(const UnicodeString& message,
1805 const UnicodeString& expected,
1806 const UnicodeString& actual) {
1807 return assertEquals(extractToAssertBuf(message), expected, actual);
1808 }
1809
assertEquals(const UnicodeString & message,const char * expected,const char * actual)1810 UBool IntlTest::assertEquals(const UnicodeString& message,
1811 const char* expected,
1812 const char* actual) {
1813 return assertEquals(extractToAssertBuf(message), expected, actual);
1814 }
1815 //--------------------------------------------------------------------
1816 // Time bomb - allows temporary behavior that expires at a given
1817 // release
1818 //--------------------------------------------------------------------
1819
isICUVersionBefore(int major,int minor,int milli)1820 UBool IntlTest::isICUVersionBefore(int major, int minor, int milli) {
1821 UVersionInfo iv;
1822 UVersionInfo ov = { (uint8_t)major, (uint8_t)minor, (uint8_t)milli, 0 };
1823 u_getVersion(iv);
1824 return uprv_memcmp(iv, ov, U_MAX_VERSION_LENGTH) < 0;
1825 }
1826
1827 #if !UCONFIG_NO_FORMATTING
assertEquals(const UnicodeString & message,const Formattable & expected,const Formattable & actual)1828 UBool IntlTest::assertEquals(const UnicodeString& message,
1829 const Formattable& expected,
1830 const Formattable& actual) {
1831 return assertEquals(extractToAssertBuf(message), expected, actual);
1832 }
1833 #endif
1834
setProperty(const char * propline)1835 void IntlTest::setProperty(const char* propline) {
1836 if (numProps < kMaxProps) {
1837 proplines[numProps] = propline;
1838 }
1839 numProps++;
1840 }
1841
getProperty(const char * prop)1842 const char* IntlTest::getProperty(const char* prop) {
1843 const char* val = NULL;
1844 for (int32_t i = 0; i < numProps; i++) {
1845 int32_t plen = uprv_strlen(prop);
1846 if ((int32_t)uprv_strlen(proplines[i]) > plen + 1
1847 && proplines[i][plen] == '='
1848 && uprv_strncmp(proplines[i], prop, plen) == 0) {
1849 val = &(proplines[i][plen+1]);
1850 break;
1851 }
1852 }
1853 return val;
1854 }
1855
1856 /*
1857 * Hey, Emacs, please set the following:
1858 *
1859 * Local Variables:
1860 * indent-tabs-mode: nil
1861 * End:
1862 *
1863 */
1864