blob: 3686e7fd54710c8a6d69e73e2ae27cb948184798 [file] [log] [blame]
Frank Tang3e05d9d2021-11-08 14:04:04 -08001// © 2016 and later: Unicode, Inc. and others.
2// License & terms of use: http://www.unicode.org/copyright.html
3/********************************************************************
4 * COPYRIGHT:
5 * Copyright (c) 1997-2016, International Business Machines Corporation and
6 * others. All Rights Reserved.
7 ********************************************************************/
8
9
10#include "unicode/utypes.h"
11
12/**
13 * IntlTest is a base class for tests.
14 */
15
16#include <assert.h>
17#include <stdarg.h>
18#include <stdio.h>
19#include <stdlib.h>
20#include <string.h>
21#include <cmath>
22#include <math.h>
23
24#include "unicode/ctest.h" // for str_timeDelta
25#include "unicode/curramt.h"
26#include "unicode/locid.h"
27#include "unicode/putil.h"
28#include "unicode/smpdtfmt.h"
29#include "unicode/timezone.h"
30#include "unicode/uclean.h"
31#include "unicode/ucnv.h"
32#include "unicode/unistr.h"
33#include "unicode/ures.h"
34#include "unicode/utf16.h"
35
36#include "intltest.h"
37
38#include "caltztst.h"
39#include "cmemory.h"
40#include "cstring.h"
41#include "itmajor.h"
42#include "lstmbe.h"
43#include "mutex.h"
44#include "putilimp.h" // for uprv_getRawUTCtime()
45#include "uassert.h"
46#include "udbgutil.h"
47#include "umutex.h"
48#include "uoptions.h"
49#include "number_decnum.h"
50
51#ifdef XP_MAC_CONSOLE
52#include <console.h>
53#include "Files.h"
54#endif
55
56
57static char* _testDataPath=NULL;
58
59// Static list of errors found
60static UnicodeString errorList;
61static void *knownList = NULL; // known issues
Frank Tang1f164ee2022-11-08 12:31:27 -080062static UBool noKnownIssues = false; // if true, don't emit known issues
Frank Tang3e05d9d2021-11-08 14:04:04 -080063
64//-----------------------------------------------------------------------------
65//convenience classes to ease porting code that uses the Java
66//string-concatenation operator (moved from findword test by rtg)
67
68// [LIU] Just to get things working
69UnicodeString
70UCharToUnicodeString(UChar c)
71{ return UnicodeString(c); }
72
73// [rtg] Just to get things working
74UnicodeString
75operator+(const UnicodeString& left,
76 long num)
77{
78 char buffer[64]; // nos changed from 10 to 64
79 char danger = 'p'; // guard against overrunning the buffer (rtg)
80
81 sprintf(buffer, "%ld", num);
82 assert(danger == 'p');
83
84 return left + buffer;
85}
86
87UnicodeString
88operator+(const UnicodeString& left,
89 unsigned long num)
90{
91 char buffer[64]; // nos changed from 10 to 64
92 char danger = 'p'; // guard against overrunning the buffer (rtg)
93
94 sprintf(buffer, "%lu", num);
95 assert(danger == 'p');
96
97 return left + buffer;
98}
99
100UnicodeString
101Int64ToUnicodeString(int64_t num)
102{
103 char buffer[64]; // nos changed from 10 to 64
104 char danger = 'p'; // guard against overrunning the buffer (rtg)
105
106#if defined(_MSC_VER)
107 sprintf(buffer, "%I64d", num);
108#else
109 sprintf(buffer, "%lld", (long long)num);
110#endif
111 assert(danger == 'p');
112
113 return buffer;
114}
115
116UnicodeString
117DoubleToUnicodeString(double num)
118{
119 char buffer[64]; // nos changed from 10 to 64
120 char danger = 'p'; // guard against overrunning the buffer (rtg)
121
122 sprintf(buffer, "%1.14e", num);
123 assert(danger == 'p');
124
125 return buffer;
126}
127
128// [LIU] Just to get things working
129UnicodeString
130operator+(const UnicodeString& left,
131 double num)
132{
133 char buffer[64]; // was 32, made it arbitrarily bigger (rtg)
134 char danger = 'p'; // guard against overrunning the buffer (rtg)
135
136 // IEEE floating point has 52 bits of mantissa, plus one assumed bit
137 // 53*log(2)/log(10) = 15.95
138 // so there is no need to show more than 16 digits. [alan]
139
140 sprintf(buffer, "%.17g", num);
141 assert(danger == 'p');
142
143 return left + buffer;
144}
145
146#if 0
147UnicodeString
148operator+(const UnicodeString& left,
149 int64_t num) {
150 return left + Int64ToUnicodeString(num);
151}
152#endif
153
154#if !UCONFIG_NO_FORMATTING
155
156/**
157 * Return a string display for this, without surrounding braces.
158 */
159UnicodeString _toString(const Formattable& f) {
160 UnicodeString s;
161 switch (f.getType()) {
162 case Formattable::kDate:
163 {
164 UErrorCode status = U_ZERO_ERROR;
165 SimpleDateFormat fmt(status);
166 if (U_SUCCESS(status)) {
167 FieldPosition pos;
168 fmt.format(f.getDate(), s, pos);
169 s.insert(0, "Date:");
170 } else {
171 s = UnicodeString("Error creating date format]");
172 }
173 }
174 break;
175 case Formattable::kDouble:
176 s = UnicodeString("double:") + f.getDouble();
177 break;
178 case Formattable::kLong:
179 s = UnicodeString("long:") + f.getLong();
180 break;
181
182 case Formattable::kInt64:
183 s = UnicodeString("int64:") + Int64ToUnicodeString(f.getInt64());
184 break;
185
186 case Formattable::kString:
187 f.getString(s);
188 s.insert(0, "String:");
189 break;
190 case Formattable::kArray:
191 {
192 int32_t i, n;
193 const Formattable* array = f.getArray(n);
194 s.insert(0, UnicodeString("Array:"));
195 UnicodeString delim(", ");
196 for (i=0; i<n; ++i) {
197 if (i > 0) {
198 s.append(delim);
199 }
200 s = s + _toString(array[i]);
201 }
202 }
203 break;
204 case Formattable::kObject: {
205 const CurrencyAmount* c = dynamic_cast<const CurrencyAmount*>(f.getObject());
206 if (c != NULL) {
207 s = _toString(c->getNumber()) + " " + UnicodeString(c->getISOCurrency());
208 } else {
209 s = UnicodeString("Unknown UObject");
210 }
211 break;
212 }
213 default:
214 s = UnicodeString("Unknown Formattable type=") + (int32_t)f.getType();
215 break;
216 }
217 return s;
218}
219
220/**
221 * Originally coded this as operator+, but that makes the expression
222 * + char* ambiguous. - liu
223 */
224UnicodeString toString(const Formattable& f) {
225 UnicodeString s((UChar)91/*[*/);
226 s.append(_toString(f));
227 s.append((UChar)0x5d/*]*/);
228 return s;
229}
230
231#endif
232
233// useful when operator+ won't cooperate
234UnicodeString toString(int32_t n) {
235 return UnicodeString() + (long)n;
236}
237
238
239
240UnicodeString toString(UBool b) {
Frank Tang1f164ee2022-11-08 12:31:27 -0800241 return b ? UnicodeString("true"):UnicodeString("false");
Frank Tang3e05d9d2021-11-08 14:04:04 -0800242}
243
244UnicodeString toString(const UnicodeSet& uniset, UErrorCode& status) {
245 UnicodeString result;
246 uniset.toPattern(result, status);
247 return result;
248}
249
250// stephen - cleaned up 05/05/99
251UnicodeString operator+(const UnicodeString& left, char num)
252{ return left + (long)num; }
253UnicodeString operator+(const UnicodeString& left, short num)
254{ return left + (long)num; }
255UnicodeString operator+(const UnicodeString& left, int num)
256{ return left + (long)num; }
257UnicodeString operator+(const UnicodeString& left, unsigned char num)
258{ return left + (unsigned long)num; }
259UnicodeString operator+(const UnicodeString& left, unsigned short num)
260{ return left + (unsigned long)num; }
261UnicodeString operator+(const UnicodeString& left, unsigned int num)
262{ return left + (unsigned long)num; }
263UnicodeString operator+(const UnicodeString& left, float num)
264{ return left + (double)num; }
265
266//------------------
267
268// Append a hex string to the target
269UnicodeString&
270IntlTest::appendHex(uint32_t number,
271 int32_t digits,
272 UnicodeString& target)
273{
274 static const UChar digitString[] = {
275 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
276 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0
277 }; /* "0123456789ABCDEF" */
278
279 if (digits < 0) { // auto-digits
280 digits = 2;
281 uint32_t max = 0xff;
282 while (number > max) {
283 digits += 2;
284 max = (max << 8) | 0xff;
285 }
286 }
287 switch (digits)
288 {
289 case 8:
290 target += digitString[(number >> 28) & 0xF];
291 U_FALLTHROUGH;
292 case 7:
293 target += digitString[(number >> 24) & 0xF];
294 U_FALLTHROUGH;
295 case 6:
296 target += digitString[(number >> 20) & 0xF];
297 U_FALLTHROUGH;
298 case 5:
299 target += digitString[(number >> 16) & 0xF];
300 U_FALLTHROUGH;
301 case 4:
302 target += digitString[(number >> 12) & 0xF];
303 U_FALLTHROUGH;
304 case 3:
305 target += digitString[(number >> 8) & 0xF];
306 U_FALLTHROUGH;
307 case 2:
308 target += digitString[(number >> 4) & 0xF];
309 U_FALLTHROUGH;
310 case 1:
311 target += digitString[(number >> 0) & 0xF];
312 break;
313 default:
314 target += "**";
315 }
316 return target;
317}
318
319UnicodeString
320IntlTest::toHex(uint32_t number, int32_t digits) {
321 UnicodeString result;
322 appendHex(number, digits, result);
323 return result;
324}
325
326static inline UBool isPrintable(UChar32 c) {
327 return c <= 0x7E && (c >= 0x20 || c == 9 || c == 0xA || c == 0xD);
328}
329
330// Replace nonprintable characters with unicode escapes
331UnicodeString&
332IntlTest::prettify(const UnicodeString &source,
333 UnicodeString &target)
334{
335 int32_t i;
336
337 target.remove();
338 target += "\"";
339
340 for (i = 0; i < source.length(); )
341 {
342 UChar32 ch = source.char32At(i);
343 i += U16_LENGTH(ch);
344
345 if (!isPrintable(ch))
346 {
347 if (ch <= 0xFFFF) {
348 target += "\\u";
349 appendHex(ch, 4, target);
350 } else {
351 target += "\\U";
352 appendHex(ch, 8, target);
353 }
354 }
355 else
356 {
357 target += ch;
358 }
359 }
360
361 target += "\"";
362
363 return target;
364}
365
366// Replace nonprintable characters with unicode escapes
367UnicodeString
368IntlTest::prettify(const UnicodeString &source, UBool parseBackslash)
369{
370 int32_t i;
371 UnicodeString target;
372 target.remove();
373 target += "\"";
374
375 for (i = 0; i < source.length();)
376 {
377 UChar32 ch = source.char32At(i);
378 i += U16_LENGTH(ch);
379
380 if (!isPrintable(ch))
381 {
382 if (parseBackslash) {
383 // If we are preceded by an odd number of backslashes,
384 // then this character has already been backslash escaped.
385 // Delete a backslash.
386 int32_t backslashCount = 0;
387 for (int32_t j=target.length()-1; j>=0; --j) {
388 if (target.charAt(j) == (UChar)92) {
389 ++backslashCount;
390 } else {
391 break;
392 }
393 }
394 if ((backslashCount % 2) == 1) {
395 target.truncate(target.length() - 1);
396 }
397 }
398 if (ch <= 0xFFFF) {
399 target += "\\u";
400 appendHex(ch, 4, target);
401 } else {
402 target += "\\U";
403 appendHex(ch, 8, target);
404 }
405 }
406 else
407 {
408 target += ch;
409 }
410 }
411
412 target += "\"";
413
414 return target;
415}
416
417/* IntlTest::setICU_DATA - if the ICU_DATA environment variable is not already
418 * set, try to deduce the directory in which ICU was built,
419 * and set ICU_DATA to "icu/source/data" in that location.
420 * The intent is to allow the tests to have a good chance
421 * of running without requiring that the user manually set
422 * ICU_DATA. Common data isn't a problem, since it is
423 * picked up via a static (build time) reference, but the
424 * tests dynamically load some data.
425 */
426void IntlTest::setICU_DATA() {
427 const char *original_ICU_DATA = getenv("ICU_DATA");
428
429 if (original_ICU_DATA != NULL && *original_ICU_DATA != 0) {
430 /* If the user set ICU_DATA, don't second-guess the person. */
431 return;
432 }
433
434 // U_TOPBUILDDIR is set by the makefiles on UNIXes when building cintltst and intltst
435 // to point to the top of the build hierarchy, which may or
436 // may not be the same as the source directory, depending on
437 // the configure options used. At any rate,
438 // set the data path to the built data from this directory.
439 // The value is complete with quotes, so it can be used
440 // as-is as a string constant.
441
442#if defined (U_TOPBUILDDIR)
443 {
444 static char env_string[] = U_TOPBUILDDIR "data" U_FILE_SEP_STRING "out" U_FILE_SEP_STRING;
445 u_setDataDirectory(env_string);
446 return;
447 }
448
449#else
450 // Use #else so we don't get compiler warnings due to the return above.
451
452 /* On Windows, the file name obtained from __FILE__ includes a full path.
453 * This file is "wherever\icu\source\test\cintltst\cintltst.c"
454 * Change to "wherever\icu\source\data"
455 */
456 {
457 char p[sizeof(__FILE__) + 10];
458 char *pBackSlash;
459 int i;
460
461 strcpy(p, __FILE__);
462 /* We want to back over three '\' chars. */
463 /* Only Windows should end up here, so looking for '\' is safe. */
464 for (i=1; i<=3; i++) {
465 pBackSlash = strrchr(p, U_FILE_SEP_CHAR);
466 if (pBackSlash != NULL) {
467 *pBackSlash = 0; /* Truncate the string at the '\' */
468 }
469 }
470
471 if (pBackSlash != NULL) {
472 /* We found and truncated three names from the path.
473 * Now append "source\data" and set the environment
474 */
475 strcpy(pBackSlash, U_FILE_SEP_STRING "data" U_FILE_SEP_STRING "out" U_FILE_SEP_STRING);
476 u_setDataDirectory(p); /* p is "ICU_DATA=wherever\icu\source\data" */
477 return;
478 }
479 else {
480 /* __FILE__ on MSVC7 does not contain the directory */
481 u_setDataDirectory(".." U_FILE_SEP_STRING ".." U_FILE_SEP_STRING "data" U_FILE_SEP_STRING "out" U_FILE_SEP_STRING);
482 return;
483 }
484 }
485#endif
486
487 /* No location for the data dir was identifiable.
488 * Add other fallbacks for the test data location here if the need arises
489 */
490}
491
492
493//--------------------------------------------------------------------------------------
494
495static const int32_t indentLevel_offset = 3;
496static const char delim = '/';
497
498IntlTest* IntlTest::gTest = NULL;
499
500static int32_t execCount = 0;
501
502void it_log( UnicodeString message )
503{
504 if (IntlTest::gTest)
505 IntlTest::gTest->log( message );
506}
507
508void it_logln( UnicodeString message )
509{
510 if (IntlTest::gTest)
511 IntlTest::gTest->logln( message );
512}
513
514void it_logln( void )
515{
516 if (IntlTest::gTest)
517 IntlTest::gTest->logln();
518}
519
520void it_info( UnicodeString message )
521{
522 if (IntlTest::gTest)
523 IntlTest::gTest->info( message );
524}
525
526void it_infoln( UnicodeString message )
527{
528 if (IntlTest::gTest)
529 IntlTest::gTest->infoln( message );
530}
531
532void it_infoln( void )
533{
534 if (IntlTest::gTest)
535 IntlTest::gTest->infoln();
536}
537
538void it_err()
539{
540 if (IntlTest::gTest)
541 IntlTest::gTest->err();
542}
543
544void it_err( UnicodeString message )
545{
546 if (IntlTest::gTest)
547 IntlTest::gTest->err( message );
548}
549
550void it_errln( UnicodeString message )
551{
552 if (IntlTest::gTest)
553 IntlTest::gTest->errln( message );
554}
555
556void it_dataerr( UnicodeString message )
557{
558 if (IntlTest::gTest)
559 IntlTest::gTest->dataerr( message );
560}
561
562void it_dataerrln( UnicodeString message )
563{
564 if (IntlTest::gTest)
565 IntlTest::gTest->dataerrln( message );
566}
567
568IntlTest::IntlTest()
569{
570 caller = NULL;
571 testPath = NULL;
Frank Tang1f164ee2022-11-08 12:31:27 -0800572 LL_linestart = true;
Frank Tang3e05d9d2021-11-08 14:04:04 -0800573 errorCount = 0;
574 dataErrorCount = 0;
Frank Tang1f164ee2022-11-08 12:31:27 -0800575 verbose = false;
576 no_time = false;
577 no_err_msg = false;
578 warn_on_missing_data = false;
579 quick = false;
580 leaks = false;
Frank Tang3e05d9d2021-11-08 14:04:04 -0800581 threadCount = 12;
582 testoutfp = stdout;
583 LL_indentlevel = indentLevel_offset;
584 numProps = 0;
585 strcpy(basePath, "/");
586 currName[0]=0;
587}
588
589void IntlTest::setCaller( IntlTest* callingTest )
590{
591 caller = callingTest;
592 if (caller) {
593 warn_on_missing_data = caller->warn_on_missing_data;
594 verbose = caller->verbose;
595 no_err_msg = caller->no_err_msg;
596 quick = caller->quick;
597 threadCount = caller->threadCount;
598 testoutfp = caller->testoutfp;
599 write_golden_data = caller->write_golden_data;
600 LL_indentlevel = caller->LL_indentlevel + indentLevel_offset;
601 numProps = caller->numProps;
602 for (int32_t i = 0; i < numProps; i++) {
603 proplines[i] = caller->proplines[i];
604 }
605 }
606}
607
608UBool IntlTest::callTest( IntlTest& testToBeCalled, char* par )
609{
610 execCount--; // correct a previously assumed test-exec, as this only calls a subtest
611 testToBeCalled.setCaller( this );
612 strcpy(testToBeCalled.basePath, this->basePath );
613 UBool result = testToBeCalled.runTest( testPath, par, testToBeCalled.basePath );
614 strcpy(testToBeCalled.basePath, this->basePath ); // reset it.
615 return result;
616}
617
618void IntlTest::setPath( char* pathVal )
619{
620 this->testPath = pathVal;
621}
622
623UBool IntlTest::setVerbose( UBool verboseVal )
624{
625 UBool rval = this->verbose;
626 this->verbose = verboseVal;
627 return rval;
628}
629
630UBool IntlTest::setNotime( UBool no_time )
631{
632 UBool rval = this->no_time;
633 this->no_time = no_time;
634 return rval;
635}
636
637UBool IntlTest::setWarnOnMissingData( UBool warn_on_missing_dataVal )
638{
639 UBool rval = this->warn_on_missing_data;
640 this->warn_on_missing_data = warn_on_missing_dataVal;
641 return rval;
642}
643
644UBool IntlTest::setWriteGoldenData( UBool write_golden_data )
645{
646 UBool rval = this->write_golden_data;
647 this->write_golden_data = write_golden_data;
648 return rval;
649}
650
651UBool IntlTest::setNoErrMsg( UBool no_err_msgVal )
652{
653 UBool rval = this->no_err_msg;
654 this->no_err_msg = no_err_msgVal;
655 return rval;
656}
657
658UBool IntlTest::setQuick( UBool quickVal )
659{
660 UBool rval = this->quick;
661 this->quick = quickVal;
662 return rval;
663}
664
665UBool IntlTest::setLeaks( UBool leaksVal )
666{
667 UBool rval = this->leaks;
668 this->leaks = leaksVal;
669 return rval;
670}
671
672int32_t IntlTest::setThreadCount( int32_t count )
673{
674 int32_t rval = this->threadCount;
675 this->threadCount = count;
676 return rval;
677}
678
679int32_t IntlTest::getErrors( void )
680{
681 return errorCount;
682}
683
684int32_t IntlTest::getDataErrors( void )
685{
686 return dataErrorCount;
687}
688
689UBool IntlTest::runTest( char* name, char* par, char *baseName )
690{
691 UBool rval;
692 char* pos = NULL;
693
694 char* baseNameBuffer = NULL;
695
696 if(baseName == NULL) {
697 baseNameBuffer = (char*)malloc(1024);
698 baseName=baseNameBuffer;
699 strcpy(baseName, "/");
700 }
701
702 if (name)
703 pos = strchr( name, delim ); // check if name contains path (by looking for '/')
704 if (pos) {
705 testPath = pos+1; // store subpath for calling subtest
706 *pos = 0; // split into two strings
707 }else{
708 testPath = NULL;
709 }
710
711 if (!name || (name[0] == 0) || (strcmp(name, "*") == 0)) {
712 rval = runTestLoop( NULL, par, baseName );
713
714 }else if (strcmp( name, "LIST" ) == 0) {
715 this->usage();
Frank Tang1f164ee2022-11-08 12:31:27 -0800716 rval = true;
Frank Tang3e05d9d2021-11-08 14:04:04 -0800717
718 }else{
719 rval = runTestLoop( name, par, baseName );
720 }
721
722 if (pos)
723 *pos = delim; // restore original value at pos
724 if(baseNameBuffer!=NULL) {
725 free(baseNameBuffer);
726 }
727 return rval;
728}
729
730// call individual tests, to be overridden to call implementations
731void IntlTest::runIndexedTest( int32_t /*index*/, UBool /*exec*/, const char* & /*name*/, char* /*par*/ )
732{
733 // to be overridden by a method like:
734 /*
735 switch (index) {
736 case 0: name = "First Test"; if (exec) FirstTest( par ); break;
737 case 1: name = "Second Test"; if (exec) SecondTest( par ); break;
738 default: name = ""; break;
739 }
740 */
741 this->errln("*** runIndexedTest needs to be overridden! ***");
742}
743
744
745UBool IntlTest::runTestLoop( char* testname, char* par, char *baseName )
746{
747 int32_t index = 0;
748 const char* name;
749 UBool run_this_test;
750 int32_t lastErrorCount;
Frank Tang1f164ee2022-11-08 12:31:27 -0800751 UBool rval = false;
Frank Tang3e05d9d2021-11-08 14:04:04 -0800752 UBool lastTestFailed;
753
754 if(baseName == NULL) {
755 printf("ERROR: baseName can't be null.\n");
Frank Tang1f164ee2022-11-08 12:31:27 -0800756 return false;
Frank Tang3e05d9d2021-11-08 14:04:04 -0800757 } else {
758 if ((char *)this->basePath != baseName) {
759 strcpy(this->basePath, baseName);
760 }
761 }
762
763 char * saveBaseLoc = baseName+strlen(baseName);
764
765 IntlTest* saveTest = gTest;
766 gTest = this;
767 do {
Frank Tang1f164ee2022-11-08 12:31:27 -0800768 this->runIndexedTest( index, false, name, par );
Frank Tang3e05d9d2021-11-08 14:04:04 -0800769 if (strcmp(name,"skip") == 0) {
Frank Tang1f164ee2022-11-08 12:31:27 -0800770 run_this_test = false;
Frank Tang3e05d9d2021-11-08 14:04:04 -0800771 } else {
772 if (!name || (name[0] == 0))
773 break;
774 if (!testname) {
Frank Tang1f164ee2022-11-08 12:31:27 -0800775 run_this_test = true;
Frank Tang3e05d9d2021-11-08 14:04:04 -0800776 }else{
777 run_this_test = (UBool) (strcmp( name, testname ) == 0);
778 }
779 }
780 if (run_this_test) {
781 lastErrorCount = errorCount;
782 execCount++;
783 char msg[256];
784 sprintf(msg, "%s {", name);
Frank Tang1f164ee2022-11-08 12:31:27 -0800785 LL_message(msg, true);
Frank Tang3e05d9d2021-11-08 14:04:04 -0800786 UDate timeStart = uprv_getRawUTCtime();
787 strcpy(saveBaseLoc,name);
788 strcat(saveBaseLoc,"/");
789
790 strcpy(currName, name); // set
Frank Tang1f164ee2022-11-08 12:31:27 -0800791 this->runIndexedTest( index, true, name, par );
Frank Tang3e05d9d2021-11-08 14:04:04 -0800792 currName[0]=0; // reset
793
794 UDate timeStop = uprv_getRawUTCtime();
Frank Tang1f164ee2022-11-08 12:31:27 -0800795 rval = true; // at least one test has been called
Frank Tang3e05d9d2021-11-08 14:04:04 -0800796 char secs[256];
797 if(!no_time) {
798 sprintf(secs, "%f", (timeStop-timeStart)/1000.0);
799 } else {
800 secs[0]=0;
801 }
802
803
804 strcpy(saveBaseLoc,name);
805
806
807 ctest_xml_testcase(baseName, name, secs, (lastErrorCount!=errorCount)?"err":NULL);
808
809
810 saveBaseLoc[0]=0; /* reset path */
811
812 if (lastErrorCount == errorCount) {
813 sprintf( msg, " } OK: %s ", name );
814 if(!no_time) str_timeDelta(msg+strlen(msg),timeStop-timeStart);
Frank Tang1f164ee2022-11-08 12:31:27 -0800815 lastTestFailed = false;
Frank Tang3e05d9d2021-11-08 14:04:04 -0800816 }else{
817 sprintf(msg, " } ERRORS (%li) in %s", (long)(errorCount-lastErrorCount), name);
818 if(!no_time) str_timeDelta(msg+strlen(msg),timeStop-timeStart);
819
820 for(int i=0;i<LL_indentlevel;i++) {
821 errorList += " ";
822 }
823 errorList += name;
824 errorList += "\n";
Frank Tang1f164ee2022-11-08 12:31:27 -0800825 lastTestFailed = true;
Frank Tang3e05d9d2021-11-08 14:04:04 -0800826 }
827 LL_indentlevel -= 3;
828 if (lastTestFailed) {
Frank Tang1f164ee2022-11-08 12:31:27 -0800829 LL_message( "", true);
Frank Tang3e05d9d2021-11-08 14:04:04 -0800830 }
Frank Tang1f164ee2022-11-08 12:31:27 -0800831 LL_message( msg, true);
Frank Tang3e05d9d2021-11-08 14:04:04 -0800832 if (lastTestFailed) {
Frank Tang1f164ee2022-11-08 12:31:27 -0800833 LL_message( "", true);
Frank Tang3e05d9d2021-11-08 14:04:04 -0800834 }
835 LL_indentlevel += 3;
836 }
837 index++;
838 }while(name);
839
840 *saveBaseLoc = 0;
841
842 gTest = saveTest;
843 return rval;
844}
845
846
847/**
848* Adds given string to the log if we are in verbose mode.
849*/
850void IntlTest::log( const UnicodeString &message )
851{
852 if( verbose ) {
Frank Tang1f164ee2022-11-08 12:31:27 -0800853 LL_message( message, false );
Frank Tang3e05d9d2021-11-08 14:04:04 -0800854 }
855}
856
857/**
858* Adds given string to the log if we are in verbose mode. Adds a new line to
859* the given message.
860*/
861void IntlTest::logln( const UnicodeString &message )
862{
863 if( verbose ) {
Frank Tang1f164ee2022-11-08 12:31:27 -0800864 LL_message( message, true );
Frank Tang3e05d9d2021-11-08 14:04:04 -0800865 }
866}
867
868void IntlTest::logln( void )
869{
870 if( verbose ) {
Frank Tang1f164ee2022-11-08 12:31:27 -0800871 LL_message( "", true );
Frank Tang3e05d9d2021-11-08 14:04:04 -0800872 }
873}
874
875/**
876* Unconditionally adds given string to the log.
877*/
878void IntlTest::info( const UnicodeString &message )
879{
Frank Tang1f164ee2022-11-08 12:31:27 -0800880 LL_message( message, false );
Frank Tang3e05d9d2021-11-08 14:04:04 -0800881}
882
883/**
884* Unconditionally adds given string to the log. Adds a new line to
885* the given message.
886*/
887void IntlTest::infoln( const UnicodeString &message )
888{
Frank Tang1f164ee2022-11-08 12:31:27 -0800889 LL_message( message, true );
Frank Tang3e05d9d2021-11-08 14:04:04 -0800890}
891
892void IntlTest::infoln( void )
893{
Frank Tang1f164ee2022-11-08 12:31:27 -0800894 LL_message( "", true );
Frank Tang3e05d9d2021-11-08 14:04:04 -0800895}
896
897int32_t IntlTest::IncErrorCount( void )
898{
899 errorCount++;
900 if (caller) caller->IncErrorCount();
901 return errorCount;
902}
903
904int32_t IntlTest::IncDataErrorCount( void )
905{
906 dataErrorCount++;
907 if (caller) caller->IncDataErrorCount();
908 return dataErrorCount;
909}
910
911void IntlTest::err()
912{
913 IncErrorCount();
914}
915
916void IntlTest::err( const UnicodeString &message )
917{
918 IncErrorCount();
Frank Tang1f164ee2022-11-08 12:31:27 -0800919 if (!no_err_msg) LL_message( message, false );
Frank Tang3e05d9d2021-11-08 14:04:04 -0800920}
921
922void IntlTest::errln( const UnicodeString &message )
923{
924 IncErrorCount();
Frank Tang1f164ee2022-11-08 12:31:27 -0800925 if (!no_err_msg) LL_message( message, true );
Frank Tang3e05d9d2021-11-08 14:04:04 -0800926}
927
928void IntlTest::dataerr( const UnicodeString &message )
929{
930 IncDataErrorCount();
931
932 if (!warn_on_missing_data) {
933 IncErrorCount();
934 }
935
Frank Tang1f164ee2022-11-08 12:31:27 -0800936 if (!no_err_msg) LL_message( message, false );
Frank Tang3e05d9d2021-11-08 14:04:04 -0800937}
938
939void IntlTest::dataerrln( const UnicodeString &message )
940{
941 int32_t errCount = IncDataErrorCount();
942 UnicodeString msg;
943 if (!warn_on_missing_data) {
944 IncErrorCount();
945 msg = message;
946 } else {
947 msg = UnicodeString("[DATA] " + message);
948 }
949
950 if (!no_err_msg) {
951 if ( errCount == 1) {
Frank Tang1f164ee2022-11-08 12:31:27 -0800952 LL_message( msg + " - (Are you missing data?)", true ); // only show this message the first time
Frank Tang3e05d9d2021-11-08 14:04:04 -0800953 } else {
Frank Tang1f164ee2022-11-08 12:31:27 -0800954 LL_message( msg , true );
Frank Tang3e05d9d2021-11-08 14:04:04 -0800955 }
956 }
957}
958
959void IntlTest::errcheckln(UErrorCode status, const UnicodeString &message ) {
960 if (status == U_FILE_ACCESS_ERROR || status == U_MISSING_RESOURCE_ERROR) {
961 dataerrln(message);
962 } else {
963 errln(message);
964 }
965}
966
967/* convenience functions that include sprintf formatting */
968void IntlTest::log(const char *fmt, ...)
969{
970 char buffer[4000];
971 va_list ap;
972
973 va_start(ap, fmt);
974 /* sprintf it just to make sure that the information is valid */
975 vsprintf(buffer, fmt, ap);
976 va_end(ap);
977 if( verbose ) {
978 log(UnicodeString(buffer, (const char *)NULL));
979 }
980}
981
982void IntlTest::logln(const char *fmt, ...)
983{
984 char buffer[4000];
985 va_list ap;
986
987 va_start(ap, fmt);
988 /* sprintf it just to make sure that the information is valid */
989 vsprintf(buffer, fmt, ap);
990 va_end(ap);
991 if( verbose ) {
992 logln(UnicodeString(buffer, (const char *)NULL));
993 }
994}
995
996UBool IntlTest::logKnownIssue(const char *ticket, const char *fmt, ...)
997{
998 char buffer[4000];
999 va_list ap;
1000
1001 va_start(ap, fmt);
1002 /* sprintf it just to make sure that the information is valid */
1003 vsprintf(buffer, fmt, ap);
1004 va_end(ap);
1005 return logKnownIssue(ticket, UnicodeString(buffer, (const char *)NULL));
1006}
1007
1008UBool IntlTest::logKnownIssue(const char *ticket) {
1009 return logKnownIssue(ticket, UnicodeString());
1010}
1011
1012UBool IntlTest::logKnownIssue(const char *ticket, const UnicodeString &msg) {
Frank Tang1f164ee2022-11-08 12:31:27 -08001013 if(noKnownIssues) return false;
Frank Tang3e05d9d2021-11-08 14:04:04 -08001014
1015 char fullpath[2048];
1016 strcpy(fullpath, basePath);
1017 strcat(fullpath, currName);
1018 UnicodeString msg2 = msg;
Frank Tang1f164ee2022-11-08 12:31:27 -08001019 UBool firstForTicket = true, firstForWhere = true;
Frank Tang3e05d9d2021-11-08 14:04:04 -08001020 knownList = udbg_knownIssue_openU(knownList, ticket, fullpath, msg2.getTerminatedBuffer(), &firstForTicket, &firstForWhere);
1021
1022 msg2 = UNICODE_STRING_SIMPLE("(Known issue ") +
1023 UnicodeString(ticket, -1, US_INV) + UNICODE_STRING_SIMPLE(") ") + msg;
1024 if(firstForTicket || firstForWhere) {
1025 infoln(msg2);
1026 } else {
1027 logln(msg2);
1028 }
1029
Frank Tang1f164ee2022-11-08 12:31:27 -08001030 return true;
Frank Tang3e05d9d2021-11-08 14:04:04 -08001031}
1032
1033/* convenience functions that include sprintf formatting */
1034void IntlTest::info(const char *fmt, ...)
1035{
1036 char buffer[4000];
1037 va_list ap;
1038
1039 va_start(ap, fmt);
1040 /* sprintf it just to make sure that the information is valid */
1041 vsprintf(buffer, fmt, ap);
1042 va_end(ap);
1043 info(UnicodeString(buffer, (const char *)NULL));
1044}
1045
1046void IntlTest::infoln(const char *fmt, ...)
1047{
1048 char buffer[4000];
1049 va_list ap;
1050
1051 va_start(ap, fmt);
1052 /* sprintf it just to make sure that the information is valid */
1053 vsprintf(buffer, fmt, ap);
1054 va_end(ap);
1055 infoln(UnicodeString(buffer, (const char *)NULL));
1056}
1057
1058void IntlTest::err(const char *fmt, ...)
1059{
1060 char buffer[4000];
1061 va_list ap;
1062
1063 va_start(ap, fmt);
1064 vsprintf(buffer, fmt, ap);
1065 va_end(ap);
1066 err(UnicodeString(buffer, (const char *)NULL));
1067}
1068
1069void IntlTest::errln(const char *fmt, ...)
1070{
1071 char buffer[4000];
1072 va_list ap;
1073
1074 va_start(ap, fmt);
1075 vsprintf(buffer, fmt, ap);
1076 va_end(ap);
1077 errln(UnicodeString(buffer, (const char *)NULL));
1078}
1079
1080void IntlTest::dataerrln(const char *fmt, ...)
1081{
1082 char buffer[4000];
1083 va_list ap;
1084
1085 va_start(ap, fmt);
1086 vsprintf(buffer, fmt, ap);
1087 va_end(ap);
1088 dataerrln(UnicodeString(buffer, (const char *)NULL));
1089}
1090
1091void IntlTest::errcheckln(UErrorCode status, const char *fmt, ...)
1092{
1093 char buffer[4000];
1094 va_list ap;
1095
1096 va_start(ap, fmt);
1097 vsprintf(buffer, fmt, ap);
1098 va_end(ap);
1099
1100 if (status == U_FILE_ACCESS_ERROR || status == U_MISSING_RESOURCE_ERROR) {
1101 dataerrln(UnicodeString(buffer, (const char *)NULL));
1102 } else {
1103 errln(UnicodeString(buffer, (const char *)NULL));
1104 }
1105}
1106
1107void IntlTest::printErrors()
1108{
Frank Tang1f164ee2022-11-08 12:31:27 -08001109 IntlTest::LL_message(errorList, true);
Frank Tang3e05d9d2021-11-08 14:04:04 -08001110}
1111
1112UBool IntlTest::printKnownIssues()
1113{
1114 if(knownList != NULL) {
1115 udbg_knownIssue_print(knownList);
1116 udbg_knownIssue_close(knownList);
Frank Tang1f164ee2022-11-08 12:31:27 -08001117 return true;
Frank Tang3e05d9d2021-11-08 14:04:04 -08001118 } else {
Frank Tang1f164ee2022-11-08 12:31:27 -08001119 return false;
Frank Tang3e05d9d2021-11-08 14:04:04 -08001120 }
1121}
1122
1123
1124void IntlTest::LL_message( UnicodeString message, UBool newline )
1125{
1126 // Synchronize this function.
1127 // All error messages generated by tests funnel through here.
1128 // Multithreaded tests can concurrently generate errors, requiring synchronization
1129 // to keep each message together.
1130 static UMutex messageMutex;
1131 Mutex lock(&messageMutex);
1132
1133 // string that starts with a LineFeed character and continues
1134 // with spaces according to the current indentation
1135 static const UChar indentUChars[] = {
1136 '\n',
1137 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1138 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1139 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1140 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1141 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1142 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1143 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1144 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1145 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1146 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32
1147 };
1148 U_ASSERT(1 + LL_indentlevel <= UPRV_LENGTHOF(indentUChars));
Frank Tang1f164ee2022-11-08 12:31:27 -08001149 UnicodeString indent(false, indentUChars, 1 + LL_indentlevel);
Frank Tang3e05d9d2021-11-08 14:04:04 -08001150
1151 char buffer[30000];
1152 int32_t length;
1153
1154 // stream out the indentation string first if necessary
1155 length = indent.extract(1, indent.length(), buffer, sizeof(buffer));
1156 if (length > 0) {
1157 fwrite(buffer, sizeof(*buffer), length, (FILE *)testoutfp);
1158 }
1159
1160 // replace each LineFeed by the indentation string
1161 message.findAndReplace(UnicodeString((UChar)'\n'), indent);
1162
1163 // stream out the message
1164 length = message.extract(0, message.length(), buffer, sizeof(buffer));
1165 if (length > 0) {
1166 length = length > 30000 ? 30000 : length;
1167 fwrite(buffer, sizeof(*buffer), length, (FILE *)testoutfp);
1168 }
1169
1170 if (newline) {
1171 char newLine = '\n';
1172 fwrite(&newLine, sizeof(newLine), 1, (FILE *)testoutfp);
1173 }
1174
1175 // A newline usually flushes the buffer, but
1176 // flush the message just in case of a core dump.
1177 fflush((FILE *)testoutfp);
1178}
1179
1180/**
1181* Print a usage message for this test class.
1182*/
1183void IntlTest::usage( void )
1184{
Frank Tang1f164ee2022-11-08 12:31:27 -08001185 UBool save_verbose = setVerbose( true );
Frank Tang3e05d9d2021-11-08 14:04:04 -08001186 logln("Test names:");
1187 logln("-----------");
1188
1189 int32_t index = 0;
1190 const char* name = NULL;
1191 do{
Frank Tang1f164ee2022-11-08 12:31:27 -08001192 this->runIndexedTest( index, false, name );
Frank Tang3e05d9d2021-11-08 14:04:04 -08001193 if (!name) break;
1194 logln(name);
1195 index++;
1196 }while (name && (name[0] != 0));
1197 setVerbose( save_verbose );
1198}
1199
1200
1201// memory leak reporting software will be able to take advantage of the testsuite
1202// being run a second time local to a specific method in order to report only actual leaks
1203UBool
1204IntlTest::run_phase2( char* name, char* par ) // supports reporting memory leaks
1205{
1206 UnicodeString* strLeak = new UnicodeString("forced leak"); // for verifying purify filter
1207 strLeak->append(" for verifying purify filter");
1208 return this->runTest( name, par );
1209}
1210
1211
1212#if UCONFIG_NO_LEGACY_CONVERSION
1213# define TRY_CNV_1 "iso-8859-1"
1214# define TRY_CNV_2 "ibm-1208"
1215#else
1216# define TRY_CNV_1 "iso-8859-7"
1217# define TRY_CNV_2 "sjis"
1218#endif
1219
1220#ifdef UNISTR_COUNT_FINAL_STRING_LENGTHS
1221U_CAPI void unistr_printLengths();
1222#endif
1223
1224int
1225main(int argc, char* argv[])
1226{
Frank Tang1f164ee2022-11-08 12:31:27 -08001227 UBool syntax = false;
1228 UBool all = false;
1229 UBool verbose = false;
1230 UBool no_err_msg = false;
1231 UBool no_time = false;
1232 UBool quick = true;
1233 UBool name = false;
1234 UBool leaks = false;
1235 UBool utf8 = false;
Frank Tang3e05d9d2021-11-08 14:04:04 -08001236 const char *summary_file = NULL;
Frank Tang1f164ee2022-11-08 12:31:27 -08001237 UBool warnOnMissingData = false;
1238 UBool writeGoldenData = false;
1239 UBool defaultDataFound = false;
Frank Tang3e05d9d2021-11-08 14:04:04 -08001240 int32_t threadCount = 12;
1241 UErrorCode errorCode = U_ZERO_ERROR;
1242 UConverter *cnv = NULL;
1243 const char *warnOrErr = "Failure";
1244 UDate startTime, endTime;
1245 int32_t diffTime;
1246 const char *props[IntlTest::kMaxProps];
1247 int32_t nProps = 0;
1248
1249 U_MAIN_INIT_ARGS(argc, argv);
1250
1251 startTime = uprv_getRawUTCtime();
1252
1253 for (int i = 1; i < argc; ++i) {
1254 if (argv[i][0] == '-') {
1255 const char* str = argv[i] + 1;
1256 if (strcmp("verbose", str) == 0 ||
1257 strcmp("v", str) == 0)
Frank Tang1f164ee2022-11-08 12:31:27 -08001258 verbose = true;
Frank Tang3e05d9d2021-11-08 14:04:04 -08001259 else if (strcmp("noerrormsg", str) == 0 ||
1260 strcmp("n", str) == 0)
Frank Tang1f164ee2022-11-08 12:31:27 -08001261 no_err_msg = true;
Frank Tang3e05d9d2021-11-08 14:04:04 -08001262 else if (strcmp("exhaustive", str) == 0 ||
1263 strcmp("e", str) == 0)
Frank Tang1f164ee2022-11-08 12:31:27 -08001264 quick = false;
Frank Tang3e05d9d2021-11-08 14:04:04 -08001265 else if (strcmp("all", str) == 0 ||
1266 strcmp("a", str) == 0)
Frank Tang1f164ee2022-11-08 12:31:27 -08001267 all = true;
Frank Tang3e05d9d2021-11-08 14:04:04 -08001268 else if (strcmp("utf-8", str) == 0 ||
1269 strcmp("u", str) == 0)
Frank Tang1f164ee2022-11-08 12:31:27 -08001270 utf8 = true;
Frank Tang3e05d9d2021-11-08 14:04:04 -08001271 else if (strcmp("noknownissues", str) == 0 ||
1272 strcmp("K", str) == 0)
Frank Tang1f164ee2022-11-08 12:31:27 -08001273 noKnownIssues = true;
Frank Tang3e05d9d2021-11-08 14:04:04 -08001274 else if (strcmp("leaks", str) == 0 ||
1275 strcmp("l", str) == 0)
Frank Tang1f164ee2022-11-08 12:31:27 -08001276 leaks = true;
Frank Tang3e05d9d2021-11-08 14:04:04 -08001277 else if (strcmp("notime", str) == 0 ||
1278 strcmp("T", str) == 0)
Frank Tang1f164ee2022-11-08 12:31:27 -08001279 no_time = true;
Frank Tang3e05d9d2021-11-08 14:04:04 -08001280 else if (strcmp("goldens", str) == 0 ||
1281 strcmp("G", str) == 0)
Frank Tang1f164ee2022-11-08 12:31:27 -08001282 writeGoldenData = true;
Frank Tang3e05d9d2021-11-08 14:04:04 -08001283 else if (strncmp("E", str, 1) == 0)
1284 summary_file = str+1;
1285 else if (strcmp("x", str)==0) {
1286 if(++i>=argc) {
1287 printf("* Error: '-x' option requires an argument. usage: '-x outfile.xml'.\n");
Frank Tang1f164ee2022-11-08 12:31:27 -08001288 syntax = true;
Frank Tang3e05d9d2021-11-08 14:04:04 -08001289 }
1290 if(ctest_xml_setFileName(argv[i])) { /* set the name */
1291 return 1; /* error */
1292 }
1293 } else if (strcmp("w", str) == 0) {
Frank Tang1f164ee2022-11-08 12:31:27 -08001294 warnOnMissingData = true;
Frank Tang3e05d9d2021-11-08 14:04:04 -08001295 warnOrErr = "WARNING";
1296 }
1297 else if (strncmp("threads:", str, 8) == 0) {
1298 threadCount = atoi(str + 8);
1299 }
1300 else if (strncmp("prop:", str, 5) == 0) {
1301 if (nProps < IntlTest::kMaxProps) {
1302 props[nProps] = str + 5;
1303 }
1304 nProps++;
1305 }
1306 else {
Frank Tang1f164ee2022-11-08 12:31:27 -08001307 syntax = true;
Frank Tang3e05d9d2021-11-08 14:04:04 -08001308 }
1309 }else{
Frank Tang1f164ee2022-11-08 12:31:27 -08001310 name = true;
Frank Tang3e05d9d2021-11-08 14:04:04 -08001311 }
1312 }
1313
1314 if (!all && !name) {
Frank Tang1f164ee2022-11-08 12:31:27 -08001315 all = true;
Frank Tang3e05d9d2021-11-08 14:04:04 -08001316 } else if (all && name) {
Frank Tang1f164ee2022-11-08 12:31:27 -08001317 syntax = true;
Frank Tang3e05d9d2021-11-08 14:04:04 -08001318 }
1319
1320 if (syntax) {
1321 fprintf(stdout,
1322 "### Syntax:\n"
1323 "### IntlTest [-option1 -option2 ...] [testname1 testname2 ...] \n"
1324 "### \n"
1325 "### Options are: verbose (v), all (a), noerrormsg (n), \n"
1326 "### exhaustive (e), leaks (l), -x xmlfile.xml, prop:<property>=<value>, \n"
1327 "### notime (T), \n"
1328 "### threads:<threadCount>\n"
1329 "### (The default thread count is 12.),\n"
1330 "### (Specify either -all (shortcut -a) or a test name). \n"
1331 "### -all will run all of the tests.\n"
1332 "### \n"
1333 "### To get a list of the test names type: intltest LIST \n"
1334 "### To run just the utility tests type: intltest utility \n"
1335 "### \n"
1336 "### Test names can be nested using slashes (\"testA/subtest1\") \n"
1337 "### For example to list the utility tests type: intltest utility/LIST \n"
1338 "### To run just the Locale test type: intltest utility/LocaleTest \n"
1339 "### \n"
1340 "### A parameter can be specified for a test by appending '@' and the value \n"
1341 "### to the testname. \n\n");
1342 return 1;
1343 }
1344
1345 if (nProps > IntlTest::kMaxProps) {
1346 fprintf(stdout, "### Too many properties. Exiting.\n");
1347 }
1348
1349 MajorTestLevel major;
1350 major.setVerbose( verbose );
1351 major.setNoErrMsg( no_err_msg );
1352 major.setQuick( quick );
1353 major.setLeaks( leaks );
1354 major.setThreadCount( threadCount );
1355 major.setWarnOnMissingData( warnOnMissingData );
1356 major.setWriteGoldenData( writeGoldenData );
1357 major.setNotime (no_time);
1358 for (int32_t i = 0; i < nProps; i++) {
1359 major.setProperty(props[i]);
1360 }
1361
1362
1363 fprintf(stdout, "-----------------------------------------------\n");
1364 fprintf(stdout, " IntlTest (C++) Test Suite for \n");
1365 fprintf(stdout, " International Components for Unicode %s\n", U_ICU_VERSION);
1366
1367
1368 {
1369 const char *charsetFamily = "Unknown";
1370 int32_t voidSize = (int32_t)sizeof(void*);
1371 int32_t bits = voidSize * 8;
1372 if(U_CHARSET_FAMILY==U_ASCII_FAMILY) {
1373 charsetFamily="ASCII";
1374 } else if(U_CHARSET_FAMILY==U_EBCDIC_FAMILY) {
1375 charsetFamily="EBCDIC";
1376 }
1377 fprintf(stdout,
1378 " Bits: %d, Byte order: %s, Chars: %s\n",
1379 bits, U_IS_BIG_ENDIAN?"Big endian":"Little endian",
1380 charsetFamily);
1381 }
1382 fprintf(stdout, "-----------------------------------------------\n");
1383 fprintf(stdout, " Options: \n");
1384 fprintf(stdout, " all (a) : %s\n", (all? "On" : "Off"));
1385 fprintf(stdout, " Verbose (v) : %s\n", (verbose? "On" : "Off"));
1386 fprintf(stdout, " No error messages (n) : %s\n", (no_err_msg? "On" : "Off"));
1387 fprintf(stdout, " Exhaustive (e) : %s\n", (!quick? "On" : "Off"));
1388 fprintf(stdout, " Leaks (l) : %s\n", (leaks? "On" : "Off"));
1389 fprintf(stdout, " utf-8 (u) : %s\n", (utf8? "On" : "Off"));
1390 fprintf(stdout, " notime (T) : %s\n", (no_time? "On" : "Off"));
1391 fprintf(stdout, " noknownissues (K) : %s\n", (noKnownIssues? "On" : "Off"));
1392 fprintf(stdout, " Warn on missing data (w) : %s\n", (warnOnMissingData? "On" : "Off"));
1393 fprintf(stdout, " Write golden data (G) : %s\n", (writeGoldenData? "On" : "Off"));
1394 fprintf(stdout, " Threads : %d\n", threadCount);
1395 for (int32_t i = 0; i < nProps; i++) {
1396 fprintf(stdout, " Custom property (prop:) : %s\n", props[i]);
1397 }
1398 fprintf(stdout, "-----------------------------------------------\n");
1399
1400 if(utf8) {
1401 ucnv_setDefaultName("utf-8");
1402 }
1403 /* Check whether ICU will initialize without forcing the build data directory into
1404 * the ICU_DATA path. Success here means either the data dll contains data, or that
1405 * this test program was run with ICU_DATA set externally. Failure of this check
1406 * is normal when ICU data is not packaged into a shared library.
1407 *
1408 * Whether or not this test succeeds, we want to cleanup and reinitialize
1409 * with a data path so that data loading from individual files can be tested.
1410 */
1411 u_init(&errorCode);
1412 if (U_FAILURE(errorCode)) {
1413 fprintf(stderr,
1414 "#### Note: ICU Init without build-specific setDataDirectory() failed.\n");
Frank Tang1f164ee2022-11-08 12:31:27 -08001415 defaultDataFound = false;
Frank Tang3e05d9d2021-11-08 14:04:04 -08001416 }
1417 else {
Frank Tang1f164ee2022-11-08 12:31:27 -08001418 defaultDataFound = true;
Frank Tang3e05d9d2021-11-08 14:04:04 -08001419 }
1420 u_cleanup();
1421 if(utf8) {
1422 ucnv_setDefaultName("utf-8");
1423 }
1424 errorCode = U_ZERO_ERROR;
1425
1426 /* Initialize ICU */
1427 if (!defaultDataFound) {
1428 IntlTest::setICU_DATA(); // Must set data directory before u_init() is called.
1429 }
1430 u_init(&errorCode);
1431 if (U_FAILURE(errorCode)) {
1432 fprintf(stderr,
1433 "#### ERROR! %s: u_init() failed with status = \"%s\".\n"
1434 "*** Check the ICU_DATA environment variable and \n"
1435 "*** check that the data files are present.\n", argv[0], u_errorName(errorCode));
1436 if(warnOnMissingData == 0) {
1437 fprintf(stderr, "*** Exiting. Use the '-w' option if data files were\n*** purposely removed, to continue test anyway.\n");
1438 u_cleanup();
1439 return 1;
1440 }
1441 }
1442
1443 // initial check for the default converter
1444 errorCode = U_ZERO_ERROR;
1445 cnv = ucnv_open(0, &errorCode);
1446 if(cnv != 0) {
1447 // ok
1448 ucnv_close(cnv);
1449 } else {
1450 fprintf(stdout,
1451 "*** %s! The default converter [%s] cannot be opened.\n"
1452 "*** Check the ICU_DATA environment variable and\n"
1453 "*** check that the data files are present.\n",
1454 warnOrErr, ucnv_getDefaultName());
1455 if(!warnOnMissingData) {
1456 fprintf(stdout, "*** Exiting. Use the '-w' option if data files were\n*** purposely removed, to continue test anyway.\n");
1457 return 1;
1458 }
1459 }
1460
1461 // try more data
1462 cnv = ucnv_open(TRY_CNV_2, &errorCode);
1463 if(cnv != 0) {
1464 // ok
1465 ucnv_close(cnv);
1466 } else {
1467 fprintf(stdout,
1468 "*** %s! The converter for " TRY_CNV_2 " cannot be opened.\n"
1469 "*** Check the ICU_DATA environment variable and \n"
1470 "*** check that the data files are present.\n", warnOrErr);
1471 if(!warnOnMissingData) {
1472 fprintf(stdout, "*** Exiting. Use the '-w' option if data files were\n*** purposely removed, to continue test anyway.\n");
1473 return 1;
1474 }
1475 }
1476
1477 UResourceBundle *rb = ures_open(0, "en", &errorCode);
1478 ures_close(rb);
1479 if(U_FAILURE(errorCode)) {
1480 fprintf(stdout,
1481 "*** %s! The \"en\" locale resource bundle cannot be opened.\n"
1482 "*** Check the ICU_DATA environment variable and \n"
1483 "*** check that the data files are present.\n", warnOrErr);
1484 if(!warnOnMissingData) {
1485 fprintf(stdout, "*** Exiting. Use the '-w' option if data files were\n*** purposely removed, to continue test anyway.\n");
1486 return 1;
1487 }
1488 }
1489
1490 Locale originalLocale; // Save the default locale for comparison later on.
1491
1492 if(ctest_xml_init("intltest"))
1493 return 1;
1494
1495
1496 /* TODO: Add option to call u_cleanup and rerun tests. */
1497 if (all) {
1498 major.runTest();
1499 if (leaks) {
1500 major.run_phase2( NULL, NULL );
1501 }
1502 }else{
1503 for (int i = 1; i < argc; ++i) {
1504 if (argv[i][0] != '-') {
1505 char* name = argv[i];
1506 fprintf(stdout, "\n=== Handling test: %s: ===\n", name);
1507
1508 char baseName[1024];
1509 sprintf(baseName, "/%s/", name);
1510
1511 char* parameter = strchr( name, '@' );
1512 if (parameter) {
1513 *parameter = 0;
1514 parameter += 1;
1515 }
1516 execCount = 0;
1517 UBool res = major.runTest( name, parameter, baseName );
1518 if (leaks && res) {
1519 major.run_phase2( name, parameter );
1520 }
1521 if (!res || (execCount <= 0)) {
1522 fprintf(stdout, "\n---ERROR: Test doesn't exist: %s!\n", name);
1523 }
1524 } else if(!strcmp(argv[i],"-x")) {
1525 i++;
1526 }
1527 }
1528 }
1529
1530
1531#if !UCONFIG_NO_FORMATTING
1532 CalendarTimeZoneTest::cleanup();
1533#endif
1534
1535 free(_testDataPath);
1536 _testDataPath = 0;
1537
1538 Locale lastDefaultLocale;
1539 if (originalLocale != lastDefaultLocale) {
1540 major.errln("FAILURE: A test changed the default locale without resetting it.");
1541 }
1542
1543 fprintf(stdout, "\n--------------------------------------\n");
1544 if( major.printKnownIssues() ) {
1545 fprintf(stdout, " To run suppressed tests, use the -K option. \n");
1546 }
1547 if (major.getErrors() == 0) {
1548 /* Call it twice to make sure that the defaults were reset. */
1549 /* Call it before the OK message to verify proper cleanup. */
1550 u_cleanup();
1551 u_cleanup();
1552
1553 fprintf(stdout, "OK: All tests passed without error.\n");
1554
1555 if (major.getDataErrors() != 0) {
1556 fprintf(stdout, "\t*WARNING* some data-loading errors were ignored by the -w option.\n");
1557 }
1558 }else{
1559 fprintf(stdout, "Errors in total: %ld.\n", (long)major.getErrors());
1560 major.printErrors();
1561
1562 if(summary_file != NULL) {
1563 FILE *summf = fopen(summary_file, "w");
1564 if( summf != NULL) {
1565 char buf[10000];
1566 int32_t length = errorList.extract(0, errorList.length(), buf, sizeof(buf));
1567 fwrite(buf, sizeof(*buf), length, (FILE*)summf);
1568 fclose(summf);
1569 }
1570 }
1571
1572
1573 if (major.getDataErrors() != 0) {
1574 fprintf(stdout, "\t*Note* some errors are data-loading related. If the data used is not the \n"
1575 "\tstock ICU data (i.e some have been added or removed), consider using\n"
1576 "\tthe '-w' option to turn these errors into warnings.\n");
1577 }
1578
1579 /* Call afterwards to display errors. */
1580 u_cleanup();
1581 }
1582
1583#ifdef UNISTR_COUNT_FINAL_STRING_LENGTHS
1584 unistr_printLengths();
1585#endif
1586
1587 fprintf(stdout, "--------------------------------------\n");
1588
1589 if (execCount <= 0) {
1590 fprintf(stdout, "***** Not all called tests actually exist! *****\n");
1591 }
1592 if(!no_time) {
1593 endTime = uprv_getRawUTCtime();
1594 diffTime = (int32_t)(endTime - startTime);
1595 printf("Elapsed Time: %02d:%02d:%02d.%03d\n",
1596 (int)((diffTime%U_MILLIS_PER_DAY)/U_MILLIS_PER_HOUR),
1597 (int)((diffTime%U_MILLIS_PER_HOUR)/U_MILLIS_PER_MINUTE),
1598 (int)((diffTime%U_MILLIS_PER_MINUTE)/U_MILLIS_PER_SECOND),
1599 (int)(diffTime%U_MILLIS_PER_SECOND));
1600 }
1601
1602 if(ctest_xml_fini())
1603 return 1;
1604
1605 return major.getErrors();
1606}
1607
1608const char* IntlTest::loadTestData(UErrorCode& err){
1609 if ( _testDataPath == NULL){
1610 const char* directory=NULL;
1611 UResourceBundle* test =NULL;
1612 char* tdpath=NULL;
1613 const char* tdrelativepath;
1614
1615#if defined (U_TOPBUILDDIR)
1616 tdrelativepath = "test" U_FILE_SEP_STRING "testdata" U_FILE_SEP_STRING "out" U_FILE_SEP_STRING;
1617 directory = U_TOPBUILDDIR;
1618#else
1619 tdrelativepath = ".." U_FILE_SEP_STRING "test" U_FILE_SEP_STRING "testdata" U_FILE_SEP_STRING "out" U_FILE_SEP_STRING;
1620 directory = pathToDataDirectory();
1621#endif
1622
1623 tdpath = (char*) malloc(sizeof(char) *(( strlen(directory) * strlen(tdrelativepath)) + 100));
1624
1625 if (tdpath == NULL) {
1626 err = U_MEMORY_ALLOCATION_ERROR;
1627 it_dataerrln((UnicodeString) "Could not allocate memory for _testDataPath " + u_errorName(err));
1628 return "";
1629 }
1630
1631 /* u_getDataDirectory shoul return \source\data ... set the
1632 * directory to ..\source\data\..\test\testdata\out\testdata
1633 */
1634 strcpy(tdpath, directory);
1635 strcat(tdpath, tdrelativepath);
1636 strcat(tdpath,"testdata");
1637
1638 test=ures_open(tdpath, "testtypes", &err);
1639
1640 if (U_FAILURE(err)) {
1641 err = U_FILE_ACCESS_ERROR;
1642 it_dataerrln((UnicodeString)"Could not load testtypes.res in testdata bundle with path " + tdpath + (UnicodeString)" - " + u_errorName(err));
1643 return "";
1644 }
1645 ures_close(test);
1646 _testDataPath = tdpath;
1647 return _testDataPath;
1648 }
1649 return _testDataPath;
1650}
1651
1652const char* IntlTest::getTestDataPath(UErrorCode& err) {
1653 return loadTestData(err);
1654}
1655
1656/**
1657 * Returns the path to icu/source/test/testdata/
1658 * Note: this function is parallel with C loadSourceTestData in cintltst.c
1659 */
1660const char *IntlTest::getSourceTestData(UErrorCode& /*err*/) {
1661 const char *srcDataDir = NULL;
1662#ifdef U_TOPSRCDIR
1663 srcDataDir = U_TOPSRCDIR U_FILE_SEP_STRING"test" U_FILE_SEP_STRING "testdata" U_FILE_SEP_STRING;
1664#else
1665 srcDataDir = ".." U_FILE_SEP_STRING ".." U_FILE_SEP_STRING "test" U_FILE_SEP_STRING "testdata" U_FILE_SEP_STRING;
1666 FILE *f = fopen(".." U_FILE_SEP_STRING ".." U_FILE_SEP_STRING "test" U_FILE_SEP_STRING "testdata" U_FILE_SEP_STRING "rbbitst.txt", "r");
1667 if (f) {
1668 /* We're in icu/source/test/intltest/ */
1669 fclose(f);
1670 }
1671 else {
1672 /* We're in icu/source/test/intltest/Platform/(Debug|Release) */
1673 srcDataDir = ".." U_FILE_SEP_STRING ".." U_FILE_SEP_STRING ".." U_FILE_SEP_STRING ".." U_FILE_SEP_STRING
1674 "test" U_FILE_SEP_STRING "testdata" U_FILE_SEP_STRING;
1675 }
1676#endif
1677 return srcDataDir;
1678}
1679
1680char *IntlTest::getUnidataPath(char path[]) {
1681 const int kUnicodeDataTxtLength = 15; // strlen("UnicodeData.txt")
1682
1683 // Look inside ICU_DATA first.
1684 strcpy(path, pathToDataDirectory());
1685 strcat(path, "unidata" U_FILE_SEP_STRING "UnicodeData.txt");
1686 FILE *f = fopen(path, "r");
1687 if(f != NULL) {
1688 fclose(f);
1689 *(strchr(path, 0) - kUnicodeDataTxtLength) = 0; // Remove the basename.
1690 return path;
1691 }
1692
1693 // As a fallback, try to guess where the source data was located
1694 // at the time ICU was built, and look there.
1695# ifdef U_TOPSRCDIR
1696 strcpy(path, U_TOPSRCDIR U_FILE_SEP_STRING "data");
1697# else
1698 UErrorCode errorCode = U_ZERO_ERROR;
1699 const char *testDataPath = loadTestData(errorCode);
1700 if(U_FAILURE(errorCode)) {
1701 it_errln(UnicodeString(
1702 "unable to find path to source/data/unidata/ and loadTestData() failed: ") +
1703 u_errorName(errorCode));
1704 return NULL;
1705 }
1706 strcpy(path, testDataPath);
1707 strcat(path, U_FILE_SEP_STRING ".." U_FILE_SEP_STRING ".."
1708 U_FILE_SEP_STRING ".." U_FILE_SEP_STRING ".."
1709 U_FILE_SEP_STRING "data");
1710# endif
1711 strcat(path, U_FILE_SEP_STRING);
1712 strcat(path, "unidata" U_FILE_SEP_STRING "UnicodeData.txt");
1713 f = fopen(path, "r");
1714 if(f != NULL) {
1715 fclose(f);
1716 *(strchr(path, 0) - kUnicodeDataTxtLength) = 0; // Remove the basename.
1717 return path;
1718 }
1719 return NULL;
1720}
1721
1722const char* IntlTest::fgDataDir = NULL;
1723
1724/* returns the path to icu/source/data */
1725const char * IntlTest::pathToDataDirectory()
1726{
1727
1728 if(fgDataDir != NULL) {
1729 return fgDataDir;
1730 }
1731
1732 /* U_TOPSRCDIR is set by the makefiles on UNIXes when building cintltst and intltst
1733 // to point to the top of the build hierarchy, which may or
1734 // may not be the same as the source directory, depending on
1735 // the configure options used. At any rate,
1736 // set the data path to the built data from this directory.
1737 // The value is complete with quotes, so it can be used
1738 // as-is as a string constant.
1739 */
1740#if defined (U_TOPSRCDIR)
1741 {
1742 fgDataDir = U_TOPSRCDIR U_FILE_SEP_STRING "data" U_FILE_SEP_STRING;
1743 }
1744#else
1745
1746 /* On Windows, the file name obtained from __FILE__ includes a full path.
1747 * This file is "wherever\icu\source\test\cintltst\cintltst.c"
1748 * Change to "wherever\icu\source\data"
1749 */
1750 {
1751 static char p[sizeof(__FILE__) + 10];
1752 char *pBackSlash;
1753 int i;
1754
1755 strcpy(p, __FILE__);
1756 /* We want to back over three '\' chars. */
1757 /* Only Windows should end up here, so looking for '\' is safe. */
1758 for (i=1; i<=3; i++) {
1759 pBackSlash = strrchr(p, U_FILE_SEP_CHAR);
1760 if (pBackSlash != NULL) {
1761 *pBackSlash = 0; /* Truncate the string at the '\' */
1762 }
1763 }
1764
1765 if (pBackSlash != NULL) {
1766 /* We found and truncated three names from the path.
1767 * Now append "source\data" and set the environment
1768 */
1769 strcpy(pBackSlash, U_FILE_SEP_STRING "data" U_FILE_SEP_STRING );
1770 fgDataDir = p;
1771 }
1772 else {
1773 /* __FILE__ on MSVC7 does not contain the directory */
1774 FILE *file = fopen(".." U_FILE_SEP_STRING ".." U_FILE_SEP_STRING "data" U_FILE_SEP_STRING "Makefile.in", "r");
1775 if (file) {
1776 fclose(file);
1777 fgDataDir = ".." U_FILE_SEP_STRING ".." U_FILE_SEP_STRING "data" U_FILE_SEP_STRING;
1778 }
1779 else {
1780 fgDataDir = ".." U_FILE_SEP_STRING ".." U_FILE_SEP_STRING ".." U_FILE_SEP_STRING ".." U_FILE_SEP_STRING "data" U_FILE_SEP_STRING;
1781 }
1782 }
1783 }
1784#endif
1785
1786 return fgDataDir;
1787
1788}
1789
1790/*
1791 * This is a variant of cintltst/ccolltst.c:CharsToUChars().
1792 * It converts an invariant-character string into a UnicodeString, with
1793 * unescaping \u sequences.
1794 */
1795UnicodeString CharsToUnicodeString(const char* chars){
1796 return UnicodeString(chars, -1, US_INV).unescape();
1797}
1798
1799UnicodeString ctou(const char* chars) {
1800 return CharsToUnicodeString(chars);
1801}
1802
1803#define RAND_M (714025)
1804#define RAND_IA (1366)
1805#define RAND_IC (150889)
1806
1807static int32_t RAND_SEED;
1808
1809/**
1810 * Returns a uniform random value x, with 0.0 <= x < 1.0. Use
1811 * with care: Does not return all possible values; returns one of
1812 * 714,025 values, uniformly spaced. However, the period is
1813 * effectively infinite. See: Numerical Recipes, section 7.1.
1814 *
1815 * @param seedp pointer to seed. Set *seedp to any negative value
1816 * to restart the sequence.
1817 */
1818float IntlTest::random(int32_t* seedp) {
1819 static int32_t iy, ir[98];
Frank Tang1f164ee2022-11-08 12:31:27 -08001820 static UBool first=true;
Frank Tang3e05d9d2021-11-08 14:04:04 -08001821 int32_t j;
1822 if (*seedp < 0 || first) {
Frank Tang1f164ee2022-11-08 12:31:27 -08001823 first = false;
Frank Tang3e05d9d2021-11-08 14:04:04 -08001824 if ((*seedp=(RAND_IC-(*seedp)) % RAND_M) < 0) *seedp = -(*seedp);
1825 for (j=1;j<=97;++j) {
1826 *seedp=(RAND_IA*(*seedp)+RAND_IC) % RAND_M;
1827 ir[j]=(*seedp);
1828 }
1829 *seedp=(RAND_IA*(*seedp)+RAND_IC) % RAND_M;
1830 iy=(*seedp);
1831 }
1832 j=(int32_t)(1 + 97.0*iy/RAND_M);
1833 U_ASSERT(j>=1 && j<=97);
1834 iy=ir[j];
1835 *seedp=(RAND_IA*(*seedp)+RAND_IC) % RAND_M;
1836 ir[j]=(*seedp);
1837 return (float) iy/RAND_M;
1838}
1839
1840/**
1841 * Convenience method using a global seed.
1842 */
1843float IntlTest::random() {
1844 return random(&RAND_SEED);
1845}
1846
1847
1848/*
1849 * Integer random number class implementation.
1850 * Similar to C++ std::minstd_rand, with the same algorithm & constants.
1851 */
1852IntlTest::icu_rand::icu_rand(uint32_t seed) {
1853 seed = seed % 2147483647UL;
1854 if (seed == 0) {
1855 seed = 1;
1856 }
1857 fLast = seed;
1858}
1859
1860IntlTest::icu_rand::~icu_rand() {}
1861
1862void IntlTest::icu_rand::seed(uint32_t seed) {
1863 if (seed == 0) {
1864 seed = 1;
1865 }
1866 fLast = seed;
1867}
1868
1869uint32_t IntlTest::icu_rand::operator() () {
1870 fLast = ((uint64_t)fLast * 48271UL) % 2147483647UL;
1871 return fLast;
1872}
1873
1874uint32_t IntlTest::icu_rand::getSeed() {
1875 return (uint32_t) fLast;
1876}
1877
1878
1879
1880static inline UChar toHex(int32_t i) {
1881 return (UChar)(i + (i < 10 ? 0x30 : (0x41 - 10)));
1882}
1883
1884static UnicodeString& escape(const UnicodeString& s, UnicodeString& result) {
1885 for (int32_t i=0; i<s.length(); ++i) {
1886 UChar c = s[i];
1887 if (c <= (UChar)0x7F) {
1888 result += c;
1889 } else {
1890 result += (UChar)0x5c;
1891 result += (UChar)0x75;
1892 result += toHex((c >> 12) & 0xF);
1893 result += toHex((c >> 8) & 0xF);
1894 result += toHex((c >> 4) & 0xF);
1895 result += toHex( c & 0xF);
1896 }
1897 }
1898 return result;
1899}
1900
1901#define VERBOSE_ASSERTIONS
1902
1903UBool IntlTest::assertTrue(const char* message, UBool condition, UBool quiet, UBool possibleDataError, const char *file, int line) {
1904 if (file != NULL) {
1905 if (!condition) {
1906 if (possibleDataError) {
1907 dataerrln("%s:%d: FAIL: assertTrue() failed: %s", file, line, message);
1908 } else {
1909 errln("%s:%d: FAIL: assertTrue() failed: %s", file, line, message);
1910 }
1911 } else if (!quiet) {
1912 logln("%s:%d: Ok: %s", file, line, message);
1913 }
1914 } else {
1915 if (!condition) {
1916 if (possibleDataError) {
1917 dataerrln("FAIL: assertTrue() failed: %s", message);
1918 } else {
1919 errln("FAIL: assertTrue() failed: %s", message);
1920 }
1921 } else if (!quiet) {
1922 logln("Ok: %s", message);
1923 }
1924
1925 }
1926 return condition;
1927}
1928
1929UBool IntlTest::assertFalse(const char* message, UBool condition, UBool quiet, UBool possibleDataError) {
1930 if (condition) {
1931 if (possibleDataError) {
1932 dataerrln("FAIL: assertFalse() failed: %s", message);
1933 } else {
1934 errln("FAIL: assertFalse() failed: %s", message);
1935 }
1936 } else if (!quiet) {
1937 logln("Ok: %s", message);
1938 }
1939 return !condition;
1940}
1941
1942UBool IntlTest::assertSuccess(const char* message, UErrorCode ec, UBool possibleDataError, const char *file, int line) {
1943 if( file==NULL ) {
1944 file = ""; // prevent failure if no file given
1945 }
1946 if (U_FAILURE(ec)) {
1947 if (possibleDataError) {
1948 dataerrln("FAIL: %s:%d: %s (%s)", file, line, message, u_errorName(ec));
1949 } else {
1950 errcheckln(ec, "FAIL: %s:%d: %s (%s)", file, line, message, u_errorName(ec));
1951 }
Frank Tang1f164ee2022-11-08 12:31:27 -08001952 return false;
Frank Tang3e05d9d2021-11-08 14:04:04 -08001953 } else {
1954 logln("OK: %s:%d: %s - (%s)", file, line, message, u_errorName(ec));
1955 }
Frank Tang1f164ee2022-11-08 12:31:27 -08001956 return true;
Frank Tang3e05d9d2021-11-08 14:04:04 -08001957}
1958
1959UBool IntlTest::assertEquals(const char* message,
1960 const UnicodeString& expected,
1961 const UnicodeString& actual,
1962 UBool possibleDataError) {
1963 if (expected != actual) {
1964 if (possibleDataError) {
1965 dataerrln((UnicodeString)"FAIL: " + message + "; got " +
1966 prettify(actual) +
1967 "; expected " + prettify(expected));
1968 } else {
1969 errln((UnicodeString)"FAIL: " + message + "; got " +
1970 prettify(actual) +
1971 "; expected " + prettify(expected));
1972 }
Frank Tang1f164ee2022-11-08 12:31:27 -08001973 return false;
Frank Tang3e05d9d2021-11-08 14:04:04 -08001974 }
1975#ifdef VERBOSE_ASSERTIONS
1976 else {
1977 logln((UnicodeString)"Ok: " + message + "; got " + prettify(actual));
1978 }
1979#endif
Frank Tang1f164ee2022-11-08 12:31:27 -08001980 return true;
Frank Tang3e05d9d2021-11-08 14:04:04 -08001981}
1982
1983UBool IntlTest::assertEquals(const char* message,
1984 const char* expected,
1985 const char* actual) {
1986 U_ASSERT(expected != nullptr);
1987 U_ASSERT(actual != nullptr);
1988 if (uprv_strcmp(expected, actual) != 0) {
1989 errln((UnicodeString)"FAIL: " + message + "; got \"" +
1990 actual +
1991 "\"; expected \"" + expected + "\"");
Frank Tang1f164ee2022-11-08 12:31:27 -08001992 return false;
Frank Tang3e05d9d2021-11-08 14:04:04 -08001993 }
1994#ifdef VERBOSE_ASSERTIONS
1995 else {
1996 logln((UnicodeString)"Ok: " + message + "; got \"" + actual + "\"");
1997 }
1998#endif
Frank Tang1f164ee2022-11-08 12:31:27 -08001999 return true;
Frank Tang3e05d9d2021-11-08 14:04:04 -08002000}
2001
2002UBool IntlTest::assertEquals(const char* message,
2003 int32_t expected,
2004 int32_t actual) {
2005 if (expected != actual) {
2006 errln((UnicodeString)"FAIL: " + message + "; got " +
2007 actual + "=0x" + toHex(actual) +
2008 "; expected " + expected + "=0x" + toHex(expected));
Frank Tang1f164ee2022-11-08 12:31:27 -08002009 return false;
Frank Tang3e05d9d2021-11-08 14:04:04 -08002010 }
2011#ifdef VERBOSE_ASSERTIONS
2012 else {
2013 logln((UnicodeString)"Ok: " + message + "; got " + actual + "=0x" + toHex(actual));
2014 }
2015#endif
Frank Tang1f164ee2022-11-08 12:31:27 -08002016 return true;
Frank Tang3e05d9d2021-11-08 14:04:04 -08002017}
2018
2019UBool IntlTest::assertEquals(const char* message,
2020 int64_t expected,
2021 int64_t actual) {
2022 if (expected != actual) {
2023 errln((UnicodeString)"FAIL: " + message + "; got int64 " +
2024 Int64ToUnicodeString(actual) +
2025 "; expected " + Int64ToUnicodeString(expected) );
Frank Tang1f164ee2022-11-08 12:31:27 -08002026 return false;
Frank Tang3e05d9d2021-11-08 14:04:04 -08002027 }
2028#ifdef VERBOSE_ASSERTIONS
2029 else {
2030 logln((UnicodeString)"Ok: " + message + "; got int64 " + Int64ToUnicodeString(actual));
2031 }
2032#endif
Frank Tang1f164ee2022-11-08 12:31:27 -08002033 return true;
Frank Tang3e05d9d2021-11-08 14:04:04 -08002034}
2035
2036UBool IntlTest::assertEquals(const char* message,
2037 double expected,
2038 double actual) {
2039 bool bothNaN = std::isnan(expected) && std::isnan(actual);
2040 if (expected != actual && !bothNaN) {
2041 errln((UnicodeString)"FAIL: " + message + "; got " +
2042 actual +
2043 "; expected " + expected);
Frank Tang1f164ee2022-11-08 12:31:27 -08002044 return false;
Frank Tang3e05d9d2021-11-08 14:04:04 -08002045 }
2046#ifdef VERBOSE_ASSERTIONS
2047 else {
2048 logln((UnicodeString)"Ok: " + message + "; got " + actual);
2049 }
2050#endif
Frank Tang1f164ee2022-11-08 12:31:27 -08002051 return true;
Frank Tang3e05d9d2021-11-08 14:04:04 -08002052}
2053
2054UBool IntlTest::assertEquals(const char* message,
2055 UBool expected,
2056 UBool actual) {
2057 if (expected != actual) {
2058 errln((UnicodeString)"FAIL: " + message + "; got " +
2059 toString(actual) +
2060 "; expected " + toString(expected));
Frank Tang1f164ee2022-11-08 12:31:27 -08002061 return false;
Frank Tang3e05d9d2021-11-08 14:04:04 -08002062 }
2063#ifdef VERBOSE_ASSERTIONS
2064 else {
2065 logln((UnicodeString)"Ok: " + message + "; got " + toString(actual));
2066 }
2067#endif
Frank Tang1f164ee2022-11-08 12:31:27 -08002068 return true;
Frank Tang3e05d9d2021-11-08 14:04:04 -08002069}
2070
2071
2072UBool IntlTest::assertEquals(const char* message,
2073 UErrorCode expected,
2074 UErrorCode actual) {
2075 if (expected != actual) {
2076 errln((UnicodeString)"FAIL: " + message + "; got " +
2077 u_errorName(actual) +
2078 "; expected " + u_errorName(expected));
Frank Tang1f164ee2022-11-08 12:31:27 -08002079 return false;
Frank Tang3e05d9d2021-11-08 14:04:04 -08002080 }
2081#ifdef VERBOSE_ASSERTIONS
2082 else {
2083 logln((UnicodeString)"Ok: " + message + "; got " + u_errorName(actual));
2084 }
2085#endif
Frank Tang1f164ee2022-11-08 12:31:27 -08002086 return true;
Frank Tang3e05d9d2021-11-08 14:04:04 -08002087}
2088
2089UBool IntlTest::assertEquals(const char* message,
2090 const UnicodeSet& expected,
2091 const UnicodeSet& actual) {
2092 IcuTestErrorCode status(*this, "assertEqualsUniSet");
2093 if (expected != actual) {
2094 errln((UnicodeString)"FAIL: " + message + "; got " +
2095 toString(actual, status) +
2096 "; expected " + toString(expected, status));
Frank Tang1f164ee2022-11-08 12:31:27 -08002097 return false;
Frank Tang3e05d9d2021-11-08 14:04:04 -08002098 }
2099#ifdef VERBOSE_ASSERTIONS
2100 else {
2101 logln((UnicodeString)"Ok: " + message + "; got " + toString(actual, status));
2102 }
2103#endif
Frank Tang1f164ee2022-11-08 12:31:27 -08002104 return true;
Frank Tang3e05d9d2021-11-08 14:04:04 -08002105}
2106
2107
2108#if !UCONFIG_NO_FORMATTING
2109UBool IntlTest::assertEquals(const char* message,
2110 const Formattable& expected,
2111 const Formattable& actual,
2112 UBool possibleDataError) {
2113 if (expected != actual) {
2114 if (possibleDataError) {
2115 dataerrln((UnicodeString)"FAIL: " + message + "; got " +
2116 toString(actual) +
2117 "; expected " + toString(expected));
2118 } else {
2119 errln((UnicodeString)"FAIL: " + message + "; got " +
2120 toString(actual) +
2121 "; expected " + toString(expected));
2122 }
Frank Tang1f164ee2022-11-08 12:31:27 -08002123 return false;
Frank Tang3e05d9d2021-11-08 14:04:04 -08002124 }
2125#ifdef VERBOSE_ASSERTIONS
2126 else {
2127 logln((UnicodeString)"Ok: " + message + "; got " + toString(actual));
2128 }
2129#endif
Frank Tang1f164ee2022-11-08 12:31:27 -08002130 return true;
Frank Tang3e05d9d2021-11-08 14:04:04 -08002131}
2132#endif
2133
2134std::string vectorToString(const std::vector<std::string>& strings) {
2135 std::string result = "{";
2136 bool first = true;
2137 for (auto element : strings) {
2138 if (first) {
2139 first = false;
2140 } else {
2141 result += ", ";
2142 }
2143 result += "\"";
2144 result += element;
2145 result += "\"";
2146 }
2147 result += "}";
2148 return result;
2149}
2150
2151UBool IntlTest::assertEquals(const char* message,
2152 const std::vector<std::string>& expected,
2153 const std::vector<std::string>& actual) {
2154 if (expected != actual) {
2155 std::string expectedAsString = vectorToString(expected);
2156 std::string actualAsString = vectorToString(actual);
2157 errln((UnicodeString)"FAIL: " + message +
2158 "; got " + actualAsString.c_str() +
2159 "; expected " + expectedAsString.c_str());
Frank Tang1f164ee2022-11-08 12:31:27 -08002160 return false;
Frank Tang3e05d9d2021-11-08 14:04:04 -08002161 }
2162#ifdef VERBOSE_ASSERTIONS
2163 else {
2164 logln((UnicodeString)"Ok: " + message + "; got " + vectorToString(actual).c_str());
2165 }
2166#endif
Frank Tang1f164ee2022-11-08 12:31:27 -08002167 return true;
Frank Tang3e05d9d2021-11-08 14:04:04 -08002168}
2169
2170UBool IntlTest::assertNotEquals(const char* message,
2171 int32_t expectedNot,
2172 int32_t actual) {
2173 if (expectedNot == actual) {
2174 errln((UnicodeString)("FAIL: ") + message + "; got " + actual + "=0x" + toHex(actual) +
2175 "; expected != " + expectedNot);
Frank Tang1f164ee2022-11-08 12:31:27 -08002176 return false;
Frank Tang3e05d9d2021-11-08 14:04:04 -08002177 }
2178#ifdef VERBOSE_ASSERTIONS
2179 else {
2180 logln((UnicodeString)("Ok: ") + message + "; got " + actual + "=0x" + toHex(actual) +
2181 " != " + expectedNot);
2182 }
2183#endif
Frank Tang1f164ee2022-11-08 12:31:27 -08002184 return true;
Frank Tang3e05d9d2021-11-08 14:04:04 -08002185}
2186
2187UBool IntlTest::assertEqualsNear(const char* message,
2188 double expected,
2189 double actual,
2190 double delta) {
Frank Tangd2858cb2022-04-08 20:34:12 -07002191 bool bothNaN = std::isnan(expected) && std::isnan(actual);
2192 bool bothPosInf = uprv_isPositiveInfinity(expected) && uprv_isPositiveInfinity(actual);
2193 bool bothNegInf = uprv_isNegativeInfinity(expected) && uprv_isNegativeInfinity(actual);
2194 if (bothPosInf || bothNegInf || bothNaN) {
2195 // We don't care about delta in these cases
Frank Tang1f164ee2022-11-08 12:31:27 -08002196 return true;
Frank Tangd2858cb2022-04-08 20:34:12 -07002197 }
Frank Tang3e05d9d2021-11-08 14:04:04 -08002198 if (std::isnan(delta) || std::isinf(delta)) {
2199 errln((UnicodeString)("FAIL: ") + message + "; nonsensical delta " + delta +
Frank Tangd2858cb2022-04-08 20:34:12 -07002200 " - delta may not be NaN or Inf. (Got " + actual + "; expected " + expected + ".)");
Frank Tang1f164ee2022-11-08 12:31:27 -08002201 return false;
Frank Tang3e05d9d2021-11-08 14:04:04 -08002202 }
Frank Tang3e05d9d2021-11-08 14:04:04 -08002203 double difference = std::abs(expected - actual);
Frank Tangd2858cb2022-04-08 20:34:12 -07002204 if (expected != actual && (difference > delta || std::isnan(difference))) {
Frank Tang3e05d9d2021-11-08 14:04:04 -08002205 errln((UnicodeString)("FAIL: ") + message + "; got " + actual + "; expected " + expected +
2206 "; acceptable delta " + delta);
Frank Tang1f164ee2022-11-08 12:31:27 -08002207 return false;
Frank Tang3e05d9d2021-11-08 14:04:04 -08002208 }
2209#ifdef VERBOSE_ASSERTIONS
2210 else {
2211 logln((UnicodeString)("Ok: ") + message + "; got " + actual);
2212 }
2213#endif
Frank Tang1f164ee2022-11-08 12:31:27 -08002214 return true;
Frank Tang3e05d9d2021-11-08 14:04:04 -08002215}
2216
2217static char ASSERT_BUF[256];
2218
2219static const char* extractToAssertBuf(const UnicodeString& message) {
2220 UnicodeString buf;
2221 escape(message, buf);
2222 buf.extract(0, 0x7FFFFFFF, ASSERT_BUF, sizeof(ASSERT_BUF)-1, 0);
2223 ASSERT_BUF[sizeof(ASSERT_BUF)-1] = 0;
2224 return ASSERT_BUF;
2225}
2226
2227UBool IntlTest::assertTrue(const UnicodeString& message, UBool condition, UBool quiet, UBool possibleDataError) {
2228 return assertTrue(extractToAssertBuf(message), condition, quiet, possibleDataError);
2229}
2230
2231UBool IntlTest::assertFalse(const UnicodeString& message, UBool condition, UBool quiet, UBool possibleDataError) {
2232 return assertFalse(extractToAssertBuf(message), condition, quiet, possibleDataError);
2233}
2234
2235UBool IntlTest::assertSuccess(const UnicodeString& message, UErrorCode ec) {
2236 return assertSuccess(extractToAssertBuf(message), ec);
2237}
2238
2239UBool IntlTest::assertEquals(const UnicodeString& message,
2240 const UnicodeString& expected,
2241 const UnicodeString& actual,
2242 UBool possibleDataError) {
2243 return assertEquals(extractToAssertBuf(message), expected, actual, possibleDataError);
2244}
2245
2246UBool IntlTest::assertEquals(const UnicodeString& message,
2247 const char* expected,
2248 const char* actual) {
2249 return assertEquals(extractToAssertBuf(message), expected, actual);
2250}
2251UBool IntlTest::assertEquals(const UnicodeString& message,
2252 UBool expected,
2253 UBool actual) {
2254 return assertEquals(extractToAssertBuf(message), expected, actual);
2255}
2256UBool IntlTest::assertEquals(const UnicodeString& message,
2257 int32_t expected,
2258 int32_t actual) {
2259 return assertEquals(extractToAssertBuf(message), expected, actual);
2260}
2261UBool IntlTest::assertEquals(const UnicodeString& message,
2262 int64_t expected,
2263 int64_t actual) {
2264 return assertEquals(extractToAssertBuf(message), expected, actual);
2265}
2266UBool IntlTest::assertEquals(const UnicodeString& message,
2267 double expected,
2268 double actual) {
2269 return assertEquals(extractToAssertBuf(message), expected, actual);
2270}
2271UBool IntlTest::assertEquals(const UnicodeString& message,
2272 UErrorCode expected,
2273 UErrorCode actual) {
2274 return assertEquals(extractToAssertBuf(message), expected, actual);
2275}
2276UBool IntlTest::assertEquals(const UnicodeString& message,
2277 const UnicodeSet& expected,
2278 const UnicodeSet& actual) {
2279 return assertEquals(extractToAssertBuf(message), expected, actual);
2280}
2281UBool IntlTest::assertEquals(const UnicodeString& message,
2282 const std::vector<std::string>& expected,
2283 const std::vector<std::string>& actual) {
2284 return assertEquals(extractToAssertBuf(message), expected, actual);
2285}
2286UBool IntlTest::assertNotEquals(const UnicodeString &message,
2287 int32_t expectedNot,
2288 int32_t actual) {
2289 return assertNotEquals(extractToAssertBuf(message), expectedNot, actual);
2290}
2291UBool IntlTest::assertEqualsNear(const UnicodeString& message,
2292 double expected,
2293 double actual,
2294 double delta) {
2295 return assertEqualsNear(extractToAssertBuf(message), expected, actual, delta);
2296}
2297
2298#if !UCONFIG_NO_FORMATTING
2299UBool IntlTest::assertEquals(const UnicodeString& message,
2300 const Formattable& expected,
2301 const Formattable& actual) {
2302 return assertEquals(extractToAssertBuf(message), expected, actual);
2303}
2304#endif
2305
2306void IntlTest::setProperty(const char* propline) {
2307 if (numProps < kMaxProps) {
2308 proplines[numProps] = propline;
2309 }
2310 numProps++;
2311}
2312
2313const char* IntlTest::getProperty(const char* prop) {
2314 const char* val = NULL;
2315 for (int32_t i = 0; i < numProps; i++) {
2316 int32_t plen = static_cast<int32_t>(uprv_strlen(prop));
2317 if ((int32_t)uprv_strlen(proplines[i]) > plen + 1
2318 && proplines[i][plen] == '='
2319 && uprv_strncmp(proplines[i], prop, plen) == 0) {
2320 val = &(proplines[i][plen+1]);
2321 break;
2322 }
2323 }
2324 return val;
2325}
2326
2327//-------------------------------------------------------------------------------
2328//
2329// ReadAndConvertFile Read a text data file, convert it to UChars, and
2330// return the data in one big UChar * buffer, which the caller must delete.
2331//
2332// parameters:
2333// fileName: the name of the file, with no directory part. The test data directory
2334// is assumed.
2335// ulen an out parameter, receives the actual length (in UChars) of the file data.
2336// encoding The file encoding. If the file contains a BOM, that will override the encoding
2337// specified here. The BOM, if it exists, will be stripped from the returned data.
2338// Pass NULL for the system default encoding.
2339// status
2340// returns:
2341// The file data, converted to UChar.
2342// The caller must delete this when done with
2343// delete [] theBuffer;
2344//
2345//
2346//--------------------------------------------------------------------------------
2347UChar *IntlTest::ReadAndConvertFile(const char *fileName, int &ulen, const char *encoding, UErrorCode &status) {
2348 UChar *retPtr = NULL;
2349 char *fileBuf = NULL;
2350 UConverter* conv = NULL;
2351 FILE *f = NULL;
2352
2353 ulen = 0;
2354 if (U_FAILURE(status)) {
2355 return retPtr;
2356 }
2357
2358 //
2359 // Open the file.
2360 //
2361 f = fopen(fileName, "rb");
2362 if (f == 0) {
2363 dataerrln("Error opening test data file %s\n", fileName);
2364 status = U_FILE_ACCESS_ERROR;
2365 return NULL;
2366 }
2367 //
2368 // Read it in
2369 //
2370 int fileSize;
2371 int amt_read;
2372
2373 fseek( f, 0, SEEK_END);
2374 fileSize = ftell(f);
2375 fileBuf = new char[fileSize];
2376 fseek(f, 0, SEEK_SET);
2377 amt_read = static_cast<int>(fread(fileBuf, 1, fileSize, f));
2378 if (amt_read != fileSize || fileSize <= 0) {
2379 errln("Error reading test data file.");
2380 goto cleanUpAndReturn;
2381 }
2382
2383 //
2384 // Look for a Unicode Signature (BOM) on the data just read
2385 //
2386 int32_t signatureLength;
2387 const char * fileBufC;
2388 const char* bomEncoding;
2389
2390 fileBufC = fileBuf;
2391 bomEncoding = ucnv_detectUnicodeSignature(
2392 fileBuf, fileSize, &signatureLength, &status);
2393 if(bomEncoding!=NULL ){
2394 fileBufC += signatureLength;
2395 fileSize -= signatureLength;
2396 encoding = bomEncoding;
2397 }
2398
2399 //
2400 // Open a converter to take the rule file to UTF-16
2401 //
2402 conv = ucnv_open(encoding, &status);
2403 if (U_FAILURE(status)) {
2404 goto cleanUpAndReturn;
2405 }
2406
2407 //
2408 // Convert the rules to UChar.
2409 // Preflight first to determine required buffer size.
2410 //
2411 ulen = ucnv_toUChars(conv,
2412 NULL, // dest,
2413 0, // destCapacity,
2414 fileBufC,
2415 fileSize,
2416 &status);
2417 if (status == U_BUFFER_OVERFLOW_ERROR) {
2418 // Buffer Overflow is expected from the preflight operation.
2419 status = U_ZERO_ERROR;
2420
2421 retPtr = new UChar[ulen+1];
2422 ucnv_toUChars(conv,
2423 retPtr, // dest,
2424 ulen+1,
2425 fileBufC,
2426 fileSize,
2427 &status);
2428 }
2429
2430cleanUpAndReturn:
2431 fclose(f);
2432 delete []fileBuf;
2433 ucnv_close(conv);
2434 if (U_FAILURE(status)) {
2435 errln("ucnv_toUChars: ICU Error \"%s\"\n", u_errorName(status));
2436 delete []retPtr;
2437 retPtr = 0;
2438 ulen = 0;
2439 }
2440 return retPtr;
2441}
2442
2443#if !UCONFIG_NO_BREAK_ITERATION
2444UBool LSTMDataIsBuilt() {
2445 // If we can find the LSTM data, the RBBI will use the LSTM engine.
2446 // So we skip the test which depending on the dictionary data.
2447 UErrorCode status = U_ZERO_ERROR;
2448 DeleteLSTMData(CreateLSTMDataForScript(USCRIPT_THAI, status));
2449 UBool thaiDataIsBuilt = U_SUCCESS(status);
2450 status = U_ZERO_ERROR;
2451 DeleteLSTMData(CreateLSTMDataForScript(USCRIPT_MYANMAR, status));
2452 UBool burmeseDataIsBuilt = U_SUCCESS(status);
2453 return thaiDataIsBuilt | burmeseDataIsBuilt;
2454}
2455
2456UBool IntlTest::skipLSTMTest() {
2457 return ! LSTMDataIsBuilt();
2458}
2459UBool IntlTest::skipDictionaryTest() {
2460 return LSTMDataIsBuilt();
2461}
2462#endif /* #if !UCONFIG_NO_BREAK_ITERATION */
2463
2464/*
2465 * Hey, Emacs, please set the following:
2466 *
2467 * Local Variables:
2468 * indent-tabs-mode: nil
2469 * End:
2470 *
2471 */