]> git.saurik.com Git - apple/icu.git/blame - icuSources/test/intltest/intltest.cpp
ICU-511.31.tar.gz
[apple/icu.git] / icuSources / test / intltest / intltest.cpp
CommitLineData
b75a7d8f
A
1/********************************************************************
2 * COPYRIGHT:
51004dcb 3 * Copyright (c) 1997-2013, International Business Machines Corporation and
b75a7d8f
A
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"
374ca955
A
25#include "unicode/timezone.h"
26#include "unicode/curramt.h"
27#include "unicode/putil.h"
b75a7d8f
A
28
29#include "intltest.h"
30#include "caltztst.h"
31#include "itmajor.h"
374ca955 32#include "cstring.h"
b75a7d8f 33#include "umutex.h"
374ca955
A
34#include "uassert.h"
35#include "cmemory.h"
73c04bcf
A
36#include "uoptions.h"
37
729e4ab9 38#include "putilimp.h" // for uprv_getRawUTCtime()
73c04bcf 39#include "unicode/locid.h"
729e4ab9 40#include "unicode/ctest.h" // for str_timeDelta
b75a7d8f
A
41
42#ifdef XP_MAC_CONSOLE
43#include <console.h>
44#include "Files.h"
45#endif
46
47
48static char* _testDataPath=NULL;
49
50// Static list of errors found
51static 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
58UnicodeString
59UCharToUnicodeString(UChar c)
60{ return UnicodeString(c); }
61
b75a7d8f
A
62// [rtg] Just to get things working
63UnicodeString
64operator+(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
76UnicodeString
77operator+(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
374ca955
A
89UnicodeString
90Int64ToUnicodeString(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
4388f060 95#if defined(_MSC_VER)
374ca955
A
96 sprintf(buffer, "%I64d", num);
97#else
73c04bcf 98 sprintf(buffer, "%lld", (long long)num);
374ca955
A
99#endif
100 assert(danger == 'p');
101
102 return buffer;
103}
104
b75a7d8f
A
105// [LIU] Just to get things working
106UnicodeString
107operator+(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
374ca955
A
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
46f4442e 117 sprintf(buffer, "%.17g", num);
b75a7d8f
A
118 assert(danger == 'p');
119
120 return left + buffer;
121}
122
123#if !UCONFIG_NO_FORMATTING
124
125/**
729e4ab9 126 * Return a string display for this, without surrounding braces.
b75a7d8f 127 */
374ca955 128UnicodeString _toString(const Formattable& f) {
b75a7d8f
A
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);
374ca955 138 s.insert(0, "Date:");
b75a7d8f 139 } else {
374ca955 140 s = UnicodeString("Error creating date format]");
b75a7d8f
A
141 }
142 }
143 break;
144 case Formattable::kDouble:
374ca955 145 s = UnicodeString("double:") + f.getDouble();
b75a7d8f
A
146 break;
147 case Formattable::kLong:
374ca955 148 s = UnicodeString("long:") + f.getLong();
b75a7d8f 149 break;
374ca955
A
150
151 case Formattable::kInt64:
152 s = UnicodeString("int64:") + Int64ToUnicodeString(f.getInt64());
153 break;
154
b75a7d8f
A
155 case Formattable::kString:
156 f.getString(s);
374ca955 157 s.insert(0, "String:");
b75a7d8f
A
158 break;
159 case Formattable::kArray:
160 {
161 int32_t i, n;
162 const Formattable* array = f.getArray(n);
374ca955 163 s.insert(0, UnicodeString("Array:"));
b75a7d8f
A
164 UnicodeString delim(", ");
165 for (i=0; i<n; ++i) {
166 if (i > 0) {
167 s.append(delim);
168 }
374ca955 169 s = s + _toString(array[i]);
b75a7d8f 170 }
b75a7d8f
A
171 }
172 break;
729e4ab9
A
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());
374ca955
A
177 } else {
178 s = UnicodeString("Unknown UObject");
179 }
180 break;
729e4ab9 181 }
374ca955
A
182 default:
183 s = UnicodeString("Unknown Formattable type=") + (int32_t)f.getType();
184 break;
b75a7d8f
A
185 }
186 return s;
187}
188
374ca955
A
189/**
190 * Originally coded this as operator+, but that makes the expression
191 * + char* ambiguous. - liu
192 */
193UnicodeString toString(const Formattable& f) {
194 UnicodeString s((UChar)91/*[*/);
195 s.append(_toString(f));
196 s.append((UChar)0x5d/*]*/);
197 return s;
198}
199
b75a7d8f
A
200#endif
201
374ca955
A
202// useful when operator+ won't cooperate
203UnicodeString toString(int32_t n) {
204 return UnicodeString() + (long)n;
205}
206
b75a7d8f
A
207// stephen - cleaned up 05/05/99
208UnicodeString operator+(const UnicodeString& left, char num)
209{ return left + (long)num; }
210UnicodeString operator+(const UnicodeString& left, short num)
211{ return left + (long)num; }
212UnicodeString operator+(const UnicodeString& left, int num)
213{ return left + (long)num; }
214UnicodeString operator+(const UnicodeString& left, unsigned char num)
215{ return left + (unsigned long)num; }
216UnicodeString operator+(const UnicodeString& left, unsigned short num)
217{ return left + (unsigned long)num; }
218UnicodeString operator+(const UnicodeString& left, unsigned int num)
219{ return left + (unsigned long)num; }
220UnicodeString operator+(const UnicodeString& left, float num)
221{ return left + (double)num; }
222
223//------------------
224
225// Append a hex string to the target
226UnicodeString&
227IntlTest::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
51004dcb
A
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 }
b75a7d8f
A
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
51004dcb
A
269UnicodeString
270IntlTest::toHex(uint32_t number, int32_t digits) {
271 UnicodeString result;
272 appendHex(number, digits, result);
273 return result;
274}
275
729e4ab9
A
276static inline UBool isPrintable(UChar32 c) {
277 return c <= 0x7E && (c >= 0x20 || c == 9 || c == 0xA || c == 0xD);
278}
279
b75a7d8f
A
280// Replace nonprintable characters with unicode escapes
281UnicodeString&
282IntlTest::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);
729e4ab9 293 i += U16_LENGTH(ch);
b75a7d8f 294
729e4ab9 295 if (!isPrintable(ch))
b75a7d8f
A
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
317UnicodeString
318IntlTest::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);
729e4ab9 328 i += U16_LENGTH(ch);
b75a7d8f 329
729e4ab9 330 if (!isPrintable(ch))
b75a7d8f
A
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
b75a7d8f
A
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 */
376void 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.
374ca955 389 // The value is complete with quotes, so it can be used
b75a7d8f
A
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
445static const int32_t indentLevel_offset = 3;
446static const char delim = '/';
447
448IntlTest* IntlTest::gTest = NULL;
449
450static int32_t execCount = 0;
451
452void it_log( UnicodeString message )
453{
454 if (IntlTest::gTest)
455 IntlTest::gTest->log( message );
456}
457
458void it_logln( UnicodeString message )
459{
460 if (IntlTest::gTest)
461 IntlTest::gTest->logln( message );
462}
463
464void it_logln( void )
465{
466 if (IntlTest::gTest)
467 IntlTest::gTest->logln();
468}
469
470void it_info( UnicodeString message )
471{
472 if (IntlTest::gTest)
473 IntlTest::gTest->info( message );
474}
475
476void it_infoln( UnicodeString message )
477{
478 if (IntlTest::gTest)
479 IntlTest::gTest->infoln( message );
480}
481
482void it_infoln( void )
483{
484 if (IntlTest::gTest)
485 IntlTest::gTest->infoln();
486}
487
488void it_err()
489{
490 if (IntlTest::gTest)
491 IntlTest::gTest->err();
492}
493
494void it_err( UnicodeString message )
495{
496 if (IntlTest::gTest)
497 IntlTest::gTest->err( message );
498}
499
500void it_errln( UnicodeString message )
501{
502 if (IntlTest::gTest)
503 IntlTest::gTest->errln( message );
504}
505
73c04bcf
A
506void it_dataerr( UnicodeString message )
507{
508 if (IntlTest::gTest)
509 IntlTest::gTest->dataerr( message );
510}
511
512void it_dataerrln( UnicodeString message )
513{
514 if (IntlTest::gTest)
515 IntlTest::gTest->dataerrln( message );
516}
b75a7d8f
A
517
518IntlTest::IntlTest()
519{
520 caller = NULL;
73c04bcf 521 testPath = NULL;
b75a7d8f
A
522 LL_linestart = TRUE;
523 errorCount = 0;
73c04bcf 524 dataErrorCount = 0;
b75a7d8f 525 verbose = FALSE;
51004dcb 526 no_time = FALSE;
b75a7d8f 527 no_err_msg = FALSE;
73c04bcf 528 warn_on_missing_data = FALSE;
b75a7d8f
A
529 quick = FALSE;
530 leaks = FALSE;
729e4ab9 531 threadCount = 1;
b75a7d8f
A
532 testoutfp = stdout;
533 LL_indentlevel = indentLevel_offset;
729e4ab9
A
534 numProps = 0;
535 strcpy(basePath, "/");
b75a7d8f
A
536}
537
538void IntlTest::setCaller( IntlTest* callingTest )
539{
540 caller = callingTest;
541 if (caller) {
46f4442e 542 warn_on_missing_data = caller->warn_on_missing_data;
b75a7d8f
A
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;
729e4ab9
A
548 numProps = caller->numProps;
549 for (int32_t i = 0; i < numProps; i++) {
550 proplines[i] = caller->proplines[i];
551 }
b75a7d8f
A
552 }
553}
554
555UBool 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 );
729e4ab9
A
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;
b75a7d8f
A
563}
564
565void IntlTest::setPath( char* pathVal )
566{
73c04bcf 567 this->testPath = pathVal;
b75a7d8f
A
568}
569
570UBool IntlTest::setVerbose( UBool verboseVal )
571{
572 UBool rval = this->verbose;
573 this->verbose = verboseVal;
574 return rval;
575}
576
51004dcb
A
577UBool IntlTest::setNotime( UBool no_time )
578{
579 UBool rval = this->no_time;
580 this->no_time = no_time;
581 return rval;
582}
583
73c04bcf
A
584UBool 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
b75a7d8f
A
591UBool 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
598UBool IntlTest::setQuick( UBool quickVal )
599{
600 UBool rval = this->quick;
601 this->quick = quickVal;
602 return rval;
603}
604
605UBool IntlTest::setLeaks( UBool leaksVal )
606{
607 UBool rval = this->leaks;
608 this->leaks = leaksVal;
609 return rval;
610}
611
729e4ab9
A
612int32_t IntlTest::setThreadCount( int32_t count )
613{
614 int32_t rval = this->threadCount;
615 this->threadCount = count;
616 return rval;
617}
618
b75a7d8f
A
619int32_t IntlTest::getErrors( void )
620{
621 return errorCount;
622}
623
73c04bcf
A
624int32_t IntlTest::getDataErrors( void )
625{
626 return dataErrorCount;
627}
628
729e4ab9 629UBool IntlTest::runTest( char* name, char* par, char *baseName )
b75a7d8f
A
630{
631 UBool rval;
632 char* pos = NULL;
633
729e4ab9
A
634 char* baseNameBuffer = NULL;
635
636 if(baseName == NULL) {
637 baseNameBuffer = (char*)malloc(1024);
638 baseName=baseNameBuffer;
639 strcpy(baseName, "/");
640 }
641
b75a7d8f
A
642 if (name)
643 pos = strchr( name, delim ); // check if name contains path (by looking for '/')
644 if (pos) {
73c04bcf 645 testPath = pos+1; // store subpath for calling subtest
b75a7d8f
A
646 *pos = 0; // split into two strings
647 }else{
73c04bcf 648 testPath = NULL;
b75a7d8f
A
649 }
650
651 if (!name || (name[0] == 0) || (strcmp(name, "*") == 0)) {
729e4ab9 652 rval = runTestLoop( NULL, par, baseName );
b75a7d8f
A
653
654 }else if (strcmp( name, "LIST" ) == 0) {
655 this->usage();
656 rval = TRUE;
657
658 }else{
729e4ab9 659 rval = runTestLoop( name, par, baseName );
b75a7d8f
A
660 }
661
662 if (pos)
663 *pos = delim; // restore original value at pos
729e4ab9
A
664 if(baseNameBuffer!=NULL) {
665 free(baseNameBuffer);
666 }
b75a7d8f
A
667 return rval;
668}
669
670// call individual tests, to be overriden to call implementations
51004dcb 671void IntlTest::runIndexedTest( int32_t /*index*/, UBool /*exec*/, const char* & /*name*/, char* /*par*/ )
b75a7d8f
A
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! ***");
b75a7d8f
A
682}
683
684
729e4ab9 685UBool IntlTest::runTestLoop( char* testname, char* par, char *baseName )
b75a7d8f
A
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
729e4ab9
A
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
b75a7d8f
A
705 IntlTest* saveTest = gTest;
706 gTest = this;
707 do {
374ca955 708 this->runIndexedTest( index, FALSE, name, par );
729e4ab9
A
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 }
b75a7d8f
A
719 }
720 if (run_this_test) {
721 lastErrorCount = errorCount;
722 execCount++;
729e4ab9
A
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
b75a7d8f 730 this->runIndexedTest( index, TRUE, name, par );
729e4ab9
A
731
732 UDate timeStop = uprv_getRawUTCtime();
b75a7d8f 733 rval = TRUE; // at least one test has been called
729e4ab9 734 char secs[256];
51004dcb
A
735 if(!no_time) {
736 sprintf(secs, "%f", (timeStop-timeStart)/1000.0);
737 } else {
738 secs[0]=0;
739 }
729e4ab9
A
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
b75a7d8f 750 if (lastErrorCount == errorCount) {
729e4ab9 751 sprintf( msg, " } OK: %s ", name );
51004dcb 752 if(!no_time) str_timeDelta(msg+strlen(msg),timeStop-timeStart);
b75a7d8f
A
753 lastTestFailed = FALSE;
754 }else{
729e4ab9 755 sprintf(msg, " } ERRORS (%li) in %s", (long)(errorCount-lastErrorCount), name);
51004dcb 756 if(!no_time) str_timeDelta(msg+strlen(msg),timeStop-timeStart);
b75a7d8f
A
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
729e4ab9
A
778 *saveBaseLoc = 0;
779
b75a7d8f
A
780 gTest = saveTest;
781 return rval;
782}
783
784
785/**
786* Adds given string to the log if we are in verbose mode.
787*/
788void 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*/
799void IntlTest::logln( const UnicodeString &message )
800{
801 if( verbose ) {
802 LL_message( message, TRUE );
803 }
804}
805
806void IntlTest::logln( void )
807{
808 if( verbose ) {
809 LL_message( "", TRUE );
810 }
811}
812
813/**
814* Unconditionally adds given string to the log.
815*/
816void 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*/
825void IntlTest::infoln( const UnicodeString &message )
826{
827 LL_message( message, TRUE );
828}
829
830void IntlTest::infoln( void )
831{
832 LL_message( "", TRUE );
833}
834
835int32_t IntlTest::IncErrorCount( void )
836{
837 errorCount++;
838 if (caller) caller->IncErrorCount();
839 return errorCount;
840}
841
73c04bcf
A
842int32_t IntlTest::IncDataErrorCount( void )
843{
844 dataErrorCount++;
845 if (caller) caller->IncDataErrorCount();
846 return dataErrorCount;
847}
848
849void IntlTest::err()
850{
b75a7d8f
A
851 IncErrorCount();
852}
853
854void IntlTest::err( const UnicodeString &message )
855{
856 IncErrorCount();
857 if (!no_err_msg) LL_message( message, FALSE );
858}
859
860void IntlTest::errln( const UnicodeString &message )
861{
862 IncErrorCount();
863 if (!no_err_msg) LL_message( message, TRUE );
864}
865
73c04bcf
A
866void 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
877void IntlTest::dataerrln( const UnicodeString &message )
878{
879 IncDataErrorCount();
729e4ab9 880 UnicodeString msg;
73c04bcf
A
881 if (!warn_on_missing_data) {
882 IncErrorCount();
729e4ab9
A
883 msg = message;
884 } else {
885 msg = UnicodeString("[DATA] " + message);
73c04bcf
A
886 }
887
729e4ab9
A
888 if (!no_err_msg) LL_message( msg + " - (Are you missing data?)", TRUE );
889}
890
891void 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 }
73c04bcf
A
897}
898
b75a7d8f
A
899/* convenience functions that include sprintf formatting */
900void IntlTest::log(const char *fmt, ...)
901{
374ca955 902 char buffer[4000];
b75a7d8f
A
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
914void IntlTest::logln(const char *fmt, ...)
915{
374ca955 916 char buffer[4000];
b75a7d8f
A
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 */
929void IntlTest::info(const char *fmt, ...)
930{
374ca955 931 char buffer[4000];
b75a7d8f
A
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
941void IntlTest::infoln(const char *fmt, ...)
942{
374ca955 943 char buffer[4000];
b75a7d8f
A
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
953void IntlTest::err(const char *fmt, ...)
954{
374ca955 955 char buffer[4000];
b75a7d8f
A
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
964void IntlTest::errln(const char *fmt, ...)
965{
374ca955 966 char buffer[4000];
b75a7d8f
A
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
73c04bcf
A
975void 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
729e4ab9
A
986void 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
b75a7d8f
A
1002void IntlTest::printErrors()
1003{
1004 IntlTest::LL_message(errorList, TRUE);
1005}
1006
1007void 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) {
374ca955 1032 fwrite(buffer, sizeof(*buffer), length, (FILE *)testoutfp);
b75a7d8f
A
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) {
73c04bcf 1041 length = length > 10000 ? 10000 : length;
374ca955 1042 fwrite(buffer, sizeof(*buffer), length, (FILE *)testoutfp);
b75a7d8f
A
1043 }
1044
1045 if (newline) {
1046 char newLine = '\n';
374ca955 1047 fwrite(&newLine, sizeof(newLine), 1, (FILE *)testoutfp);
b75a7d8f
A
1048 }
1049
1050 // A newline usually flushes the buffer, but
1051 // flush the message just in case of a core dump.
374ca955 1052 fflush((FILE *)testoutfp);
b75a7d8f
A
1053}
1054
1055/**
1056* Print a usage message for this test class.
1057*/
1058void 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
1078UBool
1079IntlTest::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
1095int
1096main(int argc, char* argv[])
1097{
1098 UBool syntax = FALSE;
374ca955 1099 UBool all = FALSE;
b75a7d8f
A
1100 UBool verbose = FALSE;
1101 UBool no_err_msg = FALSE;
51004dcb 1102 UBool no_time = FALSE;
b75a7d8f
A
1103 UBool quick = TRUE;
1104 UBool name = FALSE;
1105 UBool leaks = FALSE;
1106 UBool warnOnMissingData = FALSE;
73c04bcf 1107 UBool defaultDataFound = FALSE;
729e4ab9 1108 int32_t threadCount = 1;
b75a7d8f
A
1109 UErrorCode errorCode = U_ZERO_ERROR;
1110 UConverter *cnv = NULL;
374ca955 1111 const char *warnOrErr = "Failure";
73c04bcf
A
1112 UDate startTime, endTime;
1113 int32_t diffTime;
729e4ab9
A
1114 const char *props[IntlTest::kMaxProps];
1115 int32_t nProps = 0;
b75a7d8f 1116
73c04bcf 1117 U_MAIN_INIT_ARGS(argc, argv);
374ca955 1118
729e4ab9 1119 startTime = uprv_getRawUTCtime();
b75a7d8f
A
1120
1121 for (int i = 1; i < argc; ++i) {
1122 if (argv[i][0] == '-') {
1123 const char* str = argv[i] + 1;
374ca955
A
1124 if (strcmp("verbose", str) == 0 ||
1125 strcmp("v", str) == 0)
b75a7d8f 1126 verbose = TRUE;
374ca955
A
1127 else if (strcmp("noerrormsg", str) == 0 ||
1128 strcmp("n", str) == 0)
b75a7d8f 1129 no_err_msg = TRUE;
374ca955
A
1130 else if (strcmp("exhaustive", str) == 0 ||
1131 strcmp("e", str) == 0)
b75a7d8f 1132 quick = FALSE;
374ca955
A
1133 else if (strcmp("all", str) == 0 ||
1134 strcmp("a", str) == 0)
b75a7d8f 1135 all = TRUE;
374ca955
A
1136 else if (strcmp("leaks", str) == 0 ||
1137 strcmp("l", str) == 0)
b75a7d8f 1138 leaks = TRUE;
51004dcb
A
1139 else if (strcmp("notime", str) == 0 ||
1140 strcmp("T", str) == 0)
1141 no_time = TRUE;
729e4ab9
A
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) {
b75a7d8f
A
1151 warnOnMissingData = TRUE;
1152 warnOrErr = "WARNING";
374ca955 1153 }
729e4ab9
A
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 }
374ca955 1163 else {
b75a7d8f
A
1164 syntax = TRUE;
1165 }
1166 }else{
1167 name = TRUE;
b75a7d8f
A
1168 }
1169 }
1170
374ca955
A
1171 if (!all && !name) {
1172 all = TRUE;
1173 } else if (all && name) {
1174 syntax = TRUE;
1175 }
b75a7d8f
A
1176
1177 if (syntax) {
1178 fprintf(stdout,
1179 "### Syntax:\n"
1180 "### IntlTest [-option1 -option2 ...] [testname1 testname2 ...] \n"
729e4ab9
A
1181 "### \n"
1182 "### Options are: verbose (v), all (a), noerrormsg (n), \n"
1183 "### exhaustive (e), leaks (l), -x xmlfile.xml, prop:<propery>=<value>, \n"
51004dcb 1184 "### notime (T), \n"
729e4ab9
A
1185 "### threads:<threadCount> (Mulithreading must first be \n"
1186 "### enabled otherwise this will be ignored. \n"
1187 "### The default thread count is 1.),\n"
b75a7d8f
A
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
729e4ab9
A
1203 if (nProps > IntlTest::kMaxProps) {
1204 fprintf(stdout, "### Too many properties. Exiting.\n");
1205 }
1206
b75a7d8f
A
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 );
729e4ab9 1213 major.setThreadCount( threadCount );
73c04bcf 1214 major.setWarnOnMissingData( warnOnMissingData );
51004dcb 1215 major.setNotime (no_time);
729e4ab9
A
1216 for (int32_t i = 0; i < nProps; i++) {
1217 major.setProperty(props[i]);
1218 }
1219
1220
b75a7d8f
A
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);
729e4ab9
A
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 }
b75a7d8f
A
1240 fprintf(stdout, "-----------------------------------------------\n");
1241 fprintf(stdout, " Options: \n");
73c04bcf
A
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"));
51004dcb 1247 fprintf(stdout, " notime (T) : %s\n", (no_time? "On" : "Off"));
73c04bcf 1248 fprintf(stdout, " Warn on missing data (w) : %s\n", (warnOnMissingData? "On" : "Off"));
729e4ab9
A
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 }
b75a7d8f
A
1257 fprintf(stdout, "-----------------------------------------------\n");
1258
73c04bcf
A
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();
b75a7d8f 1277 errorCode = U_ZERO_ERROR;
73c04bcf
A
1278
1279 /* Initialize ICU */
1280 if (!defaultDataFound) {
1281 IntlTest::setICU_DATA(); // Must set data directory before u_init() is called.
1282 }
b75a7d8f
A
1283 u_init(&errorCode);
1284 if (U_FAILURE(errorCode)) {
73c04bcf
A
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 }
b75a7d8f
A
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) {
374ca955 1310 fprintf(stdout, "*** Exiting. Use the '-w' option if data files were\n*** purposely removed, to continue test anyway.\n");
b75a7d8f
A
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) {
374ca955 1326 fprintf(stdout, "*** Exiting. Use the '-w' option if data files were\n*** purposely removed, to continue test anyway.\n");
b75a7d8f
A
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) {
374ca955 1339 fprintf(stdout, "*** Exiting. Use the '-w' option if data files were\n*** purposely removed, to continue test anyway.\n");
b75a7d8f
A
1340 return 1;
1341 }
1342 }
1343
73c04bcf
A
1344 Locale originalLocale; // Save the default locale for comparison later on.
1345
729e4ab9
A
1346 if(ctest_xml_init("intltest"))
1347 return 1;
1348
1349
b75a7d8f
A
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);
729e4ab9
A
1361
1362 char baseName[1024];
1363 sprintf(baseName, "/%s/", name);
1364
b75a7d8f
A
1365 char* parameter = strchr( name, '@' );
1366 if (parameter) {
1367 *parameter = 0;
1368 parameter += 1;
1369 }
1370 execCount = 0;
729e4ab9 1371 UBool res = major.runTest( name, parameter, baseName );
b75a7d8f
A
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 }
729e4ab9
A
1379 } else if(!strcmp(argv[i],"-x")) {
1380 i++;
b75a7d8f
A
1381 }
1382 }
1383 }
1384
729e4ab9 1385
b75a7d8f
A
1386#if !UCONFIG_NO_FORMATTING
1387 CalendarTimeZoneTest::cleanup();
1388#endif
1389
1390 free(_testDataPath);
1391 _testDataPath = 0;
1392
73c04bcf
A
1393 Locale lastDefaultLocale;
1394 if (originalLocale != lastDefaultLocale) {
1395 major.errln("FAILURE: A test changed the default locale without resetting it.");
1396 }
1397
b75a7d8f
A
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();
73c04bcf 1403 u_cleanup();
b75a7d8f
A
1404
1405 fprintf(stdout, "OK: All tests passed without error.\n");
73c04bcf
A
1406
1407 if (major.getDataErrors() != 0) {
1408 fprintf(stdout, "\t*WARNING* some data-loading errors were ignored by the -w option.\n");
1409 }
b75a7d8f
A
1410 }else{
1411 fprintf(stdout, "Errors in total: %ld.\n", (long)major.getErrors());
1412 major.printErrors();
1413
73c04bcf
A
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
b75a7d8f
A
1421 /* Call afterwards to display errors. */
1422 u_cleanup();
1423 }
1424
1425 fprintf(stdout, "--------------------------------------\n");
1426
b75a7d8f
A
1427 if (execCount <= 0) {
1428 fprintf(stdout, "***** Not all called tests actually exist! *****\n");
1429 }
51004dcb
A
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 }
729e4ab9
A
1439
1440 if(ctest_xml_fini())
1441 return 1;
1442
b75a7d8f
A
1443 return major.getErrors();
1444}
1445
1446const 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)
51004dcb 1454 tdrelativepath = "test" U_FILE_SEP_STRING "testdata" U_FILE_SEP_STRING "out" U_FILE_SEP_STRING;
b75a7d8f
A
1455 directory = U_TOPBUILDDIR;
1456#else
51004dcb 1457 tdrelativepath = ".." U_FILE_SEP_STRING "test" U_FILE_SEP_STRING "testdata" U_FILE_SEP_STRING "out" U_FILE_SEP_STRING;
b75a7d8f
A
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 */
374ca955 1467 strcpy(tdpath, directory);
b75a7d8f
A
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;
729e4ab9 1475 it_dataerrln((UnicodeString)"Could not load testtypes.res in testdata bundle with path " + tdpath + (UnicodeString)" - " + u_errorName(err));
b75a7d8f
A
1476 return "";
1477 }
1478 ures_close(test);
1479 _testDataPath = tdpath;
1480 return _testDataPath;
1481 }
1482 return _testDataPath;
1483}
1484
374ca955
A
1485const char* IntlTest::getTestDataPath(UErrorCode& err) {
1486 return loadTestData(err);
1487}
1488
1489/* Returns the path to icu/source/test/testdata/ */
1490const char *IntlTest::getSourceTestData(UErrorCode& /*err*/) {
1491 const char *srcDataDir = NULL;
1492#ifdef U_TOPSRCDIR
51004dcb 1493 srcDataDir = U_TOPSRCDIR U_FILE_SEP_STRING"test" U_FILE_SEP_STRING "testdata" U_FILE_SEP_STRING;
374ca955 1494#else
51004dcb
A
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");
374ca955
A
1497 if (f) {
1498 /* We're in icu/source/test/intltest/ */
1499 fclose(f);
1500 }
1501 else {
729e4ab9 1502 /* We're in icu/source/test/intltest/Platform/(Debug|Release) */
51004dcb 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;
374ca955
A
1504 }
1505#endif
1506 return srcDataDir;
1507}
1508
b75a7d8f
A
1509const char* IntlTest::fgDataDir = NULL;
1510
1511/* returns the path to icu/source/data */
1512const 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 */
51004dcb 1561 FILE *file = fopen(".." U_FILE_SEP_STRING ".."U_FILE_SEP_STRING "data" U_FILE_SEP_STRING "Makefile.in", "r");
374ca955
A
1562 if (file) {
1563 fclose(file);
51004dcb 1564 fgDataDir = ".." U_FILE_SEP_STRING ".."U_FILE_SEP_STRING "data" U_FILE_SEP_STRING;
374ca955
A
1565 }
1566 else {
51004dcb 1567 fgDataDir = ".." U_FILE_SEP_STRING ".." U_FILE_SEP_STRING ".." U_FILE_SEP_STRING ".."U_FILE_SEP_STRING "data" U_FILE_SEP_STRING;
374ca955 1568 }
b75a7d8f
A
1569 }
1570 }
1571#endif
1572
1573 return fgDataDir;
1574
1575}
1576
1577/*
1578 * This is a variant of cintltst/ccolltst.c:CharsToUChars().
729e4ab9 1579 * It converts an invariant-character string into a UnicodeString, with
b75a7d8f
A
1580 * unescaping \u sequences.
1581 */
729e4ab9
A
1582UnicodeString CharsToUnicodeString(const char* chars){
1583 return UnicodeString(chars, -1, US_INV).unescape();
b75a7d8f
A
1584}
1585
374ca955
A
1586UnicodeString 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
1594static 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 */
1605float 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 */
1630float IntlTest::random() {
1631 return random(&RAND_SEED);
1632}
1633
1634static inline UChar toHex(int32_t i) {
1635 return (UChar)(i + (i < 10 ? 0x30 : (0x41 - 10)));
1636}
1637
1638static 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
51004dcb
A
1657UBool 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);
729e4ab9 1667 }
51004dcb
A
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
374ca955
A
1679 }
1680 return condition;
1681}
1682
1683UBool 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
729e4ab9 1692UBool IntlTest::assertSuccess(const char* message, UErrorCode ec, UBool possibleDataError) {
374ca955 1693 if (U_FAILURE(ec)) {
729e4ab9
A
1694 if (possibleDataError) {
1695 dataerrln("FAIL: %s (%s)", message, u_errorName(ec));
46f4442e 1696 } else {
729e4ab9 1697 errcheckln(ec, "FAIL: %s (%s)", message, u_errorName(ec));
46f4442e 1698 }
729e4ab9 1699
374ca955
A
1700 return FALSE;
1701 }
1702 return TRUE;
1703}
1704
1705UBool IntlTest::assertEquals(const char* message,
1706 const UnicodeString& expected,
729e4ab9
A
1707 const UnicodeString& actual,
1708 UBool possibleDataError) {
374ca955 1709 if (expected != actual) {
729e4ab9
A
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 }
374ca955
A
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
1729UBool 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
51004dcb
A
1746UBool 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
374ca955
A
1763#if !UCONFIG_NO_FORMATTING
1764UBool 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
1782static char ASSERT_BUF[256];
1783
1784static 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
1792UBool IntlTest::assertTrue(const UnicodeString& message, UBool condition, UBool quiet) {
1793 return assertTrue(extractToAssertBuf(message), condition, quiet);
1794}
1795
1796UBool IntlTest::assertFalse(const UnicodeString& message, UBool condition, UBool quiet) {
1797 return assertFalse(extractToAssertBuf(message), condition, quiet);
1798}
1799
1800UBool IntlTest::assertSuccess(const UnicodeString& message, UErrorCode ec) {
1801 return assertSuccess(extractToAssertBuf(message), ec);
1802}
1803
1804UBool IntlTest::assertEquals(const UnicodeString& message,
1805 const UnicodeString& expected,
1806 const UnicodeString& actual) {
1807 return assertEquals(extractToAssertBuf(message), expected, actual);
1808}
1809
1810UBool 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
4388f060
A
1820UBool 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;
374ca955
A
1825}
1826
1827#if !UCONFIG_NO_FORMATTING
1828UBool IntlTest::assertEquals(const UnicodeString& message,
1829 const Formattable& expected,
1830 const Formattable& actual) {
1831 return assertEquals(extractToAssertBuf(message), expected, actual);
1832}
1833#endif
1834
729e4ab9
A
1835void IntlTest::setProperty(const char* propline) {
1836 if (numProps < kMaxProps) {
1837 proplines[numProps] = propline;
1838 }
1839 numProps++;
1840}
1841
1842const 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
b75a7d8f
A
1856/*
1857 * Hey, Emacs, please set the following:
1858 *
1859 * Local Variables:
1860 * indent-tabs-mode: nil
1861 * End:
1862 *
1863 */