| 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
|
|
|
|
|