1/******************************************************************** 2 * COPYRIGHT: 3 * Copyright (c) 1997-2010, International Business Machines Corporation and 4 * others. All Rights Reserved. 5 ********************************************************************/ 6/* file name: strtest.cpp 7* encoding: US-ASCII 8* tab size: 8 (not used) 9* indentation:4 10* 11* created on: 1999nov22 12* created by: Markus W. Scherer 13*/ 14 15#include <string.h> 16 17#include "unicode/utypes.h" 18#include "unicode/putil.h" 19#include "unicode/std_string.h" 20#include "unicode/stringpiece.h" 21#include "unicode/unistr.h" 22#include "unicode/ustring.h" 23#include "charstr.h" 24#include "intltest.h" 25#include "strtest.h" 26 27StringTest::~StringTest() {} 28 29void StringTest::TestEndian(void) { 30 union { 31 uint8_t byte; 32 uint16_t word; 33 } u; 34 u.word=0x0100; 35 if(U_IS_BIG_ENDIAN!=u.byte) { 36 errln("TestEndian: U_IS_BIG_ENDIAN needs to be fixed in platform.h"); 37 } 38} 39 40void StringTest::TestSizeofTypes(void) { 41 if(U_SIZEOF_WCHAR_T!=sizeof(wchar_t)) { 42 errln("TestSizeofWCharT: U_SIZEOF_WCHAR_T!=sizeof(wchar_t) - U_SIZEOF_WCHAR_T needs to be fixed in platform.h"); 43 } 44#ifdef U_INT64_T_UNAVAILABLE 45 errln("int64_t and uint64_t are undefined."); 46#else 47 if(8!=sizeof(int64_t)) { 48 errln("TestSizeofTypes: 8!=sizeof(int64_t) - int64_t needs to be fixed in platform.h"); 49 } 50 if(8!=sizeof(uint64_t)) { 51 errln("TestSizeofTypes: 8!=sizeof(uint64_t) - uint64_t needs to be fixed in platform.h"); 52 } 53#endif 54 if(8!=sizeof(double)) { 55 errln("8!=sizeof(double) - putil.c code may not work"); 56 } 57 if(4!=sizeof(int32_t)) { 58 errln("4!=sizeof(int32_t)"); 59 } 60 if(4!=sizeof(uint32_t)) { 61 errln("4!=sizeof(uint32_t)"); 62 } 63 if(2!=sizeof(int16_t)) { 64 errln("2!=sizeof(int16_t)"); 65 } 66 if(2!=sizeof(uint16_t)) { 67 errln("2!=sizeof(uint16_t)"); 68 } 69 if(2!=sizeof(UChar)) { 70 errln("2!=sizeof(UChar)"); 71 } 72 if(1!=sizeof(int8_t)) { 73 errln("1!=sizeof(int8_t)"); 74 } 75 if(1!=sizeof(uint8_t)) { 76 errln("1!=sizeof(uint8_t)"); 77 } 78 if(1!=sizeof(UBool)) { 79 errln("1!=sizeof(UBool)"); 80 } 81} 82 83void StringTest::TestCharsetFamily(void) { 84 unsigned char c='A'; 85 if( (U_CHARSET_FAMILY==U_ASCII_FAMILY && c!=0x41) || 86 (U_CHARSET_FAMILY==U_EBCDIC_FAMILY && c!=0xc1) 87 ) { 88 errln("TestCharsetFamily: U_CHARSET_FAMILY needs to be fixed in platform.h"); 89 } 90} 91 92U_STRING_DECL(ustringVar, "aZ0 -", 5); 93 94void 95StringTest::Test_U_STRING() { 96 U_STRING_INIT(ustringVar, "aZ0 -", 5); 97 if( sizeof(ustringVar)/sizeof(*ustringVar)!=6 || 98 ustringVar[0]!=0x61 || 99 ustringVar[1]!=0x5a || 100 ustringVar[2]!=0x30 || 101 ustringVar[3]!=0x20 || 102 ustringVar[4]!=0x2d || 103 ustringVar[5]!=0 104 ) { 105 errln("Test_U_STRING: U_STRING_DECL with U_STRING_INIT does not work right! " 106 "See putil.h and utypes.h with platform.h."); 107 } 108} 109 110void 111StringTest::Test_UNICODE_STRING() { 112 UnicodeString ustringVar=UNICODE_STRING("aZ0 -", 5); 113 if( ustringVar.length()!=5 || 114 ustringVar[0]!=0x61 || 115 ustringVar[1]!=0x5a || 116 ustringVar[2]!=0x30 || 117 ustringVar[3]!=0x20 || 118 ustringVar[4]!=0x2d 119 ) { 120 errln("Test_UNICODE_STRING: UNICODE_STRING does not work right! " 121 "See unistr.h and utypes.h with platform.h."); 122 } 123} 124 125void 126StringTest::Test_UNICODE_STRING_SIMPLE() { 127 UnicodeString ustringVar=UNICODE_STRING_SIMPLE("aZ0 -"); 128 if( ustringVar.length()!=5 || 129 ustringVar[0]!=0x61 || 130 ustringVar[1]!=0x5a || 131 ustringVar[2]!=0x30 || 132 ustringVar[3]!=0x20 || 133 ustringVar[4]!=0x2d 134 ) { 135 errln("Test_UNICODE_STRING_SIMPLE: UNICODE_STRING_SIMPLE does not work right! " 136 "See unistr.h and utypes.h with platform.h."); 137 } 138} 139 140void 141StringTest::Test_UTF8_COUNT_TRAIL_BYTES() { 142 if(UTF8_COUNT_TRAIL_BYTES(0x7F) != 0 143 || UTF8_COUNT_TRAIL_BYTES(0xC0) != 1 144 || UTF8_COUNT_TRAIL_BYTES(0xE0) != 2 145 || UTF8_COUNT_TRAIL_BYTES(0xF0) != 3) 146 { 147 errln("Test_UTF8_COUNT_TRAIL_BYTES: UTF8_COUNT_TRAIL_BYTES does not work right! " 148 "See utf8.h."); 149 } 150} 151 152void StringTest::runIndexedTest(int32_t index, UBool exec, const char *&name, char * /*par*/) { 153 if(exec) { 154 logln("TestSuite Character and String Test: "); 155 } 156 TESTCASE_AUTO_BEGIN; 157 TESTCASE_AUTO(TestEndian); 158 TESTCASE_AUTO(TestSizeofTypes); 159 TESTCASE_AUTO(TestCharsetFamily); 160 TESTCASE_AUTO(Test_U_STRING); 161 TESTCASE_AUTO(Test_UNICODE_STRING); 162 TESTCASE_AUTO(Test_UNICODE_STRING_SIMPLE); 163 TESTCASE_AUTO(Test_UTF8_COUNT_TRAIL_BYTES); 164 TESTCASE_AUTO(TestSTLCompatibility); 165 TESTCASE_AUTO(TestStdNamespaceQualifier); 166 TESTCASE_AUTO(TestUsingStdNamespace); 167 TESTCASE_AUTO(TestStringPiece); 168 TESTCASE_AUTO(TestStringPieceComparisons); 169 TESTCASE_AUTO(TestByteSink); 170 TESTCASE_AUTO(TestCheckedArrayByteSink); 171 TESTCASE_AUTO(TestStringByteSink); 172 TESTCASE_AUTO(TestCharString); 173 TESTCASE_AUTO_END; 174} 175 176// Syntax check for the correct namespace qualifier for the standard string class. 177void 178StringTest::TestStdNamespaceQualifier() { 179#if U_HAVE_STD_STRING 180 U_STD_NSQ string s="abc xyz"; 181 U_STD_NSQ string t="abc"; 182 t.append(" "); 183 t.append("xyz"); 184 if(s!=t) { 185 errln("standard string concatenation error: %s != %s", s.c_str(), t.c_str()); 186 } 187#endif 188} 189 190void 191StringTest::TestUsingStdNamespace() { 192#if U_HAVE_STD_STRING 193 // Now test that "using namespace std;" is defined correctly. 194 U_STD_NS_USE 195 196 string s="abc xyz"; 197 string t="abc"; 198 t.append(" "); 199 t.append("xyz"); 200 if(s!=t) { 201 errln("standard string concatenation error: %s != %s", s.c_str(), t.c_str()); 202 } 203#endif 204} 205 206void 207StringTest::TestStringPiece() { 208 // Default constructor. 209 StringPiece empty; 210 if(!empty.empty() || empty.data()!=NULL || empty.length()!=0 || empty.size()!=0) { 211 errln("StringPiece() failed"); 212 } 213 // Construct from NULL const char * pointer. 214 StringPiece null(NULL); 215 if(!null.empty() || null.data()!=NULL || null.length()!=0 || null.size()!=0) { 216 errln("StringPiece(NULL) failed"); 217 } 218 // Construct from const char * pointer. 219 static const char *abc_chars="abc"; 220 StringPiece abc(abc_chars); 221 if(abc.empty() || abc.data()!=abc_chars || abc.length()!=3 || abc.size()!=3) { 222 errln("StringPiece(abc_chars) failed"); 223 } 224 // Construct from const char * pointer and length. 225 static const char *abcdefg_chars="abcdefg"; 226 StringPiece abcd(abcdefg_chars, 4); 227 if(abcd.empty() || abcd.data()!=abcdefg_chars || abcd.length()!=4 || abcd.size()!=4) { 228 errln("StringPiece(abcdefg_chars, 4) failed"); 229 } 230#if U_HAVE_STD_STRING 231 // Construct from std::string. 232 U_STD_NSQ string uvwxyz_string("uvwxyz"); 233 StringPiece uvwxyz(uvwxyz_string); 234 if(uvwxyz.empty() || uvwxyz.data()!=uvwxyz_string.data() || uvwxyz.length()!=6 || uvwxyz.size()!=6) { 235 errln("StringPiece(uvwxyz_string) failed"); 236 } 237#endif 238 // Substring constructor with pos. 239 StringPiece sp(abcd, -1); 240 if(sp.empty() || sp.data()!=abcdefg_chars || sp.length()!=4 || sp.size()!=4) { 241 errln("StringPiece(abcd, -1) failed"); 242 } 243 sp=StringPiece(abcd, 5); 244 if(!sp.empty() || sp.length()!=0 || sp.size()!=0) { 245 errln("StringPiece(abcd, 5) failed"); 246 } 247 sp=StringPiece(abcd, 2); 248 if(sp.empty() || sp.data()!=abcdefg_chars+2 || sp.length()!=2 || sp.size()!=2) { 249 errln("StringPiece(abcd, -1) failed"); 250 } 251 // Substring constructor with pos and len. 252 sp=StringPiece(abcd, -1, 8); 253 if(sp.empty() || sp.data()!=abcdefg_chars || sp.length()!=4 || sp.size()!=4) { 254 errln("StringPiece(abcd, -1, 8) failed"); 255 } 256 sp=StringPiece(abcd, 5, 8); 257 if(!sp.empty() || sp.length()!=0 || sp.size()!=0) { 258 errln("StringPiece(abcd, 5, 8) failed"); 259 } 260 sp=StringPiece(abcd, 2, 8); 261 if(sp.empty() || sp.data()!=abcdefg_chars+2 || sp.length()!=2 || sp.size()!=2) { 262 errln("StringPiece(abcd, -1) failed"); 263 } 264 sp=StringPiece(abcd, 2, -1); 265 if(!sp.empty() || sp.length()!=0 || sp.size()!=0) { 266 errln("StringPiece(abcd, 5, -1) failed"); 267 } 268 // static const npos 269 const int32_t *ptr_npos=&StringPiece::npos; 270 if(StringPiece::npos!=0x7fffffff || *ptr_npos!=0x7fffffff) { 271 errln("StringPiece::npos!=0x7fffffff"); 272 } 273 // substr() method with pos, using len=npos. 274 sp=abcd.substr(-1); 275 if(sp.empty() || sp.data()!=abcdefg_chars || sp.length()!=4 || sp.size()!=4) { 276 errln("abcd.substr(-1) failed"); 277 } 278 sp=abcd.substr(5); 279 if(!sp.empty() || sp.length()!=0 || sp.size()!=0) { 280 errln("abcd.substr(5) failed"); 281 } 282 sp=abcd.substr(2); 283 if(sp.empty() || sp.data()!=abcdefg_chars+2 || sp.length()!=2 || sp.size()!=2) { 284 errln("abcd.substr(-1) failed"); 285 } 286 // substr() method with pos and len. 287 sp=abcd.substr(-1, 8); 288 if(sp.empty() || sp.data()!=abcdefg_chars || sp.length()!=4 || sp.size()!=4) { 289 errln("abcd.substr(-1, 8) failed"); 290 } 291 sp=abcd.substr(5, 8); 292 if(!sp.empty() || sp.length()!=0 || sp.size()!=0) { 293 errln("abcd.substr(5, 8) failed"); 294 } 295 sp=abcd.substr(2, 8); 296 if(sp.empty() || sp.data()!=abcdefg_chars+2 || sp.length()!=2 || sp.size()!=2) { 297 errln("abcd.substr(-1) failed"); 298 } 299 sp=abcd.substr(2, -1); 300 if(!sp.empty() || sp.length()!=0 || sp.size()!=0) { 301 errln("abcd.substr(5, -1) failed"); 302 } 303 // clear() 304 sp=abcd; 305 sp.clear(); 306 if(!sp.empty() || sp.data()!=NULL || sp.length()!=0 || sp.size()!=0) { 307 errln("abcd.clear() failed"); 308 } 309 // remove_prefix() 310 sp=abcd; 311 sp.remove_prefix(-1); 312 if(sp.empty() || sp.data()!=abcdefg_chars || sp.length()!=4 || sp.size()!=4) { 313 errln("abcd.remove_prefix(-1) failed"); 314 } 315 sp=abcd; 316 sp.remove_prefix(2); 317 if(sp.empty() || sp.data()!=abcdefg_chars+2 || sp.length()!=2 || sp.size()!=2) { 318 errln("abcd.remove_prefix(2) failed"); 319 } 320 sp=abcd; 321 sp.remove_prefix(5); 322 if(!sp.empty() || sp.length()!=0 || sp.size()!=0) { 323 errln("abcd.remove_prefix(5) failed"); 324 } 325 // remove_suffix() 326 sp=abcd; 327 sp.remove_suffix(-1); 328 if(sp.empty() || sp.data()!=abcdefg_chars || sp.length()!=4 || sp.size()!=4) { 329 errln("abcd.remove_suffix(-1) failed"); 330 } 331 sp=abcd; 332 sp.remove_suffix(2); 333 if(sp.empty() || sp.data()!=abcdefg_chars || sp.length()!=2 || sp.size()!=2) { 334 errln("abcd.remove_suffix(2) failed"); 335 } 336 sp=abcd; 337 sp.remove_suffix(5); 338 if(!sp.empty() || sp.length()!=0 || sp.size()!=0) { 339 errln("abcd.remove_suffix(5) failed"); 340 } 341} 342 343void 344StringTest::TestStringPieceComparisons() { 345 StringPiece empty; 346 StringPiece null(NULL); 347 StringPiece abc("abc"); 348 StringPiece abcd("abcdefg", 4); 349 StringPiece abx("abx"); 350 if(empty!=null) { 351 errln("empty!=null"); 352 } 353 if(empty==abc) { 354 errln("empty==abc"); 355 } 356 if(abc==abcd) { 357 errln("abc==abcd"); 358 } 359 abcd.remove_suffix(1); 360 if(abc!=abcd) { 361 errln("abc!=abcd.remove_suffix(1)"); 362 } 363 if(abc==abx) { 364 errln("abc==abx"); 365 } 366} 367 368// Verify that ByteSink is subclassable and Flush() overridable. 369class SimpleByteSink : public ByteSink { 370public: 371 SimpleByteSink(char *outbuf) : fOutbuf(outbuf), fLength(0) {} 372 virtual void Append(const char *bytes, int32_t n) { 373 if(fOutbuf != bytes) { 374 memcpy(fOutbuf, bytes, n); 375 } 376 fOutbuf += n; 377 fLength += n; 378 } 379 virtual void Flush() { Append("z", 1); } 380 int32_t length() { return fLength; } 381private: 382 char *fOutbuf; 383 int32_t fLength; 384}; 385 386// Test the ByteSink base class. 387void 388StringTest::TestByteSink() { 389 char buffer[20]; 390 buffer[4] = '!'; 391 SimpleByteSink sink(buffer); 392 sink.Append("abc", 3); 393 sink.Flush(); 394 if(!(sink.length() == 4 && 0 == memcmp("abcz", buffer, 4) && buffer[4] == '!')) { 395 errln("ByteSink (SimpleByteSink) did not Append() or Flush() as expected"); 396 return; 397 } 398 char scratch[20]; 399 int32_t capacity = -1; 400 char *dest = sink.GetAppendBuffer(0, 50, scratch, (int32_t)sizeof(scratch), &capacity); 401 if(dest != NULL || capacity != 0) { 402 errln("ByteSink.GetAppendBuffer(min_capacity<1) did not properly return NULL[0]"); 403 return; 404 } 405 dest = sink.GetAppendBuffer(10, 50, scratch, 9, &capacity); 406 if(dest != NULL || capacity != 0) { 407 errln("ByteSink.GetAppendBuffer(scratch_capacity<min_capacity) did not properly return NULL[0]"); 408 return; 409 } 410 dest = sink.GetAppendBuffer(5, 50, scratch, (int32_t)sizeof(scratch), &capacity); 411 if(dest != scratch || capacity != (int32_t)sizeof(scratch)) { 412 errln("ByteSink.GetAppendBuffer() did not properly return the scratch buffer"); 413 } 414} 415 416void 417StringTest::TestCheckedArrayByteSink() { 418 char buffer[20]; // < 26 for the test code to work 419 buffer[3] = '!'; 420 CheckedArrayByteSink sink(buffer, (int32_t)sizeof(buffer)); 421 sink.Append("abc", 3); 422 if(!(sink.NumberOfBytesAppended() == 3 && sink.NumberOfBytesWritten() == 3 && 423 0 == memcmp("abc", buffer, 3) && buffer[3] == '!') && 424 !sink.Overflowed() 425 ) { 426 errln("CheckedArrayByteSink did not Append() as expected"); 427 return; 428 } 429 char scratch[10]; 430 int32_t capacity = -1; 431 char *dest = sink.GetAppendBuffer(0, 50, scratch, (int32_t)sizeof(scratch), &capacity); 432 if(dest != NULL || capacity != 0) { 433 errln("CheckedArrayByteSink.GetAppendBuffer(min_capacity<1) did not properly return NULL[0]"); 434 return; 435 } 436 dest = sink.GetAppendBuffer(10, 50, scratch, 9, &capacity); 437 if(dest != NULL || capacity != 0) { 438 errln("CheckedArrayByteSink.GetAppendBuffer(scratch_capacity<min_capacity) did not properly return NULL[0]"); 439 return; 440 } 441 dest = sink.GetAppendBuffer(10, 50, scratch, (int32_t)sizeof(scratch), &capacity); 442 if(dest != buffer + 3 || capacity != (int32_t)sizeof(buffer) - 3) { 443 errln("CheckedArrayByteSink.GetAppendBuffer() did not properly return its own buffer"); 444 return; 445 } 446 memcpy(dest, "defghijklm", 10); 447 sink.Append(dest, 10); 448 if(!(sink.NumberOfBytesAppended() == 13 && sink.NumberOfBytesWritten() == 13 && 449 0 == memcmp("abcdefghijklm", buffer, 13) && 450 !sink.Overflowed()) 451 ) { 452 errln("CheckedArrayByteSink did not Append(its own buffer) as expected"); 453 return; 454 } 455 dest = sink.GetAppendBuffer(10, 50, scratch, (int32_t)sizeof(scratch), &capacity); 456 if(dest != scratch || capacity != (int32_t)sizeof(scratch)) { 457 errln("CheckedArrayByteSink.GetAppendBuffer() did not properly return the scratch buffer"); 458 } 459 memcpy(dest, "nopqrstuvw", 10); 460 sink.Append(dest, 10); 461 if(!(sink.NumberOfBytesAppended() == 23 && 462 sink.NumberOfBytesWritten() == (int32_t)sizeof(buffer) && 463 0 == memcmp("abcdefghijklmnopqrstuvwxyz", buffer, (int32_t)sizeof(buffer)) && 464 sink.Overflowed()) 465 ) { 466 errln("CheckedArrayByteSink did not Append(scratch buffer) as expected"); 467 return; 468 } 469 sink.Reset().Append("123", 3); 470 if(!(sink.NumberOfBytesAppended() == 3 && sink.NumberOfBytesWritten() == 3 && 471 0 == memcmp("123defghijklmnopqrstuvwxyz", buffer, (int32_t)sizeof(buffer)) && 472 !sink.Overflowed()) 473 ) { 474 errln("CheckedArrayByteSink did not Reset().Append() as expected"); 475 return; 476 } 477} 478 479void 480StringTest::TestStringByteSink() { 481#if U_HAVE_STD_STRING 482 // Not much to test because only the constructor and Append() 483 // are implemented, and trivially so. 484 U_STD_NSQ string result("abc"); // std::string 485 StringByteSink<U_STD_NSQ string> sink(&result); 486 sink.Append("def", 3); 487 if(result != "abcdef") { 488 errln("StringByteSink did not Append() as expected"); 489 } 490#endif 491} 492 493#if defined(U_WINDOWS) && defined(_MSC_VER) 494#include <vector> 495#endif 496 497void 498StringTest::TestSTLCompatibility() { 499#if defined(U_WINDOWS) && defined(_MSC_VER) 500 /* Just make sure that it compiles with STL's placement new usage. */ 501 std::vector<UnicodeString> myvect; 502 myvect.push_back(UnicodeString("blah")); 503#endif 504} 505 506void 507StringTest::TestCharString() { 508 IcuTestErrorCode errorCode(*this, "TestCharString()"); 509 char expected[400]; 510 static const char longStr[] = 511 "This is a long string that is meant to cause reallocation of the internal buffer of CharString."; 512 CharString chStr(longStr, errorCode); 513 if (0 != strcmp(longStr, chStr.data()) || (int32_t)strlen(longStr) != chStr.length()) { 514 errln("CharString(longStr) failed."); 515 } 516 CharString test("Test", errorCode); 517 CharString copy(test,errorCode); 518 copy.copyFrom(chStr, errorCode); 519 if (0 != strcmp(longStr, copy.data()) || (int32_t)strlen(longStr) != copy.length()) { 520 errln("CharString.copyFrom() failed."); 521 } 522 StringPiece sp(chStr.toStringPiece()); 523 sp.remove_prefix(4); 524 chStr.append(sp, errorCode).append(chStr, errorCode); 525 strcpy(expected, longStr); 526 strcat(expected, longStr+4); 527 strcat(expected, longStr); 528 strcat(expected, longStr+4); 529 if (0 != strcmp(expected, chStr.data()) || (int32_t)strlen(expected) != chStr.length()) { 530 errln("CharString(longStr).append(substring of self).append(self) failed."); 531 } 532 chStr.clear().append("abc", errorCode).append("defghij", 3, errorCode); 533 if (0 != strcmp("abcdef", chStr.data()) || 6 != chStr.length()) { 534 errln("CharString.clear().append(abc).append(defghij, 3) failed."); 535 } 536 chStr.appendInvariantChars(UNICODE_STRING_SIMPLE( 537 "This is a long string that is meant to cause reallocation of the internal buffer of CharString."), 538 errorCode); 539 strcpy(expected, "abcdef"); 540 strcat(expected, longStr); 541 if (0 != strcmp(expected, chStr.data()) || (int32_t)strlen(expected) != chStr.length()) { 542 errln("CharString.appendInvariantChars(longStr) failed."); 543 } 544 int32_t appendCapacity = 0; 545 char *buffer = chStr.getAppendBuffer(5, 10, appendCapacity, errorCode); 546 if (errorCode.isFailure()) { 547 return; 548 } 549 memcpy(buffer, "*****", 5); 550 chStr.append(buffer, 5, errorCode); 551 chStr.truncate(chStr.length()-3); 552 strcat(expected, "**"); 553 if (0 != strcmp(expected, chStr.data()) || (int32_t)strlen(expected) != chStr.length()) { 554 errln("CharString.getAppendBuffer().append(**) failed."); 555 } 556} 557