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