5d96fad42e
X-SVN-Rev: 775
974 lines
25 KiB
C++
974 lines
25 KiB
C++
/********************************************************************
|
|
* COPYRIGHT:
|
|
* Copyright (c) 1997-1999, International Business Machines Corporation and
|
|
* others. All Rights Reserved.
|
|
********************************************************************/
|
|
|
|
|
|
/*
|
|
* IntlTest in Java is Copyright (c) 1997 Sun Microsystems, Inc.
|
|
* All Rights Reserved.
|
|
*/
|
|
|
|
/**
|
|
* IntlTest is a base class for tests.
|
|
* It is modelled according to, but not exactly similar to,
|
|
* JavaSoft's test class with the same name.
|
|
*/
|
|
|
|
|
|
#include <limits.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <iostream.h>
|
|
#include <assert.h>
|
|
|
|
#include "unicode/utypes.h"
|
|
#include "unicode/unistr.h"
|
|
#include "unicode/coll.h"
|
|
#include "unicode/smpdtfmt.h"
|
|
|
|
#include "intltest.h"
|
|
#include "itmajor.h"
|
|
|
|
#ifdef XP_MAC
|
|
#include <console.h>
|
|
#include "Files.h"
|
|
#endif
|
|
static char* _testDirectory=NULL;
|
|
//-----------------------------------------------------------------------------
|
|
//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); }
|
|
|
|
// [LIU] Just to get things working
|
|
UnicodeString
|
|
operator+(const UnicodeString& left,
|
|
const UnicodeString& right)
|
|
{
|
|
UnicodeString str(left);
|
|
str += right;
|
|
return str;
|
|
}
|
|
|
|
// [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, "%d", 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, "%u", num);
|
|
assert(danger == 'p');
|
|
|
|
return left + 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)
|
|
|
|
sprintf(buffer, "%.30g", num); // nos changed from 99 to 30
|
|
assert(danger == 'p');
|
|
|
|
return left + buffer;
|
|
}
|
|
|
|
/**
|
|
* Originally coded this as operator+, but that makes the expression
|
|
* + char* ambiguous. - liu
|
|
*/
|
|
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:");
|
|
s.insert(s.length(), ']');
|
|
} 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::kString:
|
|
f.getString(s);
|
|
s.insert(0, "[String:");
|
|
s.insert(s.length(), ']');
|
|
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]);
|
|
}
|
|
s.append(UChar(']'));
|
|
}
|
|
break;
|
|
}
|
|
return s;
|
|
}
|
|
|
|
// 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; }
|
|
|
|
//------------------
|
|
|
|
// used for collation result reporting, defined here for convenience
|
|
// (maybe moved later)
|
|
void
|
|
IntlTest::reportCResult( UnicodeString &source, UnicodeString &target,
|
|
CollationKey &sourceKey, CollationKey &targetKey,
|
|
Collator::EComparisonResult compareResult,
|
|
Collator::EComparisonResult keyResult,
|
|
Collator::EComparisonResult expectedResult )
|
|
{
|
|
if (expectedResult < -1 || expectedResult > 1)
|
|
{
|
|
errln("***** invalid call to reportCResult ****");
|
|
return;
|
|
}
|
|
|
|
if (compareResult != expectedResult)
|
|
{
|
|
UnicodeString msg1("compare("), msg2(", "), msg3(") returned "), msg4("; expected ");
|
|
UnicodeString prettySource, prettyTarget, sExpect, sResult;
|
|
|
|
prettify(source, prettySource);
|
|
prettify(target, prettyTarget);
|
|
appendCompareResult(compareResult, sResult);
|
|
appendCompareResult(expectedResult, sExpect);
|
|
|
|
errln(msg1 + prettySource + msg2 + prettyTarget + msg3 + sResult + msg4 + sExpect);
|
|
}
|
|
|
|
if (keyResult != expectedResult)
|
|
{
|
|
UnicodeString msg1("key("), msg2(").compareTo(key("), msg3(")) returned "), msg4("; expected ");
|
|
UnicodeString prettySource, prettyTarget, sExpect, sResult;
|
|
|
|
prettify(source, prettySource);
|
|
prettify(target, prettyTarget);
|
|
appendCompareResult(keyResult, sResult);
|
|
appendCompareResult(expectedResult, sExpect);
|
|
|
|
errln(msg1 + prettySource + msg2 + prettyTarget + msg3 + sResult + msg4 + sExpect);
|
|
|
|
msg1 = " ";
|
|
msg2 = " vs. ";
|
|
|
|
prettify(sourceKey, prettySource);
|
|
prettify(targetKey, prettyTarget);
|
|
|
|
errln(msg1 + prettySource + msg2 + prettyTarget);
|
|
}
|
|
}
|
|
|
|
// Append a hex string to the target
|
|
UnicodeString&
|
|
IntlTest::appendHex(uint32_t number,
|
|
int8_t digits,
|
|
UnicodeString& target)
|
|
{
|
|
static const UnicodeString digitString("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;
|
|
}
|
|
|
|
UnicodeString&
|
|
IntlTest::appendCompareResult(Collator::EComparisonResult result,
|
|
UnicodeString& target)
|
|
{
|
|
if (result == Collator::LESS)
|
|
{
|
|
target += "LESS";
|
|
}
|
|
else if (result == Collator::EQUAL)
|
|
{
|
|
target += "EQUAL";
|
|
}
|
|
else if (result == Collator::GREATER)
|
|
{
|
|
target += "GREATER";
|
|
}
|
|
else
|
|
{
|
|
UnicodeString huh = "?";
|
|
|
|
target += (huh + (int32_t)result);
|
|
}
|
|
|
|
return target;
|
|
}
|
|
|
|
// 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(); i += 1)
|
|
{
|
|
UChar ch = source[i];
|
|
|
|
if (ch < 0x09 || (ch > 0x0A && ch < 0x20)|| ch > 0x7E)
|
|
{
|
|
target += "\\u";
|
|
appendHex(ch, 4, target);
|
|
}
|
|
else
|
|
{
|
|
target += ch;
|
|
}
|
|
}
|
|
|
|
target += "\"";
|
|
|
|
return target;
|
|
}
|
|
// Replace nonprintable characters with unicode escapes
|
|
UnicodeString
|
|
IntlTest::prettify(const UnicodeString &source)
|
|
|
|
{
|
|
int32_t i;
|
|
UnicodeString target;
|
|
target.remove();
|
|
target += "\"";
|
|
|
|
for (i = 0; i < source.length(); i += 1)
|
|
{
|
|
UChar ch = source[i];
|
|
|
|
if (ch < 0x09 || (ch > 0x0A && ch < 0x20)|| ch > 0x7E)
|
|
{
|
|
target += "\\u";
|
|
appendHex(ch, 4, target);
|
|
}
|
|
else
|
|
{
|
|
target += ch;
|
|
}
|
|
}
|
|
|
|
target += "\"";
|
|
|
|
return target;
|
|
}
|
|
// Produce a printable representation of a CollationKey
|
|
UnicodeString &IntlTest::prettify(const CollationKey &source, UnicodeString &target)
|
|
{
|
|
int32_t i, byteCount;
|
|
const uint8_t *bytes = source.getByteArray(byteCount);
|
|
|
|
target.remove();
|
|
target += "[";
|
|
|
|
for (i = 0; i < byteCount; i += 1)
|
|
{
|
|
appendHex(bytes[i], 2, target);
|
|
target += " ";
|
|
}
|
|
|
|
target += "]";
|
|
|
|
return target;
|
|
}
|
|
|
|
void
|
|
IntlTest::pathnameInContext( char* fullname, int32_t maxsize, const char* relPath ) //nosmac
|
|
{
|
|
const char* mainDir;
|
|
char sepChar;
|
|
const char inpSepChar = '|';
|
|
|
|
mainDir = u_getDataDirectory();
|
|
sepChar = U_FILE_SEP_CHAR;
|
|
char sepString[] = U_FILE_SEP_STRING;
|
|
|
|
#if defined(_WIN32) || defined(WIN32) || defined(__OS2__) || defined(OS2)
|
|
char mainDirBuffer[200];
|
|
if(mainDir!=NULL) {
|
|
strcpy(mainDirBuffer, mainDir);
|
|
strcat(mainDirBuffer, "..\\..");
|
|
} else {
|
|
mainDirBuffer[0]='\0';
|
|
}
|
|
mainDir=mainDirBuffer;
|
|
#elif defined(_AIX) || defined(SOLARIS) || defined(LINUX) || defined(HPUX) || defined(POSIX)
|
|
char mainDirBuffer[200];
|
|
strcpy(mainDirBuffer, u_getDataDirectory());
|
|
strcat(mainDirBuffer, "/../");
|
|
mainDir = mainDirBuffer;
|
|
#elif defined(XP_MAC)
|
|
Str255 volName;
|
|
int16_t volNum;
|
|
OSErr err = GetVol( volName, &volNum );
|
|
if (err != noErr) volName[0] = 0;
|
|
mainDir = (char*) &(volName[1]);
|
|
mainDir[volName[0]] = 0;
|
|
#else
|
|
mainDir = "";
|
|
#endif
|
|
/*
|
|
#if defined(_WIN32) || defined(WIN32) || defined(__OS2__) || defined(OS2)
|
|
char mainDirBuffer[200];
|
|
if(mainDir!=NULL) {
|
|
strcpy(mainDirBuffer, mainDir);
|
|
strcat(mainDirBuffer, "..\\..");
|
|
} else {
|
|
mainDirBuffer[0]='\0';
|
|
}
|
|
mainDir=mainDirBuffer;
|
|
sepChar = '\\';
|
|
#elif defined(_AIX) || defined(SOLARIS) || defined(LINUX) || defined(HPUX)
|
|
mainDir = getenv("HOME");
|
|
sepChar = '/';
|
|
#elif defined(XP_MAC)
|
|
Str255 volName;
|
|
int16_t volNum;
|
|
OSErr err = GetVol( volName, &volNum );
|
|
if (err != noErr) volName[0] = 0;
|
|
mainDir = (char*) &(volName[1]);
|
|
mainDir[volName[0]] = 0;
|
|
sepChar = ':';
|
|
#else
|
|
mainDir = "";
|
|
sepChar = '\\';
|
|
#endif
|
|
*/
|
|
|
|
if (relPath[0] == '|') relPath++;
|
|
int32_t lenMainDir = strlen( mainDir );
|
|
int32_t lenRelPath = strlen( relPath );
|
|
if (maxsize < lenMainDir + lenRelPath + 2) { fullname[0] = 0; return; }
|
|
strcpy( fullname, mainDir );
|
|
strcat( fullname, sepString );
|
|
strcat( fullname, relPath );
|
|
char* tmp = strchr( fullname, inpSepChar );
|
|
while (tmp) {
|
|
*tmp = sepChar;
|
|
tmp = strchr( tmp+1, inpSepChar );
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Functions to get and set the directory containing the Test files.
|
|
*/
|
|
|
|
const char*
|
|
IntlTest::getTestDirectory()
|
|
{
|
|
if (_testDirectory == NULL)
|
|
{
|
|
#if defined(_AIX) || defined(SOLARIS) || defined(LINUX) || defined(HPUX) || defined(POSIX)
|
|
setTestDirectory("source|test|testdata|");
|
|
#else
|
|
setTestDirectory("icu|source|test|testdata|");
|
|
#endif
|
|
}
|
|
return _testDirectory;
|
|
}
|
|
|
|
void
|
|
IntlTest::setTestDirectory(const char* newDir)
|
|
{
|
|
char newTestDir[256];
|
|
IntlTest::pathnameInContext(newTestDir, sizeof(newTestDir), newDir);
|
|
if(_testDirectory != NULL)
|
|
free(_testDirectory);
|
|
_testDirectory = (char*) malloc(sizeof(char) * (strlen(newTestDir) + 1));
|
|
strcpy(_testDirectory, newTestDir);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
|
|
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_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 );
|
|
}
|
|
|
|
IntlTest& operator<<(IntlTest& test, const UnicodeString& string)
|
|
{
|
|
if (&test == NULL) return *((IntlTest*) NULL);
|
|
test.log( string );
|
|
return test;
|
|
}
|
|
|
|
IntlTest& operator<<(IntlTest& test, const char* string)
|
|
{
|
|
if (&test == NULL) return *((IntlTest*) NULL);
|
|
test.log( string );
|
|
return test;
|
|
}
|
|
|
|
IntlTest& operator<<(IntlTest& test, const int32_t num)
|
|
{
|
|
if (&test == NULL) return *((IntlTest*) NULL);
|
|
char convert[20];
|
|
sprintf( convert, "%li", num );
|
|
test.log( convert );
|
|
return test;
|
|
}
|
|
|
|
//inline _CRTIMP ostream& __cdecl endl(ostream& _outs) { return _outs << '\n' << flush; }
|
|
//inline ostream& ostream::operator<<(ostream& (__cdecl * _f)(ostream&)) { (*_f)(*this); return *this; }
|
|
|
|
IntlTest& endl( IntlTest& test )
|
|
{
|
|
test.logln();
|
|
return test;
|
|
}
|
|
|
|
IntlTest& operator<<(IntlTest& test, IntlTest& ( * _f)(IntlTest&))
|
|
{
|
|
(*_f)(test);
|
|
return test;
|
|
}
|
|
|
|
|
|
IntlTest::IntlTest()
|
|
{
|
|
caller = NULL;
|
|
path = NULL;
|
|
LL_linestart = TRUE;
|
|
errorCount = 0;
|
|
verbose = FALSE;
|
|
no_err_msg = FALSE;
|
|
quick = FALSE;
|
|
leaks = FALSE;
|
|
testout = &cout;
|
|
LL_indentlevel = indentLevel_offset;
|
|
}
|
|
|
|
void IntlTest::setCaller( IntlTest* callingTest )
|
|
{
|
|
caller = callingTest;
|
|
if (caller) {
|
|
verbose = caller->verbose;
|
|
no_err_msg = caller->no_err_msg;
|
|
quick = caller->quick;
|
|
testout = caller->testout;
|
|
LL_indentlevel = caller->LL_indentlevel + indentLevel_offset;
|
|
}
|
|
}
|
|
|
|
bool_t IntlTest::callTest( IntlTest& testToBeCalled, char* par )
|
|
{
|
|
execCount--; // correct a previously assumed test-exec, as this only calls a subtest
|
|
testToBeCalled.setCaller( this );
|
|
return testToBeCalled.runTest( path, par );
|
|
}
|
|
|
|
void IntlTest::setPath( char* path )
|
|
{
|
|
this->path = path;
|
|
}
|
|
|
|
bool_t IntlTest::setVerbose( bool_t verbose )
|
|
{
|
|
bool_t rval = this->verbose;
|
|
this->verbose = verbose;
|
|
return rval;
|
|
}
|
|
|
|
bool_t IntlTest::setNoErrMsg( bool_t no_err_msg )
|
|
{
|
|
bool_t rval = this->no_err_msg;
|
|
this->no_err_msg = no_err_msg;
|
|
return rval;
|
|
}
|
|
|
|
bool_t IntlTest::setQuick( bool_t quick )
|
|
{
|
|
bool_t rval = this->quick;
|
|
this->quick = quick;
|
|
return rval;
|
|
}
|
|
|
|
bool_t IntlTest::setLeaks( bool_t leaks )
|
|
{
|
|
bool_t rval = this->leaks;
|
|
this->leaks = leaks;
|
|
return rval;
|
|
}
|
|
|
|
int32_t IntlTest::getErrors( void )
|
|
{
|
|
return errorCount;
|
|
}
|
|
|
|
bool_t IntlTest::runTest( char* name, char* par )
|
|
{
|
|
bool_t rval;
|
|
char* pos = NULL;
|
|
|
|
if (name) pos = strchr( name, delim ); // check if name contains path (by looking for '/')
|
|
if (pos) {
|
|
path = pos+1; // store subpath for calling subtest
|
|
*pos = 0; // split into two strings
|
|
}else{
|
|
path = NULL;
|
|
}
|
|
|
|
if (!name || (name[0] == 0) || (strcmp(name, "*") == 0)) {
|
|
rval = runTestLoop( NULL, NULL );
|
|
|
|
}else if (strcmp( name, "LIST" ) == 0) {
|
|
this->usage();
|
|
rval = TRUE;
|
|
|
|
}else{
|
|
rval = runTestLoop( name, par );
|
|
}
|
|
|
|
if (pos) *pos = delim; // restore original value at pos
|
|
return rval;
|
|
}
|
|
|
|
// call individual tests, to be overriden to call implementations
|
|
void IntlTest::runIndexedTest( int32_t index, bool_t exec, 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;
|
|
}
|
|
|
|
|
|
bool_t IntlTest::runTestLoop( char* testname, char* par )
|
|
{
|
|
int32_t index = 0;
|
|
char* name;
|
|
bool_t run_this_test;
|
|
int32_t lastErrorCount;
|
|
bool_t rval = FALSE;
|
|
|
|
IntlTest* saveTest = gTest;
|
|
gTest = this;
|
|
do {
|
|
this->runIndexedTest( index, FALSE, name );
|
|
if (!name || (name[0] == 0)) break;
|
|
if (!testname) {
|
|
run_this_test = TRUE;
|
|
}else{
|
|
run_this_test = (bool_t) (strcmp( name, testname ) == 0);
|
|
}
|
|
if (run_this_test) {
|
|
lastErrorCount = errorCount;
|
|
execCount++;
|
|
this->runIndexedTest( index, TRUE, name, par );
|
|
rval = TRUE; // at least one test has been called
|
|
char msg[256];
|
|
if (lastErrorCount == errorCount) {
|
|
sprintf( msg, "---OK: %s", name );
|
|
}else{
|
|
sprintf( msg, "---ERRORS (%li) in %s", (errorCount-lastErrorCount), name );
|
|
}
|
|
LL_indentlevel -= 3;
|
|
LL_message( "", TRUE);
|
|
LL_message( msg, TRUE);
|
|
LL_message( "", TRUE);
|
|
LL_indentlevel += 3;
|
|
}
|
|
index++;
|
|
}while(name);
|
|
|
|
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 );
|
|
}
|
|
}
|
|
|
|
int32_t IntlTest::IncErrorCount( void )
|
|
{
|
|
errorCount++;
|
|
if (caller) caller->IncErrorCount();
|
|
return errorCount;
|
|
}
|
|
|
|
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::LL_message( UnicodeString message, bool_t newline )
|
|
{
|
|
UChar c;
|
|
|
|
ostream& stream = *testout;
|
|
int32_t saveFlags = stream.flags();
|
|
stream << hex;
|
|
|
|
int32_t len = message.length();
|
|
UTextOffset pos = 0;
|
|
bool_t gen = FALSE;
|
|
do{
|
|
if (LL_linestart) {
|
|
stream << '\n';
|
|
for (int32_t i = 0; i < LL_indentlevel; i++) stream << ' ';
|
|
gen = TRUE;
|
|
LL_linestart = FALSE;
|
|
}
|
|
if (pos >= len) break;
|
|
|
|
c = message[pos++];
|
|
if (c >= ' ' && c <= '~') {
|
|
stream << (char)c;
|
|
gen = TRUE;
|
|
}else if (c == '\n') {
|
|
LL_linestart = TRUE;
|
|
}else if (c == 9) { // tab
|
|
stream << " ";
|
|
gen = TRUE;
|
|
}else{
|
|
stream << "[$" << c << "]";
|
|
gen = TRUE;
|
|
}
|
|
}while (pos < len);
|
|
|
|
if (gen) stream.flush();
|
|
stream.setf(saveFlags & ios::basefield, ios::basefield);
|
|
if (newline) LL_linestart = TRUE;
|
|
}
|
|
|
|
/**
|
|
* Print a usage message for this test class.
|
|
*/
|
|
void IntlTest::usage( void )
|
|
{
|
|
bool_t save_verbose = setVerbose( TRUE );
|
|
logln("Test names:");
|
|
logln("-----------");
|
|
|
|
int32_t index = 0;
|
|
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
|
|
bool_t
|
|
IntlTest::run_phase2( char* name, char* par ) // supports reporting memory leaks
|
|
{
|
|
UnicodeString* strLeak = new UnicodeString("forced leak"); // for verifying purify filter
|
|
return this->runTest( name, par );
|
|
}
|
|
|
|
|
|
int
|
|
main(int argc, char* argv[])
|
|
{
|
|
|
|
#ifdef XP_MAC
|
|
argc = ccommand( &argv );
|
|
#endif
|
|
|
|
bool_t syntax = FALSE;
|
|
bool_t all = TRUE;
|
|
bool_t verbose = FALSE;
|
|
bool_t no_err_msg = FALSE;
|
|
bool_t quick = TRUE;
|
|
bool_t name = FALSE;
|
|
bool_t leaks = FALSE;
|
|
|
|
for (int i = 1; i < argc; ++i) {
|
|
if (argv[i][0] == '-') {
|
|
const char* str = argv[i] + 1;
|
|
if (strcmp("verbose", str) == 0)
|
|
verbose = TRUE;
|
|
else if (strcmp("v", str) == 0)
|
|
verbose = TRUE;
|
|
else if (strcmp("noerrormsg", str) == 0)
|
|
no_err_msg = TRUE;
|
|
else if (strcmp("n", str) == 0)
|
|
no_err_msg = TRUE;
|
|
else if (strcmp("exhaustive", str) == 0)
|
|
quick = FALSE;
|
|
else if (strcmp("e", str) == 0)
|
|
quick = FALSE;
|
|
else if (strcmp("all", str) == 0)
|
|
all = TRUE;
|
|
else if (strcmp("a", str) == 0)
|
|
all = TRUE;
|
|
else if (strcmp("leaks", str) == 0)
|
|
leaks = TRUE;
|
|
else if (strcmp("l", str) == 0)
|
|
leaks = TRUE;
|
|
else {
|
|
syntax = TRUE;
|
|
}
|
|
}else{
|
|
name = TRUE;
|
|
all = FALSE;
|
|
}
|
|
}
|
|
|
|
if (all && name) syntax = TRUE;
|
|
if (!all && !name) syntax = TRUE;
|
|
|
|
if (syntax) {
|
|
cout << "### Syntax:\n"
|
|
"### IntlTest [-option1 -option2 ...] [testname1 testname2 ...] \n"
|
|
"### where options are: verbose (v), all (a), noerrormsg (n), \n"
|
|
"### exhaustive (e) and leaks (l). \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;
|
|
}
|
|
|
|
bool_t all_tests_exist = TRUE;
|
|
MajorTestLevel major;
|
|
major.setVerbose( verbose );
|
|
major.setNoErrMsg( no_err_msg );
|
|
major.setQuick( quick );
|
|
major.setLeaks( leaks );
|
|
cout << "-----------------------------------------------" << endl;
|
|
cout << " IntlTest Test Suite for " << endl;
|
|
cout << " International Classes for Unicode " << endl;
|
|
cout << "-----------------------------------------------" << endl;
|
|
cout << " Options: " << endl;
|
|
cout << " all (a) : " << (all? "On" : "Off") << endl;
|
|
cout << " Verbose (v) : " << (verbose? "On" : "Off") << endl;
|
|
cout << " No error messages (n) : " << (no_err_msg? "On" : "Off") << endl;
|
|
cout << " Exhaustive (e) : " << (!quick? "On" : "Off") << endl;
|
|
cout << " Leaks (l) : " << (leaks? "On" : "Off") << endl;
|
|
cout << "-----------------------------------------------" << endl << endl;
|
|
|
|
// initial check for the default converter
|
|
UErrorCode errorCode = U_ZERO_ERROR;
|
|
UConverter *cnv = ucnv_open(0, &errorCode);
|
|
if(cnv != 0) {
|
|
// ok
|
|
ucnv_close(cnv);
|
|
} else {
|
|
cout << "*** Failure! The default converter cannot be opened." << endl <<
|
|
"*** Check the ICU_DATA environment variable and " << endl <<
|
|
"*** check that the data files are present." << endl;
|
|
return 1;
|
|
}
|
|
|
|
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];
|
|
cout << "\n=== Handling test: " << name << ": ===\n";
|
|
char* parameter = strchr( name, '@' );
|
|
if (parameter) {
|
|
*parameter = 0;
|
|
parameter += 1;
|
|
}
|
|
execCount = 0;
|
|
bool_t res = major.runTest( name, parameter );
|
|
if (leaks && res) {
|
|
major.run_phase2( name, parameter );
|
|
}
|
|
if (!res || (execCount <= 0)) {
|
|
cout << "\n---ERROR: Test doesn't exist: " << name << " !\n";
|
|
all_tests_exist = FALSE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
cout << "\n--------------------------------------\n";
|
|
if (major.getErrors() == 0) {
|
|
cout << "OK: All tests passed without error.\n";
|
|
}else{
|
|
cout << "Errors in total: " << major.getErrors() << ".\n";
|
|
}
|
|
|
|
cout << "--------------------------------------\n";
|
|
|
|
if (execCount <= 0) {
|
|
cout << "***** Not all called tests actually exist! *****\n";
|
|
}
|
|
|
|
return major.getErrors();
|
|
}
|