diff options
Diffstat (limited to 'Build/source/libs/icu/icu-4.8.1/test/intltest/intltest.cpp')
-rw-r--r-- | Build/source/libs/icu/icu-4.8.1/test/intltest/intltest.cpp | 1797 |
1 files changed, 1797 insertions, 0 deletions
diff --git a/Build/source/libs/icu/icu-4.8.1/test/intltest/intltest.cpp b/Build/source/libs/icu/icu-4.8.1/test/intltest/intltest.cpp new file mode 100644 index 00000000000..508368c70f5 --- /dev/null +++ b/Build/source/libs/icu/icu-4.8.1/test/intltest/intltest.cpp @@ -0,0 +1,1797 @@ +/******************************************************************** + * COPYRIGHT: + * Copyright (c) 1997-2010, International Business Machines Corporation and + * others. All Rights Reserved. + ********************************************************************/ + + +#include "unicode/utypes.h" + +/** + * IntlTest is a base class for tests. + */ + +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <stdarg.h> +#include <stdlib.h> + +#include "unicode/unistr.h" +#include "unicode/ures.h" +#include "unicode/smpdtfmt.h" +#include "unicode/ucnv.h" +#include "unicode/uclean.h" +#include "unicode/timezone.h" +#include "unicode/curramt.h" +#include "unicode/putil.h" + +#include "intltest.h" +#include "caltztst.h" +#include "itmajor.h" +#include "cstring.h" +#include "umutex.h" +#include "uassert.h" +#include "cmemory.h" +#include "uoptions.h" + +#include "putilimp.h" // for uprv_getRawUTCtime() +#include "unicode/locid.h" +#include "unicode/ctest.h" // for str_timeDelta + +#ifdef XP_MAC_CONSOLE +#include <console.h> +#include "Files.h" +#endif + + +static char* _testDataPath=NULL; + +// Static list of errors found +static UnicodeString errorList; + +//----------------------------------------------------------------------------- +//convenience classes to ease porting code that uses the Java +//string-concatenation operator (moved from findword test by rtg) + +// [LIU] Just to get things working +UnicodeString +UCharToUnicodeString(UChar c) +{ return UnicodeString(c); } + +// [rtg] Just to get things working +UnicodeString +operator+(const UnicodeString& left, + long num) +{ + char buffer[64]; // nos changed from 10 to 64 + char danger = 'p'; // guard against overrunning the buffer (rtg) + + sprintf(buffer, "%ld", num); + assert(danger == 'p'); + + return left + buffer; +} + +UnicodeString +operator+(const UnicodeString& left, + unsigned long num) +{ + char buffer[64]; // nos changed from 10 to 64 + char danger = 'p'; // guard against overrunning the buffer (rtg) + + sprintf(buffer, "%lu", num); + assert(danger == 'p'); + + return left + buffer; +} + +UnicodeString +Int64ToUnicodeString(int64_t num) +{ + char buffer[64]; // nos changed from 10 to 64 + char danger = 'p'; // guard against overrunning the buffer (rtg) + +#ifdef U_WINDOWS + sprintf(buffer, "%I64d", num); +#else + sprintf(buffer, "%lld", (long long)num); +#endif + assert(danger == 'p'); + + return buffer; +} + +// [LIU] Just to get things working +UnicodeString +operator+(const UnicodeString& left, + double num) +{ + char buffer[64]; // was 32, made it arbitrarily bigger (rtg) + char danger = 'p'; // guard against overrunning the buffer (rtg) + + // IEEE floating point has 52 bits of mantissa, plus one assumed bit + // 53*log(2)/log(10) = 15.95 + // so there is no need to show more than 16 digits. [alan] + + sprintf(buffer, "%.17g", num); + assert(danger == 'p'); + + return left + buffer; +} + +#if !UCONFIG_NO_FORMATTING + +/** + * Return a string display for this, without surrounding braces. + */ +UnicodeString _toString(const Formattable& f) { + UnicodeString s; + switch (f.getType()) { + case Formattable::kDate: + { + UErrorCode status = U_ZERO_ERROR; + SimpleDateFormat fmt(status); + if (U_SUCCESS(status)) { + FieldPosition pos; + fmt.format(f.getDate(), s, pos); + s.insert(0, "Date:"); + } else { + s = UnicodeString("Error creating date format]"); + } + } + break; + case Formattable::kDouble: + s = UnicodeString("double:") + f.getDouble(); + break; + case Formattable::kLong: + s = UnicodeString("long:") + f.getLong(); + break; + + case Formattable::kInt64: + s = UnicodeString("int64:") + Int64ToUnicodeString(f.getInt64()); + break; + + case Formattable::kString: + f.getString(s); + s.insert(0, "String:"); + break; + case Formattable::kArray: + { + int32_t i, n; + const Formattable* array = f.getArray(n); + s.insert(0, UnicodeString("Array:")); + UnicodeString delim(", "); + for (i=0; i<n; ++i) { + if (i > 0) { + s.append(delim); + } + s = s + _toString(array[i]); + } + } + break; + case Formattable::kObject: { + const CurrencyAmount* c = dynamic_cast<const CurrencyAmount*>(f.getObject()); + if (c != NULL) { + s = _toString(c->getNumber()) + " " + UnicodeString(c->getISOCurrency()); + } else { + s = UnicodeString("Unknown UObject"); + } + break; + } + default: + s = UnicodeString("Unknown Formattable type=") + (int32_t)f.getType(); + break; + } + return s; +} + +/** + * Originally coded this as operator+, but that makes the expression + * + char* ambiguous. - liu + */ +UnicodeString toString(const Formattable& f) { + UnicodeString s((UChar)91/*[*/); + s.append(_toString(f)); + s.append((UChar)0x5d/*]*/); + return s; +} + +#endif + +// useful when operator+ won't cooperate +UnicodeString toString(int32_t n) { + return UnicodeString() + (long)n; +} + +// stephen - cleaned up 05/05/99 +UnicodeString operator+(const UnicodeString& left, char num) +{ return left + (long)num; } +UnicodeString operator+(const UnicodeString& left, short num) +{ return left + (long)num; } +UnicodeString operator+(const UnicodeString& left, int num) +{ return left + (long)num; } +UnicodeString operator+(const UnicodeString& left, unsigned char num) +{ return left + (unsigned long)num; } +UnicodeString operator+(const UnicodeString& left, unsigned short num) +{ return left + (unsigned long)num; } +UnicodeString operator+(const UnicodeString& left, unsigned int num) +{ return left + (unsigned long)num; } +UnicodeString operator+(const UnicodeString& left, float num) +{ return left + (double)num; } + +//------------------ + +// Append a hex string to the target +UnicodeString& +IntlTest::appendHex(uint32_t number, + int32_t digits, + UnicodeString& target) +{ + static const UChar digitString[] = { + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, + 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0 + }; /* "0123456789ABCDEF" */ + + switch (digits) + { + case 8: + target += digitString[(number >> 28) & 0xF]; + case 7: + target += digitString[(number >> 24) & 0xF]; + case 6: + target += digitString[(number >> 20) & 0xF]; + case 5: + target += digitString[(number >> 16) & 0xF]; + case 4: + target += digitString[(number >> 12) & 0xF]; + case 3: + target += digitString[(number >> 8) & 0xF]; + case 2: + target += digitString[(number >> 4) & 0xF]; + case 1: + target += digitString[(number >> 0) & 0xF]; + break; + default: + target += "**"; + } + return target; +} + +static inline UBool isPrintable(UChar32 c) { + return c <= 0x7E && (c >= 0x20 || c == 9 || c == 0xA || c == 0xD); +} + +// Replace nonprintable characters with unicode escapes +UnicodeString& +IntlTest::prettify(const UnicodeString &source, + UnicodeString &target) +{ + int32_t i; + + target.remove(); + target += "\""; + + for (i = 0; i < source.length(); ) + { + UChar32 ch = source.char32At(i); + i += U16_LENGTH(ch); + + if (!isPrintable(ch)) + { + if (ch <= 0xFFFF) { + target += "\\u"; + appendHex(ch, 4, target); + } else { + target += "\\U"; + appendHex(ch, 8, target); + } + } + else + { + target += ch; + } + } + + target += "\""; + + return target; +} + +// Replace nonprintable characters with unicode escapes +UnicodeString +IntlTest::prettify(const UnicodeString &source, UBool parseBackslash) +{ + int32_t i; + UnicodeString target; + target.remove(); + target += "\""; + + for (i = 0; i < source.length();) + { + UChar32 ch = source.char32At(i); + i += U16_LENGTH(ch); + + if (!isPrintable(ch)) + { + if (parseBackslash) { + // If we are preceded by an odd number of backslashes, + // then this character has already been backslash escaped. + // Delete a backslash. + int32_t backslashCount = 0; + for (int32_t j=target.length()-1; j>=0; --j) { + if (target.charAt(j) == (UChar)92) { + ++backslashCount; + } else { + break; + } + } + if ((backslashCount % 2) == 1) { + target.truncate(target.length() - 1); + } + } + if (ch <= 0xFFFF) { + target += "\\u"; + appendHex(ch, 4, target); + } else { + target += "\\U"; + appendHex(ch, 8, target); + } + } + else + { + target += ch; + } + } + + target += "\""; + + return target; +} + +/* IntlTest::setICU_DATA - if the ICU_DATA environment variable is not already + * set, try to deduce the directory in which ICU was built, + * and set ICU_DATA to "icu/source/data" in that location. + * The intent is to allow the tests to have a good chance + * of running without requiring that the user manually set + * ICU_DATA. Common data isn't a problem, since it is + * picked up via a static (build time) reference, but the + * tests dynamically load some data. + */ +void IntlTest::setICU_DATA() { + const char *original_ICU_DATA = getenv("ICU_DATA"); + + if (original_ICU_DATA != NULL && *original_ICU_DATA != 0) { + /* If the user set ICU_DATA, don't second-guess the person. */ + return; + } + + // U_TOPBUILDDIR is set by the makefiles on UNIXes when building cintltst and intltst + // to point to the top of the build hierarchy, which may or + // may not be the same as the source directory, depending on + // the configure options used. At any rate, + // set the data path to the built data from this directory. + // The value is complete with quotes, so it can be used + // as-is as a string constant. + +#if defined (U_TOPBUILDDIR) + { + static char env_string[] = U_TOPBUILDDIR "data" U_FILE_SEP_STRING "out" U_FILE_SEP_STRING; + u_setDataDirectory(env_string); + return; + } + +#else + // Use #else so we don't get compiler warnings due to the return above. + + /* On Windows, the file name obtained from __FILE__ includes a full path. + * This file is "wherever\icu\source\test\cintltst\cintltst.c" + * Change to "wherever\icu\source\data" + */ + { + char p[sizeof(__FILE__) + 10]; + char *pBackSlash; + int i; + + strcpy(p, __FILE__); + /* We want to back over three '\' chars. */ + /* Only Windows should end up here, so looking for '\' is safe. */ + for (i=1; i<=3; i++) { + pBackSlash = strrchr(p, U_FILE_SEP_CHAR); + if (pBackSlash != NULL) { + *pBackSlash = 0; /* Truncate the string at the '\' */ + } + } + + if (pBackSlash != NULL) { + /* We found and truncated three names from the path. + * Now append "source\data" and set the environment + */ + strcpy(pBackSlash, U_FILE_SEP_STRING "data" U_FILE_SEP_STRING "out" U_FILE_SEP_STRING); + u_setDataDirectory(p); /* p is "ICU_DATA=wherever\icu\source\data" */ + return; + } + else { + /* __FILE__ on MSVC7 does not contain the directory */ + u_setDataDirectory(".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING "data" U_FILE_SEP_STRING "out" U_FILE_SEP_STRING); + return; + } + } +#endif + + /* No location for the data dir was identifiable. + * Add other fallbacks for the test data location here if the need arises + */ +} + + +//-------------------------------------------------------------------------------------- + +static const int32_t indentLevel_offset = 3; +static const char delim = '/'; + +IntlTest* IntlTest::gTest = NULL; + +static int32_t execCount = 0; + +void it_log( UnicodeString message ) +{ + if (IntlTest::gTest) + IntlTest::gTest->log( message ); +} + +void it_logln( UnicodeString message ) +{ + if (IntlTest::gTest) + IntlTest::gTest->logln( message ); +} + +void it_logln( void ) +{ + if (IntlTest::gTest) + IntlTest::gTest->logln(); +} + +void it_info( UnicodeString message ) +{ + if (IntlTest::gTest) + IntlTest::gTest->info( message ); +} + +void it_infoln( UnicodeString message ) +{ + if (IntlTest::gTest) + IntlTest::gTest->infoln( message ); +} + +void it_infoln( void ) +{ + if (IntlTest::gTest) + IntlTest::gTest->infoln(); +} + +void it_err() +{ + if (IntlTest::gTest) + IntlTest::gTest->err(); +} + +void it_err( UnicodeString message ) +{ + if (IntlTest::gTest) + IntlTest::gTest->err( message ); +} + +void it_errln( UnicodeString message ) +{ + if (IntlTest::gTest) + IntlTest::gTest->errln( message ); +} + +void it_dataerr( UnicodeString message ) +{ + if (IntlTest::gTest) + IntlTest::gTest->dataerr( message ); +} + +void it_dataerrln( UnicodeString message ) +{ + if (IntlTest::gTest) + IntlTest::gTest->dataerrln( message ); +} + +IntlTest::IntlTest() +{ + caller = NULL; + testPath = NULL; + LL_linestart = TRUE; + errorCount = 0; + dataErrorCount = 0; + verbose = FALSE; + no_err_msg = FALSE; + warn_on_missing_data = FALSE; + quick = FALSE; + leaks = FALSE; + threadCount = 1; + testoutfp = stdout; + LL_indentlevel = indentLevel_offset; + numProps = 0; + strcpy(basePath, "/"); +} + +void IntlTest::setCaller( IntlTest* callingTest ) +{ + caller = callingTest; + if (caller) { + warn_on_missing_data = caller->warn_on_missing_data; + verbose = caller->verbose; + no_err_msg = caller->no_err_msg; + quick = caller->quick; + testoutfp = caller->testoutfp; + LL_indentlevel = caller->LL_indentlevel + indentLevel_offset; + numProps = caller->numProps; + for (int32_t i = 0; i < numProps; i++) { + proplines[i] = caller->proplines[i]; + } + } +} + +UBool IntlTest::callTest( IntlTest& testToBeCalled, char* par ) +{ + execCount--; // correct a previously assumed test-exec, as this only calls a subtest + testToBeCalled.setCaller( this ); + strcpy(testToBeCalled.basePath, this->basePath ); + UBool result = testToBeCalled.runTest( testPath, par, testToBeCalled.basePath ); + strcpy(testToBeCalled.basePath, this->basePath ); // reset it. + return result; +} + +void IntlTest::setPath( char* pathVal ) +{ + this->testPath = pathVal; +} + +UBool IntlTest::setVerbose( UBool verboseVal ) +{ + UBool rval = this->verbose; + this->verbose = verboseVal; + return rval; +} + +UBool IntlTest::setWarnOnMissingData( UBool warn_on_missing_dataVal ) +{ + UBool rval = this->warn_on_missing_data; + this->warn_on_missing_data = warn_on_missing_dataVal; + return rval; +} + +UBool IntlTest::setNoErrMsg( UBool no_err_msgVal ) +{ + UBool rval = this->no_err_msg; + this->no_err_msg = no_err_msgVal; + return rval; +} + +UBool IntlTest::setQuick( UBool quickVal ) +{ + UBool rval = this->quick; + this->quick = quickVal; + return rval; +} + +UBool IntlTest::setLeaks( UBool leaksVal ) +{ + UBool rval = this->leaks; + this->leaks = leaksVal; + return rval; +} + +int32_t IntlTest::setThreadCount( int32_t count ) +{ + int32_t rval = this->threadCount; + this->threadCount = count; + return rval; +} + +int32_t IntlTest::getErrors( void ) +{ + return errorCount; +} + +int32_t IntlTest::getDataErrors( void ) +{ + return dataErrorCount; +} + +UBool IntlTest::runTest( char* name, char* par, char *baseName ) +{ + UBool rval; + char* pos = NULL; + + char* baseNameBuffer = NULL; + + if(baseName == NULL) { + baseNameBuffer = (char*)malloc(1024); + baseName=baseNameBuffer; + strcpy(baseName, "/"); + } + + if (name) + pos = strchr( name, delim ); // check if name contains path (by looking for '/') + if (pos) { + testPath = pos+1; // store subpath for calling subtest + *pos = 0; // split into two strings + }else{ + testPath = NULL; + } + + if (!name || (name[0] == 0) || (strcmp(name, "*") == 0)) { + rval = runTestLoop( NULL, par, baseName ); + + }else if (strcmp( name, "LIST" ) == 0) { + this->usage(); + rval = TRUE; + + }else{ + rval = runTestLoop( name, par, baseName ); + } + + if (pos) + *pos = delim; // restore original value at pos + if(baseNameBuffer!=NULL) { + free(baseNameBuffer); + } + return rval; +} + +// call individual tests, to be overriden to call implementations +void IntlTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* par ) +{ + // to be overriden by a method like: + /* + switch (index) { + case 0: name = "First Test"; if (exec) FirstTest( par ); break; + case 1: name = "Second Test"; if (exec) SecondTest( par ); break; + default: name = ""; break; + } + */ + this->errln("*** runIndexedTest needs to be overriden! ***"); + name = ""; exec = exec; index = index; par = par; +} + + +UBool IntlTest::runTestLoop( char* testname, char* par, char *baseName ) +{ + int32_t index = 0; + const char* name; + UBool run_this_test; + int32_t lastErrorCount; + UBool rval = FALSE; + UBool lastTestFailed; + + if(baseName == NULL) { + printf("ERROR: baseName can't be null.\n"); + return FALSE; + } else { + if ((char *)this->basePath != baseName) { + strcpy(this->basePath, baseName); + } + } + + char * saveBaseLoc = baseName+strlen(baseName); + + IntlTest* saveTest = gTest; + gTest = this; + do { + this->runIndexedTest( index, FALSE, name, par ); + if (strcmp(name,"skip") == 0) { + run_this_test = FALSE; + } else { + if (!name || (name[0] == 0)) + break; + if (!testname) { + run_this_test = TRUE; + }else{ + run_this_test = (UBool) (strcmp( name, testname ) == 0); + } + } + if (run_this_test) { + lastErrorCount = errorCount; + execCount++; + char msg[256]; + sprintf(msg, "%s {", name); + LL_message(msg, TRUE); + UDate timeStart = uprv_getRawUTCtime(); + strcpy(saveBaseLoc,name); + strcat(saveBaseLoc,"/"); + + this->runIndexedTest( index, TRUE, name, par ); + + UDate timeStop = uprv_getRawUTCtime(); + rval = TRUE; // at least one test has been called + char secs[256]; + sprintf(secs, "%f", (timeStop-timeStart)/1000.0); + + + strcpy(saveBaseLoc,name); + + + ctest_xml_testcase(baseName, name, secs, (lastErrorCount!=errorCount)?"err":NULL); + + + saveBaseLoc[0]=0; /* reset path */ + + if (lastErrorCount == errorCount) { + sprintf( msg, " } OK: %s ", name ); + str_timeDelta(msg+strlen(msg),timeStop-timeStart); + lastTestFailed = FALSE; + }else{ + sprintf(msg, " } ERRORS (%li) in %s", (long)(errorCount-lastErrorCount), name); + str_timeDelta(msg+strlen(msg),timeStop-timeStart); + + for(int i=0;i<LL_indentlevel;i++) { + errorList += " "; + } + errorList += name; + errorList += "\n"; + lastTestFailed = TRUE; + } + LL_indentlevel -= 3; + if (lastTestFailed) { + LL_message( "", TRUE); + } + LL_message( msg, TRUE); + if (lastTestFailed) { + LL_message( "", TRUE); + } + LL_indentlevel += 3; + } + index++; + }while(name); + + *saveBaseLoc = 0; + + gTest = saveTest; + return rval; +} + + +/** +* Adds given string to the log if we are in verbose mode. +*/ +void IntlTest::log( const UnicodeString &message ) +{ + if( verbose ) { + LL_message( message, FALSE ); + } +} + +/** +* Adds given string to the log if we are in verbose mode. Adds a new line to +* the given message. +*/ +void IntlTest::logln( const UnicodeString &message ) +{ + if( verbose ) { + LL_message( message, TRUE ); + } +} + +void IntlTest::logln( void ) +{ + if( verbose ) { + LL_message( "", TRUE ); + } +} + +/** +* Unconditionally adds given string to the log. +*/ +void IntlTest::info( const UnicodeString &message ) +{ + LL_message( message, FALSE ); +} + +/** +* Unconditionally adds given string to the log. Adds a new line to +* the given message. +*/ +void IntlTest::infoln( const UnicodeString &message ) +{ + LL_message( message, TRUE ); +} + +void IntlTest::infoln( void ) +{ + LL_message( "", TRUE ); +} + +int32_t IntlTest::IncErrorCount( void ) +{ + errorCount++; + if (caller) caller->IncErrorCount(); + return errorCount; +} + +int32_t IntlTest::IncDataErrorCount( void ) +{ + dataErrorCount++; + if (caller) caller->IncDataErrorCount(); + return dataErrorCount; +} + +void IntlTest::err() +{ + IncErrorCount(); +} + +void IntlTest::err( const UnicodeString &message ) +{ + IncErrorCount(); + if (!no_err_msg) LL_message( message, FALSE ); +} + +void IntlTest::errln( const UnicodeString &message ) +{ + IncErrorCount(); + if (!no_err_msg) LL_message( message, TRUE ); +} + +void IntlTest::dataerr( const UnicodeString &message ) +{ + IncDataErrorCount(); + + if (!warn_on_missing_data) { + IncErrorCount(); + } + + if (!no_err_msg) LL_message( message, FALSE ); +} + +void IntlTest::dataerrln( const UnicodeString &message ) +{ + IncDataErrorCount(); + UnicodeString msg; + if (!warn_on_missing_data) { + IncErrorCount(); + msg = message; + } else { + msg = UnicodeString("[DATA] " + message); + } + + if (!no_err_msg) LL_message( msg + " - (Are you missing data?)", TRUE ); +} + +void IntlTest::errcheckln(UErrorCode status, const UnicodeString &message ) { + if (status == U_FILE_ACCESS_ERROR || status == U_MISSING_RESOURCE_ERROR) { + dataerrln(message); + } else { + errln(message); + } +} + +/* convenience functions that include sprintf formatting */ +void IntlTest::log(const char *fmt, ...) +{ + char buffer[4000]; + va_list ap; + + va_start(ap, fmt); + /* sprintf it just to make sure that the information is valid */ + vsprintf(buffer, fmt, ap); + va_end(ap); + if( verbose ) { + log(UnicodeString(buffer, "")); + } +} + +void IntlTest::logln(const char *fmt, ...) +{ + char buffer[4000]; + va_list ap; + + va_start(ap, fmt); + /* sprintf it just to make sure that the information is valid */ + vsprintf(buffer, fmt, ap); + va_end(ap); + if( verbose ) { + logln(UnicodeString(buffer, "")); + } +} + +/* convenience functions that include sprintf formatting */ +void IntlTest::info(const char *fmt, ...) +{ + char buffer[4000]; + va_list ap; + + va_start(ap, fmt); + /* sprintf it just to make sure that the information is valid */ + vsprintf(buffer, fmt, ap); + va_end(ap); + info(UnicodeString(buffer, "")); +} + +void IntlTest::infoln(const char *fmt, ...) +{ + char buffer[4000]; + va_list ap; + + va_start(ap, fmt); + /* sprintf it just to make sure that the information is valid */ + vsprintf(buffer, fmt, ap); + va_end(ap); + infoln(UnicodeString(buffer, "")); +} + +void IntlTest::err(const char *fmt, ...) +{ + char buffer[4000]; + va_list ap; + + va_start(ap, fmt); + vsprintf(buffer, fmt, ap); + va_end(ap); + err(UnicodeString(buffer, "")); +} + +void IntlTest::errln(const char *fmt, ...) +{ + char buffer[4000]; + va_list ap; + + va_start(ap, fmt); + vsprintf(buffer, fmt, ap); + va_end(ap); + errln(UnicodeString(buffer, "")); +} + +void IntlTest::dataerrln(const char *fmt, ...) +{ + char buffer[4000]; + va_list ap; + + va_start(ap, fmt); + vsprintf(buffer, fmt, ap); + va_end(ap); + dataerrln(UnicodeString(buffer, "")); +} + +void IntlTest::errcheckln(UErrorCode status, const char *fmt, ...) +{ + char buffer[4000]; + va_list ap; + + va_start(ap, fmt); + vsprintf(buffer, fmt, ap); + va_end(ap); + + if (status == U_FILE_ACCESS_ERROR || status == U_MISSING_RESOURCE_ERROR) { + dataerrln(UnicodeString(buffer, "")); + } else { + errln(UnicodeString(buffer, "")); + } +} + +void IntlTest::printErrors() +{ + IntlTest::LL_message(errorList, TRUE); +} + +void IntlTest::LL_message( UnicodeString message, UBool newline ) +{ + // string that starts with a LineFeed character and continues + // with spaces according to the current indentation + static const UChar indentUChars[] = { + '\n', + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32 + }; + UnicodeString indent(FALSE, indentUChars, 1 + LL_indentlevel); + + char buffer[10000]; + int32_t length; + + // stream out the indentation string first if necessary + length = indent.extract(1, indent.length(), buffer, sizeof(buffer)); + if (length > 0) { + fwrite(buffer, sizeof(*buffer), length, (FILE *)testoutfp); + } + + // replace each LineFeed by the indentation string + message.findAndReplace(UnicodeString((UChar)'\n'), indent); + + // stream out the message + length = message.extract(0, message.length(), buffer, sizeof(buffer)); + if (length > 0) { + length = length > 10000 ? 10000 : length; + fwrite(buffer, sizeof(*buffer), length, (FILE *)testoutfp); + } + + if (newline) { + char newLine = '\n'; + fwrite(&newLine, sizeof(newLine), 1, (FILE *)testoutfp); + } + + // A newline usually flushes the buffer, but + // flush the message just in case of a core dump. + fflush((FILE *)testoutfp); +} + +/** +* Print a usage message for this test class. +*/ +void IntlTest::usage( void ) +{ + UBool save_verbose = setVerbose( TRUE ); + logln("Test names:"); + logln("-----------"); + + int32_t index = 0; + const char* name = NULL; + do{ + this->runIndexedTest( index, FALSE, name ); + if (!name) break; + logln(name); + index++; + }while (name && (name[0] != 0)); + setVerbose( save_verbose ); +} + + +// memory leak reporting software will be able to take advantage of the testsuite +// being run a second time local to a specific method in order to report only actual leaks +UBool +IntlTest::run_phase2( char* name, char* par ) // supports reporting memory leaks +{ + UnicodeString* strLeak = new UnicodeString("forced leak"); // for verifying purify filter + strLeak->append(" for verifying purify filter"); + return this->runTest( name, par ); +} + + +#if UCONFIG_NO_LEGACY_CONVERSION +# define TRY_CNV_1 "iso-8859-1" +# define TRY_CNV_2 "ibm-1208" +#else +# define TRY_CNV_1 "iso-8859-7" +# define TRY_CNV_2 "sjis" +#endif + +int +main(int argc, char* argv[]) +{ + UBool syntax = FALSE; + UBool all = FALSE; + UBool verbose = FALSE; + UBool no_err_msg = FALSE; + UBool quick = TRUE; + UBool name = FALSE; + UBool leaks = FALSE; + UBool warnOnMissingData = FALSE; + UBool defaultDataFound = FALSE; + int32_t threadCount = 1; + UErrorCode errorCode = U_ZERO_ERROR; + UConverter *cnv = NULL; + const char *warnOrErr = "Failure"; + UDate startTime, endTime; + int32_t diffTime; + const char *props[IntlTest::kMaxProps]; + int32_t nProps = 0; + + U_MAIN_INIT_ARGS(argc, argv); + + startTime = uprv_getRawUTCtime(); + + for (int i = 1; i < argc; ++i) { + if (argv[i][0] == '-') { + const char* str = argv[i] + 1; + if (strcmp("verbose", str) == 0 || + strcmp("v", str) == 0) + verbose = TRUE; + else if (strcmp("noerrormsg", str) == 0 || + strcmp("n", str) == 0) + no_err_msg = TRUE; + else if (strcmp("exhaustive", str) == 0 || + strcmp("e", str) == 0) + quick = FALSE; + else if (strcmp("all", str) == 0 || + strcmp("a", str) == 0) + all = TRUE; + else if (strcmp("leaks", str) == 0 || + strcmp("l", str) == 0) + leaks = TRUE; + else if (strcmp("x", str)==0) { + if(++i>=argc) { + printf("* Error: '-x' option requires an argument. usage: '-x outfile.xml'.\n"); + syntax = TRUE; + } + if(ctest_xml_setFileName(argv[i])) { /* set the name */ + return 1; /* error */ + } + } else if (strcmp("w", str) == 0) { + warnOnMissingData = TRUE; + warnOrErr = "WARNING"; + } + else if (strncmp("threads:", str, 8) == 0) { + threadCount = atoi(str + 8); + } + else if (strncmp("prop:", str, 5) == 0) { + if (nProps < IntlTest::kMaxProps) { + props[nProps] = str + 5; + } + nProps++; + } + else { + syntax = TRUE; + } + }else{ + name = TRUE; + } + } + + if (!all && !name) { + all = TRUE; + } else if (all && name) { + syntax = TRUE; + } + + if (syntax) { + fprintf(stdout, + "### Syntax:\n" + "### IntlTest [-option1 -option2 ...] [testname1 testname2 ...] \n" + "### \n" + "### Options are: verbose (v), all (a), noerrormsg (n), \n" + "### exhaustive (e), leaks (l), -x xmlfile.xml, prop:<propery>=<value>, \n" + "### threads:<threadCount> (Mulithreading must first be \n" + "### enabled otherwise this will be ignored. \n" + "### The default thread count is 1.),\n" + "### (Specify either -all (shortcut -a) or a test name). \n" + "### -all will run all of the tests.\n" + "### \n" + "### To get a list of the test names type: intltest LIST \n" + "### To run just the utility tests type: intltest utility \n" + "### \n" + "### Test names can be nested using slashes (\"testA/subtest1\") \n" + "### For example to list the utility tests type: intltest utility/LIST \n" + "### To run just the Locale test type: intltest utility/LocaleTest \n" + "### \n" + "### A parameter can be specified for a test by appending '@' and the value \n" + "### to the testname. \n\n"); + return 1; + } + + if (nProps > IntlTest::kMaxProps) { + fprintf(stdout, "### Too many properties. Exiting.\n"); + } + + UBool all_tests_exist = TRUE; + MajorTestLevel major; + major.setVerbose( verbose ); + major.setNoErrMsg( no_err_msg ); + major.setQuick( quick ); + major.setLeaks( leaks ); + major.setThreadCount( threadCount ); + major.setWarnOnMissingData( warnOnMissingData ); + for (int32_t i = 0; i < nProps; i++) { + major.setProperty(props[i]); + } + + + fprintf(stdout, "-----------------------------------------------\n"); + fprintf(stdout, " IntlTest (C++) Test Suite for \n"); + fprintf(stdout, " International Components for Unicode %s\n", U_ICU_VERSION); + + + { + const char *charsetFamily = "Unknown"; + int32_t voidSize = (int32_t)sizeof(void*); + int32_t bits = voidSize * 8; + if(U_CHARSET_FAMILY==U_ASCII_FAMILY) { + charsetFamily="ASCII"; + } else if(U_CHARSET_FAMILY==U_EBCDIC_FAMILY) { + charsetFamily="EBCDIC"; + } + fprintf(stdout, + " Bits: %d, Byte order: %s, Chars: %s\n", + bits, U_IS_BIG_ENDIAN?"Big endian":"Little endian", + charsetFamily); + } + fprintf(stdout, "-----------------------------------------------\n"); + fprintf(stdout, " Options: \n"); + fprintf(stdout, " all (a) : %s\n", (all? "On" : "Off")); + fprintf(stdout, " Verbose (v) : %s\n", (verbose? "On" : "Off")); + fprintf(stdout, " No error messages (n) : %s\n", (no_err_msg? "On" : "Off")); + fprintf(stdout, " Exhaustive (e) : %s\n", (!quick? "On" : "Off")); + fprintf(stdout, " Leaks (l) : %s\n", (leaks? "On" : "Off")); + fprintf(stdout, " Warn on missing data (w) : %s\n", (warnOnMissingData? "On" : "Off")); +#if (ICU_USE_THREADS==0) + fprintf(stdout, " Threads : Disabled\n"); +#else + fprintf(stdout, " Threads : %d\n", threadCount); +#endif + for (int32_t i = 0; i < nProps; i++) { + fprintf(stdout, " Custom property (prop:) : %s\n", props[i]); + } + fprintf(stdout, "-----------------------------------------------\n"); + + /* Check whether ICU will initialize without forcing the build data directory into + * the ICU_DATA path. Success here means either the data dll contains data, or that + * this test program was run with ICU_DATA set externally. Failure of this check + * is normal when ICU data is not packaged into a shared library. + * + * Whether or not this test succeeds, we want to cleanup and reinitialize + * with a data path so that data loading from individual files can be tested. + */ + u_init(&errorCode); + if (U_FAILURE(errorCode)) { + fprintf(stderr, + "#### Note: ICU Init without build-specific setDataDirectory() failed.\n"); + defaultDataFound = FALSE; + } + else { + defaultDataFound = TRUE; + } + u_cleanup(); + errorCode = U_ZERO_ERROR; + + /* Initialize ICU */ + if (!defaultDataFound) { + IntlTest::setICU_DATA(); // Must set data directory before u_init() is called. + } + u_init(&errorCode); + if (U_FAILURE(errorCode)) { + fprintf(stderr, + "#### ERROR! %s: u_init() failed with status = \"%s\".\n" + "*** Check the ICU_DATA environment variable and \n" + "*** check that the data files are present.\n", argv[0], u_errorName(errorCode)); + if(warnOnMissingData == 0) { + fprintf(stderr, "*** Exiting. Use the '-w' option if data files were\n*** purposely removed, to continue test anyway.\n"); + u_cleanup(); + return 1; + } + } + + + // initial check for the default converter + errorCode = U_ZERO_ERROR; + cnv = ucnv_open(0, &errorCode); + if(cnv != 0) { + // ok + ucnv_close(cnv); + } else { + fprintf(stdout, + "*** %s! The default converter [%s] cannot be opened.\n" + "*** Check the ICU_DATA environment variable and\n" + "*** check that the data files are present.\n", + warnOrErr, ucnv_getDefaultName()); + if(!warnOnMissingData) { + fprintf(stdout, "*** Exiting. Use the '-w' option if data files were\n*** purposely removed, to continue test anyway.\n"); + return 1; + } + } + + // try more data + cnv = ucnv_open(TRY_CNV_2, &errorCode); + if(cnv != 0) { + // ok + ucnv_close(cnv); + } else { + fprintf(stdout, + "*** %s! The converter for " TRY_CNV_2 " cannot be opened.\n" + "*** Check the ICU_DATA environment variable and \n" + "*** check that the data files are present.\n", warnOrErr); + if(!warnOnMissingData) { + fprintf(stdout, "*** Exiting. Use the '-w' option if data files were\n*** purposely removed, to continue test anyway.\n"); + return 1; + } + } + + UResourceBundle *rb = ures_open(0, "en", &errorCode); + ures_close(rb); + if(U_FAILURE(errorCode)) { + fprintf(stdout, + "*** %s! The \"en\" locale resource bundle cannot be opened.\n" + "*** Check the ICU_DATA environment variable and \n" + "*** check that the data files are present.\n", warnOrErr); + if(!warnOnMissingData) { + fprintf(stdout, "*** Exiting. Use the '-w' option if data files were\n*** purposely removed, to continue test anyway.\n"); + return 1; + } + } + + Locale originalLocale; // Save the default locale for comparison later on. + + if(ctest_xml_init("intltest")) + return 1; + + + /* TODO: Add option to call u_cleanup and rerun tests. */ + if (all) { + major.runTest(); + if (leaks) { + major.run_phase2( NULL, NULL ); + } + }else{ + for (int i = 1; i < argc; ++i) { + if (argv[i][0] != '-') { + char* name = argv[i]; + fprintf(stdout, "\n=== Handling test: %s: ===\n", name); + + char baseName[1024]; + sprintf(baseName, "/%s/", name); + + char* parameter = strchr( name, '@' ); + if (parameter) { + *parameter = 0; + parameter += 1; + } + execCount = 0; + UBool res = major.runTest( name, parameter, baseName ); + if (leaks && res) { + major.run_phase2( name, parameter ); + } + if (!res || (execCount <= 0)) { + fprintf(stdout, "\n---ERROR: Test doesn't exist: %s!\n", name); + all_tests_exist = FALSE; + } + } else if(!strcmp(argv[i],"-x")) { + i++; + } + } + } + + +#if !UCONFIG_NO_FORMATTING + CalendarTimeZoneTest::cleanup(); +#endif + + free(_testDataPath); + _testDataPath = 0; + + Locale lastDefaultLocale; + if (originalLocale != lastDefaultLocale) { + major.errln("FAILURE: A test changed the default locale without resetting it."); + } + + fprintf(stdout, "\n--------------------------------------\n"); + if (major.getErrors() == 0) { + /* Call it twice to make sure that the defaults were reset. */ + /* Call it before the OK message to verify proper cleanup. */ + u_cleanup(); + u_cleanup(); + + fprintf(stdout, "OK: All tests passed without error.\n"); + + if (major.getDataErrors() != 0) { + fprintf(stdout, "\t*WARNING* some data-loading errors were ignored by the -w option.\n"); + } + }else{ + fprintf(stdout, "Errors in total: %ld.\n", (long)major.getErrors()); + major.printErrors(); + + + if (major.getDataErrors() != 0) { + fprintf(stdout, "\t*Note* some errors are data-loading related. If the data used is not the \n" + "\tstock ICU data (i.e some have been added or removed), consider using\n" + "\tthe '-w' option to turn these errors into warnings.\n"); + } + + /* Call afterwards to display errors. */ + u_cleanup(); + } + + fprintf(stdout, "--------------------------------------\n"); + + if (execCount <= 0) { + fprintf(stdout, "***** Not all called tests actually exist! *****\n"); + } + endTime = uprv_getRawUTCtime(); + diffTime = (int32_t)(endTime - startTime); + printf("Elapsed Time: %02d:%02d:%02d.%03d\n", + (int)((diffTime%U_MILLIS_PER_DAY)/U_MILLIS_PER_HOUR), + (int)((diffTime%U_MILLIS_PER_HOUR)/U_MILLIS_PER_MINUTE), + (int)((diffTime%U_MILLIS_PER_MINUTE)/U_MILLIS_PER_SECOND), + (int)(diffTime%U_MILLIS_PER_SECOND)); + + if(ctest_xml_fini()) + return 1; + + return major.getErrors(); +} + +const char* IntlTest::loadTestData(UErrorCode& err){ + if( _testDataPath == NULL){ + const char* directory=NULL; + UResourceBundle* test =NULL; + char* tdpath=NULL; + const char* tdrelativepath; + +#if defined (U_TOPBUILDDIR) + tdrelativepath = "test"U_FILE_SEP_STRING"testdata"U_FILE_SEP_STRING"out"U_FILE_SEP_STRING; + directory = U_TOPBUILDDIR; +#else + tdrelativepath = ".."U_FILE_SEP_STRING"test"U_FILE_SEP_STRING"testdata"U_FILE_SEP_STRING"out"U_FILE_SEP_STRING; + directory = pathToDataDirectory(); +#endif + + tdpath = (char*) malloc(sizeof(char) *(( strlen(directory) * strlen(tdrelativepath)) + 100)); + + + /* u_getDataDirectory shoul return \source\data ... set the + * directory to ..\source\data\..\test\testdata\out\testdata + */ + strcpy(tdpath, directory); + strcat(tdpath, tdrelativepath); + strcat(tdpath,"testdata"); + + test=ures_open(tdpath, "testtypes", &err); + + if(U_FAILURE(err)){ + err = U_FILE_ACCESS_ERROR; + it_dataerrln((UnicodeString)"Could not load testtypes.res in testdata bundle with path " + tdpath + (UnicodeString)" - " + u_errorName(err)); + return ""; + } + ures_close(test); + _testDataPath = tdpath; + return _testDataPath; + } + return _testDataPath; +} + +const char* IntlTest::getTestDataPath(UErrorCode& err) { + return loadTestData(err); +} + +/* Returns the path to icu/source/test/testdata/ */ +const char *IntlTest::getSourceTestData(UErrorCode& /*err*/) { + const char *srcDataDir = NULL; +#ifdef U_TOPSRCDIR + srcDataDir = U_TOPSRCDIR U_FILE_SEP_STRING"test"U_FILE_SEP_STRING"testdata"U_FILE_SEP_STRING; +#else + srcDataDir = ".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING"test"U_FILE_SEP_STRING"testdata"U_FILE_SEP_STRING; + FILE *f = fopen(".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING"test"U_FILE_SEP_STRING"testdata"U_FILE_SEP_STRING"rbbitst.txt", "r"); + if (f) { + /* We're in icu/source/test/intltest/ */ + fclose(f); + } + else { + /* We're in icu/source/test/intltest/Platform/(Debug|Release) */ + 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; + } +#endif + return srcDataDir; +} + +const char* IntlTest::fgDataDir = NULL; + +/* returns the path to icu/source/data */ +const char * IntlTest::pathToDataDirectory() +{ + + if(fgDataDir != NULL) { + return fgDataDir; + } + + /* U_TOPSRCDIR is set by the makefiles on UNIXes when building cintltst and intltst + // to point to the top of the build hierarchy, which may or + // may not be the same as the source directory, depending on + // the configure options used. At any rate, + // set the data path to the built data from this directory. + // The value is complete with quotes, so it can be used + // as-is as a string constant. + */ +#if defined (U_TOPSRCDIR) + { + fgDataDir = U_TOPSRCDIR U_FILE_SEP_STRING "data" U_FILE_SEP_STRING; + } +#else + + /* On Windows, the file name obtained from __FILE__ includes a full path. + * This file is "wherever\icu\source\test\cintltst\cintltst.c" + * Change to "wherever\icu\source\data" + */ + { + static char p[sizeof(__FILE__) + 10]; + char *pBackSlash; + int i; + + strcpy(p, __FILE__); + /* We want to back over three '\' chars. */ + /* Only Windows should end up here, so looking for '\' is safe. */ + for (i=1; i<=3; i++) { + pBackSlash = strrchr(p, U_FILE_SEP_CHAR); + if (pBackSlash != NULL) { + *pBackSlash = 0; /* Truncate the string at the '\' */ + } + } + + if (pBackSlash != NULL) { + /* We found and truncated three names from the path. + * Now append "source\data" and set the environment + */ + strcpy(pBackSlash, U_FILE_SEP_STRING "data" U_FILE_SEP_STRING ); + fgDataDir = p; + } + else { + /* __FILE__ on MSVC7 does not contain the directory */ + FILE *file = fopen(".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING "data" U_FILE_SEP_STRING "Makefile.in", "r"); + if (file) { + fclose(file); + fgDataDir = ".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING "data" U_FILE_SEP_STRING; + } + else { + fgDataDir = ".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING "data" U_FILE_SEP_STRING; + } + } + } +#endif + + return fgDataDir; + +} + +/* + * This is a variant of cintltst/ccolltst.c:CharsToUChars(). + * It converts an invariant-character string into a UnicodeString, with + * unescaping \u sequences. + */ +UnicodeString CharsToUnicodeString(const char* chars){ + return UnicodeString(chars, -1, US_INV).unescape(); +} + +UnicodeString ctou(const char* chars) { + return CharsToUnicodeString(chars); +} + +#define RAND_M (714025) +#define RAND_IA (1366) +#define RAND_IC (150889) + +static int32_t RAND_SEED; + +/** + * Returns a uniform random value x, with 0.0 <= x < 1.0. Use + * with care: Does not return all possible values; returns one of + * 714,025 values, uniformly spaced. However, the period is + * effectively infinite. See: Numerical Recipes, section 7.1. + * + * @param seedp pointer to seed. Set *seedp to any negative value + * to restart the sequence. + */ +float IntlTest::random(int32_t* seedp) { + static int32_t iy, ir[98]; + static UBool first=TRUE; + int32_t j; + if (*seedp < 0 || first) { + first = FALSE; + if ((*seedp=(RAND_IC-(*seedp)) % RAND_M) < 0) *seedp = -(*seedp); + for (j=1;j<=97;++j) { + *seedp=(RAND_IA*(*seedp)+RAND_IC) % RAND_M; + ir[j]=(*seedp); + } + *seedp=(RAND_IA*(*seedp)+RAND_IC) % RAND_M; + iy=(*seedp); + } + j=(int32_t)(1 + 97.0*iy/RAND_M); + U_ASSERT(j>=1 && j<=97); + iy=ir[j]; + *seedp=(RAND_IA*(*seedp)+RAND_IC) % RAND_M; + ir[j]=(*seedp); + return (float) iy/RAND_M; +} + +/** + * Convenience method using a global seed. + */ +float IntlTest::random() { + return random(&RAND_SEED); +} + +static inline UChar toHex(int32_t i) { + return (UChar)(i + (i < 10 ? 0x30 : (0x41 - 10))); +} + +static UnicodeString& escape(const UnicodeString& s, UnicodeString& result) { + for (int32_t i=0; i<s.length(); ++i) { + UChar c = s[i]; + if (c <= (UChar)0x7F) { + result += c; + } else { + result += (UChar)0x5c; + result += (UChar)0x75; + result += toHex((c >> 12) & 0xF); + result += toHex((c >> 8) & 0xF); + result += toHex((c >> 4) & 0xF); + result += toHex( c & 0xF); + } + } + return result; +} + +#define VERBOSE_ASSERTIONS + +UBool IntlTest::assertTrue(const char* message, UBool condition, UBool quiet, UBool possibleDataError) { + if (!condition) { + if (possibleDataError) { + dataerrln("FAIL: assertTrue() failed: %s", message); + } else { + errln("FAIL: assertTrue() failed: %s", message); + } + } else if (!quiet) { + logln("Ok: %s", message); + } + return condition; +} + +UBool IntlTest::assertFalse(const char* message, UBool condition, UBool quiet) { + if (condition) { + errln("FAIL: assertFalse() failed: %s", message); + } else if (!quiet) { + logln("Ok: %s", message); + } + return !condition; +} + +UBool IntlTest::assertSuccess(const char* message, UErrorCode ec, UBool possibleDataError) { + if (U_FAILURE(ec)) { + if (possibleDataError) { + dataerrln("FAIL: %s (%s)", message, u_errorName(ec)); + } else { + errcheckln(ec, "FAIL: %s (%s)", message, u_errorName(ec)); + } + + return FALSE; + } + return TRUE; +} + +UBool IntlTest::assertEquals(const char* message, + const UnicodeString& expected, + const UnicodeString& actual, + UBool possibleDataError) { + if (expected != actual) { + if (possibleDataError) { + dataerrln((UnicodeString)"FAIL: " + message + "; got " + + prettify(actual) + + "; expected " + prettify(expected)); + } else { + errln((UnicodeString)"FAIL: " + message + "; got " + + prettify(actual) + + "; expected " + prettify(expected)); + } + return FALSE; + } +#ifdef VERBOSE_ASSERTIONS + else { + logln((UnicodeString)"Ok: " + message + "; got " + prettify(actual)); + } +#endif + return TRUE; +} + +UBool IntlTest::assertEquals(const char* message, + const char* expected, + const char* actual) { + if (uprv_strcmp(expected, actual) != 0) { + errln((UnicodeString)"FAIL: " + message + "; got \"" + + actual + + "\"; expected \"" + expected + "\""); + return FALSE; + } +#ifdef VERBOSE_ASSERTIONS + else { + logln((UnicodeString)"Ok: " + message + "; got \"" + actual + "\""); + } +#endif + return TRUE; +} + +#if !UCONFIG_NO_FORMATTING +UBool IntlTest::assertEquals(const char* message, + const Formattable& expected, + const Formattable& actual) { + if (expected != actual) { + errln((UnicodeString)"FAIL: " + message + "; got " + + toString(actual) + + "; expected " + toString(expected)); + return FALSE; + } +#ifdef VERBOSE_ASSERTIONS + else { + logln((UnicodeString)"Ok: " + message + "; got " + toString(actual)); + } +#endif + return TRUE; +} +#endif + +static char ASSERT_BUF[256]; + +static const char* extractToAssertBuf(const UnicodeString& message) { + UnicodeString buf; + escape(message, buf); + buf.extract(0, 0x7FFFFFFF, ASSERT_BUF, sizeof(ASSERT_BUF)-1, 0); + ASSERT_BUF[sizeof(ASSERT_BUF)-1] = 0; + return ASSERT_BUF; +} + +UBool IntlTest::assertTrue(const UnicodeString& message, UBool condition, UBool quiet) { + return assertTrue(extractToAssertBuf(message), condition, quiet); +} + +UBool IntlTest::assertFalse(const UnicodeString& message, UBool condition, UBool quiet) { + return assertFalse(extractToAssertBuf(message), condition, quiet); +} + +UBool IntlTest::assertSuccess(const UnicodeString& message, UErrorCode ec) { + return assertSuccess(extractToAssertBuf(message), ec); +} + +UBool IntlTest::assertEquals(const UnicodeString& message, + const UnicodeString& expected, + const UnicodeString& actual) { + return assertEquals(extractToAssertBuf(message), expected, actual); +} + +UBool IntlTest::assertEquals(const UnicodeString& message, + const char* expected, + const char* actual) { + return assertEquals(extractToAssertBuf(message), expected, actual); +} +//-------------------------------------------------------------------- +// Time bomb - allows temporary behavior that expires at a given +// release +//-------------------------------------------------------------------- + +UBool IntlTest::isICUVersionAtLeast(const UVersionInfo x) { + UVersionInfo v; + u_getVersion(v); + return (uprv_memcmp(v, x, U_MAX_VERSION_LENGTH) >= 0); +} + +#if !UCONFIG_NO_FORMATTING +UBool IntlTest::assertEquals(const UnicodeString& message, + const Formattable& expected, + const Formattable& actual) { + return assertEquals(extractToAssertBuf(message), expected, actual); +} +#endif + +void IntlTest::setProperty(const char* propline) { + if (numProps < kMaxProps) { + proplines[numProps] = propline; + } + numProps++; +} + +const char* IntlTest::getProperty(const char* prop) { + const char* val = NULL; + for (int32_t i = 0; i < numProps; i++) { + int32_t plen = uprv_strlen(prop); + if ((int32_t)uprv_strlen(proplines[i]) > plen + 1 + && proplines[i][plen] == '=' + && uprv_strncmp(proplines[i], prop, plen) == 0) { + val = &(proplines[i][plen+1]); + break; + } + } + return val; +} + +/* + * Hey, Emacs, please set the following: + * + * Local Variables: + * indent-tabs-mode: nil + * End: + * + */ |