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