Index: icu46/source/test/intltest/intltest.cpp |
=================================================================== |
--- icu46/source/test/intltest/intltest.cpp (revision 0) |
+++ icu46/source/test/intltest/intltest.cpp (revision 0) |
@@ -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: |
+ * |
+ */ |
Property changes on: icu46/source/test/intltest/intltest.cpp |
___________________________________________________________________ |
Added: svn:eol-style |
+ LF |