1 /* 2 ******************************************************************************* 3 * 4 * Copyright (C) 1999-2013, International Business Machines 5 * Corporation and others. All Rights Reserved. 6 * 7 ******************************************************************************* 8 * file name: letest.cpp 9 * 10 * created on: 11/06/2000 11 * created by: Eric R. Mader 12 */ 13 14 #include "unicode/utypes.h" 15 #include "unicode/uclean.h" 16 #include "unicode/uchar.h" 17 #include "unicode/unistr.h" 18 #include "unicode/uscript.h" 19 #include "unicode/putil.h" 20 #include "unicode/ctest.h" 21 22 #include "layout/LETypes.h" 23 #include "layout/LEScripts.h" 24 #include "layout/LayoutEngine.h" 25 26 #include "layout/ParagraphLayout.h" 27 #include "layout/RunArrays.h" 28 29 #include "PortableFontInstance.h" 30 #include "SimpleFontInstance.h" 31 32 #include "letsutil.h" 33 #include "letest.h" 34 35 #include "xmlparser.h" 36 #include "putilimp.h" // for uprv_getUTCtime() 37 38 #include <stdlib.h> 39 #include <string.h> 40 41 U_NAMESPACE_USE 42 43 #define CH_COMMA 0x002C 44 45 U_CDECL_BEGIN 46 47 static void U_CALLCONV ScriptTest(void) 48 { 49 if ((int)scriptCodeCount != (int)USCRIPT_CODE_LIMIT) { 50 log_err("ScriptCodes::scriptCodeCount = %d, but UScriptCode::USCRIPT_CODE_LIMIT = %d\n", scriptCodeCount, USCRIPT_CODE_LIMIT); 51 } 52 } 53 54 static void U_CALLCONV ParamTest(void) 55 { 56 LEErrorCode status = LE_NO_ERROR; 57 SimpleFontInstance *font = new SimpleFontInstance(12, status); 58 LayoutEngine *engine = LayoutEngine::layoutEngineFactory(font, arabScriptCode, -1, status); 59 LEGlyphID *glyphs = NULL; 60 le_int32 *indices = NULL; 61 float *positions = NULL; 62 le_int32 glyphCount = 0; 63 64 glyphCount = engine->getGlyphCount(); 65 if (glyphCount != 0) { 66 log_err("Calling getGlyphCount() on an empty layout returned %d.\n", glyphCount); 67 } 68 69 glyphs = NEW_ARRAY(LEGlyphID, glyphCount + 10); 70 indices = NEW_ARRAY(le_int32, glyphCount + 10); 71 positions = NEW_ARRAY(float, glyphCount + 10); 72 73 engine->getGlyphs(NULL, status); 74 75 if (status != LE_ILLEGAL_ARGUMENT_ERROR) { 76 log_err("Calling getGlyphs(NULL, status) did not return LE_ILLEGAL_ARGUMENT_ERROR.\n"); 77 } 78 79 status = LE_NO_ERROR; 80 engine->getGlyphs(glyphs, status); 81 82 if (status != LE_NO_LAYOUT_ERROR) { 83 log_err("Calling getGlyphs(glyphs, status) on an empty layout did not return LE_NO_LAYOUT_ERROR.\n"); 84 } 85 86 status = LE_NO_ERROR; 87 engine->getGlyphs(NULL, 0xFF000000L, status); 88 89 if (status != LE_ILLEGAL_ARGUMENT_ERROR) { 90 log_err("Calling getGlyphs(NULL, 0xFF000000L, status) did not return LE_ILLEGAL_ARGUMENT_ERROR.\n"); 91 } 92 93 status = LE_NO_ERROR; 94 engine->getGlyphs(glyphs, 0xFF000000L, status); 95 96 if (status != LE_NO_LAYOUT_ERROR) { 97 log_err("Calling getGlyphs(glyphs, 0xFF000000L, status) on an empty layout did not return LE_NO_LAYOUT_ERROR.\n"); 98 } 99 100 status = LE_NO_ERROR; 101 engine->getCharIndices(NULL, status); 102 103 if (status != LE_ILLEGAL_ARGUMENT_ERROR) { 104 log_err("Calling getCharIndices(NULL, status) did not return LE_ILLEGAL_ARGUMENT_ERROR.\n"); 105 } 106 107 status = LE_NO_ERROR; 108 engine->getCharIndices(indices, status); 109 110 if (status != LE_NO_LAYOUT_ERROR) { 111 log_err("Calling getCharIndices(indices, status) on an empty layout did not return LE_NO_LAYOUT_ERROR.\n"); 112 } 113 114 status = LE_NO_ERROR; 115 engine->getCharIndices(NULL, 1024, status); 116 117 if (status != LE_ILLEGAL_ARGUMENT_ERROR) { 118 log_err("Calling getCharIndices(NULL, 1024, status) did not return LE_ILLEGAL_ARGUMENT_ERROR.\n"); 119 } 120 121 status = LE_NO_ERROR; 122 engine->getCharIndices(indices, 1024, status); 123 124 if (status != LE_NO_LAYOUT_ERROR) { 125 log_err("Calling getCharIndices(indices, 1024, status) on an empty layout did not return LE_NO_LAYOUT_ERROR.\n"); 126 } 127 128 status = LE_NO_ERROR; 129 engine->getGlyphPositions(NULL, status); 130 131 if (status != LE_ILLEGAL_ARGUMENT_ERROR) { 132 log_err("Calling getGlyphPositions(NULL, status) did not return LE_ILLEGAL_ARGUMENT_ERROR.\n"); 133 } 134 135 status = LE_NO_ERROR; 136 engine->getGlyphPositions(positions, status); 137 138 if (status != LE_NO_LAYOUT_ERROR) { 139 log_err("Calling getGlyphPositions(positions, status) on an empty layout did not return LE_NO_LAYOUT_ERROR.\n"); 140 } 141 142 DELETE_ARRAY(positions); 143 DELETE_ARRAY(indices); 144 DELETE_ARRAY(glyphs); 145 146 status = LE_NO_ERROR; 147 glyphCount = engine->layoutChars(NULL, 0, 0, 0, FALSE, 0.0, 0.0, status); 148 149 if (status != LE_ILLEGAL_ARGUMENT_ERROR) { 150 log_err("Calling layoutChars(NULL, 0, 0, 0, FALSE, 0.0, 0.0, status) did not fail w/ LE_ILLEGAL_ARGUMENT_ERROR.\n"); 151 } 152 153 LEUnicode chars[] = { 154 0x0045, 0x006E, 0x0067, 0x006C, 0x0069, 0x0073, 0x0068, 0x0020, // "English " 155 0x0645, 0x0627, 0x0646, 0x062A, 0x0648, 0x0634, // MEM ALIF KAF NOON TEH WAW SHEEN 156 0x0020, 0x0074, 0x0065, 0x0078, 0x0074, 0x02E // " text." 157 }; 158 159 status = LE_NO_ERROR; 160 glyphCount = engine->layoutChars(chars, -1, 6, 20, TRUE, 0.0, 0.0, status); 161 162 if (status != LE_ILLEGAL_ARGUMENT_ERROR) { 163 log_err("Calling layoutChars(chars, -1, 6, 20, TRUE, 0.0, 0.0, status) did not fail w/ LE_ILLEGAL_ARGUMENT_ERROR.\n"); 164 } 165 166 status = LE_NO_ERROR; 167 glyphCount = engine->layoutChars(chars, 8, -1, 20, TRUE, 0.0, 0.0, status); 168 169 if (status != LE_ILLEGAL_ARGUMENT_ERROR) { 170 log_err("Calling layoutChars(chars, 8, -1, 20, TRUE, 0.0, 0.0, status) did not fail w/ LE_ILLEGAL_ARGUMENT_ERROR.\n"); 171 } 172 173 status = LE_NO_ERROR; 174 glyphCount = engine->layoutChars(chars, 8, 6, -1, TRUE, 0.0, 0.0, status); 175 176 if (status != LE_ILLEGAL_ARGUMENT_ERROR) { 177 log_err("Calling layoutChars((chars, 8, 6, -1, TRUE, 0.0, 0.0, status) did not fail w/ LE_ILLEGAL_ARGUMENT_ERROR.\n"); 178 } 179 180 status = LE_NO_ERROR; 181 glyphCount = engine->layoutChars(chars, 8, 6, 10, TRUE, 0.0, 0.0, status); 182 183 if (status != LE_ILLEGAL_ARGUMENT_ERROR) { 184 log_err("Calling layoutChars(chars, 8, 6, 10, TRUE, 0.0, 0.0, status) did not fail w/ LE_ILLEGAL_ARGUMENT_ERROR.\n"); 185 } 186 187 float x = 0.0, y = 0.0; 188 189 status = LE_NO_ERROR; 190 glyphCount = engine->layoutChars(chars, 8, 6, 20, TRUE, 0.0, 0.0, status); 191 192 if (LE_FAILURE(status)) { 193 log_err("Calling layoutChars(chars, 8, 6, 20, TRUE, 0.0, 0.0, status) failed.\n"); 194 goto bail; 195 } 196 197 engine->getGlyphPosition(-1, x, y, status); 198 199 if (status != LE_INDEX_OUT_OF_BOUNDS_ERROR) { 200 log_err("Calling getGlyphPosition(-1, x, y, status) did not fail w/ LE_INDEX_OUT_OF_BOUNDS_ERROR.\n"); 201 } 202 203 status = LE_NO_ERROR; 204 engine->getGlyphPosition(glyphCount + 1, x, y, status); 205 206 if (status != LE_INDEX_OUT_OF_BOUNDS_ERROR) { 207 log_err("Calling getGlyphPosition(glyphCount + 1, x, y, status) did not fail w/ LE_INDEX_OUT_OF_BOUNDS_ERROR.\n"); 208 } 209 210 bail: 211 delete engine; 212 delete font; 213 } 214 U_CDECL_END 215 216 U_CDECL_BEGIN 217 static void U_CALLCONV FactoryTest(void) 218 { 219 LEErrorCode status = LE_NO_ERROR; 220 SimpleFontInstance *font = new SimpleFontInstance(12, status); 221 LayoutEngine *engine = NULL; 222 223 for(le_int32 scriptCode = 0; scriptCode < scriptCodeCount; scriptCode += 1) { 224 status = LE_NO_ERROR; 225 engine = LayoutEngine::layoutEngineFactory(font, scriptCode, -1, status); 226 227 if (LE_FAILURE(status)) { 228 log_err("Could not create a LayoutEngine for script \'%s\'.\n", uscript_getShortName((UScriptCode)scriptCode)); 229 } 230 231 delete engine; 232 } 233 234 delete font; 235 } 236 U_CDECL_END 237 238 U_CDECL_BEGIN 239 static void U_CALLCONV AccessTest(void) 240 { 241 LEErrorCode status = LE_NO_ERROR; 242 SimpleFontInstance *font = new SimpleFontInstance(12, status); 243 LayoutEngine *engine = LayoutEngine::layoutEngineFactory(font, arabScriptCode, -1, status); 244 le_int32 glyphCount; 245 LEGlyphID glyphs[6], extraBitGlyphs[6];; 246 le_int32 biasedIndices[6], indices[6], glyph; 247 float positions[6 * 2 + 2]; 248 LEUnicode chars[] = { 249 0x0045, 0x006E, 0x0067, 0x006C, 0x0069, 0x0073, 0x0068, 0x0020, // "English " 250 0x0645, 0x0627, 0x0646, 0x062A, 0x0648, 0x0634, // MEM ALIF KAF NOON TEH WAW SHEEN 251 0x0020, 0x0074, 0x0065, 0x0078, 0x0074, 0x02E // " text." 252 }; 253 254 if (LE_FAILURE(status)) { 255 log_err("Could not create LayoutEngine.\n"); 256 goto bail; 257 } 258 259 glyphCount = engine->layoutChars(chars, 8, 6, 20, TRUE, 0.0, 0.0, status); 260 261 if (LE_FAILURE(status) || glyphCount != 6) { 262 log_err("layoutChars(chars, 8, 6, 20, TRUE, 0.0, 0.0, status) failed.\n"); 263 goto bail; 264 } 265 266 engine->getGlyphs(glyphs, status); 267 engine->getCharIndices(indices, status); 268 engine->getGlyphPositions(positions, status); 269 270 if (LE_FAILURE(status)) { 271 log_err("Could not get glyph, indices and position arrays.\n"); 272 goto bail; 273 } 274 275 engine->getGlyphs(extraBitGlyphs, 0xFF000000L, status); 276 277 if (LE_FAILURE(status)) { 278 log_err("getGlyphs(extraBitGlyphs, 0xFF000000L, status); failed.\n"); 279 } else { 280 for(glyph = 0; glyph < glyphCount; glyph += 1) { 281 if (extraBitGlyphs[glyph] != (glyphs[glyph] | 0xFF000000L)) { 282 log_err("extraBigGlyphs[%d] != glyphs[%d] | 0xFF000000L: %8X, %8X\n", 283 glyph, glyph, extraBitGlyphs[glyph], glyphs[glyph]); 284 break; 285 } 286 } 287 } 288 289 status = LE_NO_ERROR; 290 engine->getCharIndices(biasedIndices, 1024, status); 291 292 if (LE_FAILURE(status)) { 293 log_err("getCharIndices(biasedIndices, 1024, status) failed.\n"); 294 } else { 295 for (glyph = 0; glyph < glyphCount; glyph += 1) { 296 if (biasedIndices[glyph] != (indices[glyph] + 1024)) { 297 log_err("biasedIndices[%d] != indices[%d] + 1024: %8X, %8X\n", 298 glyph, glyph, biasedIndices[glyph], indices[glyph]); 299 break; 300 } 301 } 302 } 303 304 status = LE_NO_ERROR; 305 for (glyph = 0; glyph <= glyphCount; glyph += 1) { 306 float x = 0.0, y = 0.0; 307 308 engine->getGlyphPosition(glyph, x, y, status); 309 310 if (LE_FAILURE(status)) { 311 log_err("getGlyphPosition(%d, x, y, status) failed.\n", glyph); 312 break; 313 } 314 315 if (x != positions[glyph*2] || y != positions[glyph*2 + 1]) { 316 log_err("getGlyphPosition(%d, x, y, status) returned bad position: (%f, %f) != (%f, %f)\n", 317 glyph, x, y, positions[glyph*2], positions[glyph*2 + 1]); 318 break; 319 } 320 } 321 322 bail: 323 delete engine; 324 delete font; 325 } 326 U_CDECL_END 327 328 le_bool compareResults(const char *testID, TestResult *expected, TestResult *actual) 329 { 330 /* NOTE: we'll stop on the first failure 'cause once there's one error, it may cascade... */ 331 if (actual->glyphCount != expected->glyphCount) { 332 log_err("Test %s: incorrect glyph count: exptected %d, got %d\n", 333 testID, expected->glyphCount, actual->glyphCount); 334 return FALSE; 335 } 336 337 le_int32 i; 338 339 for (i = 0; i < actual->glyphCount; i += 1) { 340 if (actual->glyphs[i] != expected->glyphs[i]) { 341 log_err("Test %s: incorrect id for glyph %d: expected %4X, got %4X\n", 342 testID, i, expected->glyphs[i], actual->glyphs[i]); 343 return FALSE; 344 } 345 } 346 347 for (i = 0; i < actual->glyphCount; i += 1) { 348 if (actual->indices[i] != expected->indices[i]) { 349 log_err("Test %s: incorrect index for glyph %d: expected %8X, got %8X\n", 350 testID, i, expected->indices[i], actual->indices[i]); 351 return FALSE; 352 } 353 } 354 355 for (i = 0; i <= actual->glyphCount; i += 1) { 356 double xError = uprv_fabs(actual->positions[i * 2] - expected->positions[i * 2]); 357 358 if (xError > 0.0001) { 359 log_err("Test %s: incorrect x position for glyph %d: expected %f, got %f\n", 360 testID, i, expected->positions[i * 2], actual->positions[i * 2]); 361 return FALSE; 362 } 363 364 double yError = uprv_fabs(actual->positions[i * 2 + 1] - expected->positions[i * 2 + 1]); 365 366 if (yError < 0) { 367 yError = -yError; 368 } 369 370 if (yError > 0.0001) { 371 log_err("Test %s: incorrect y position for glyph %d: expected %f, got %f\n", 372 testID, i, expected->positions[i * 2 + 1], actual->positions[i * 2 + 1]); 373 return FALSE; 374 } 375 } 376 377 return TRUE; 378 } 379 380 static void checkFontVersion(PortableFontInstance *fontInstance, const char *testVersionString, 381 le_uint32 testChecksum, const char *testID) 382 { 383 le_uint32 fontChecksum = fontInstance->getFontChecksum(); 384 385 if (fontChecksum != testChecksum) { 386 const char *fontVersionString = fontInstance->getNameString(NAME_VERSION_STRING, 387 PLATFORM_MACINTOSH, MACINTOSH_ROMAN, MACINTOSH_ENGLISH); 388 const LEUnicode *uFontVersionString = NULL; 389 390 // The standard recommends that the Macintosh Roman/English name string be present, but 391 // if it's not, try the Microsoft Unicode/English string. 392 if (fontVersionString == NULL) { 393 uFontVersionString = fontInstance->getUnicodeNameString(NAME_VERSION_STRING, 394 PLATFORM_MICROSOFT, MICROSOFT_UNICODE_BMP, MICROSOFT_ENGLISH); 395 } 396 397 log_info("Test %s: this may not be the same font used to generate the test data.\n", testID); 398 399 if (uFontVersionString != NULL) { 400 log_info("Your font's version string is \"%S\"\n", uFontVersionString); 401 fontInstance->deleteNameString(uFontVersionString); 402 } else { 403 log_info("Your font's version string is \"%s\"\n", fontVersionString); 404 fontInstance->deleteNameString(fontVersionString); 405 } 406 407 log_info("The expected version string is \"%s\"\n", testVersionString); 408 log_info("If you see errors, they may be due to the version of the font you're using.\n"); 409 } 410 } 411 412 /* Returns the path to icu/source/test/testdata/ */ 413 const char *getSourceTestData() { 414 const char *srcDataDir = NULL; 415 #ifdef U_TOPSRCDIR 416 srcDataDir = U_TOPSRCDIR U_FILE_SEP_STRING "test" U_FILE_SEP_STRING "testdata" U_FILE_SEP_STRING; 417 #else 418 srcDataDir = ".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING"test"U_FILE_SEP_STRING"testdata"U_FILE_SEP_STRING; 419 FILE *f = fopen(".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING"test"U_FILE_SEP_STRING"testdata"U_FILE_SEP_STRING"rbbitst.txt", "r"); 420 421 if (f != NULL) { 422 /* We're in icu/source/test/letest/ */ 423 fclose(f); 424 } else { 425 /* We're in icu/source/test/letest/(Debug|Release) */ 426 srcDataDir = ".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING"test"U_FILE_SEP_STRING"testdata"U_FILE_SEP_STRING; 427 } 428 #endif 429 430 return srcDataDir; 431 } 432 433 const char *getPath(char buffer[2048], const char *filename) { 434 const char *testDataDirectory = getSourceTestData(); 435 436 strcpy(buffer, testDataDirectory); 437 strcat(buffer, filename); 438 439 return buffer; 440 } 441 442 le_uint32 *getHexArray(const UnicodeString &numbers, int32_t &arraySize) 443 { 444 int32_t offset = -1; 445 446 arraySize = 1; 447 while((offset = numbers.indexOf(CH_COMMA, offset + 1)) >= 0) { 448 arraySize += 1; 449 } 450 451 le_uint32 *array = NEW_ARRAY(le_uint32, arraySize); 452 char number[16]; 453 le_int32 count = 0; 454 le_int32 start = 0, end = 0; 455 le_int32 len = 0; 456 457 // trim leading whitespace 458 while(u_isUWhiteSpace(numbers[start])) { 459 start += 1; 460 } 461 462 while((end = numbers.indexOf(CH_COMMA, start)) >= 0) { 463 len = numbers.extract(start, end - start, number, ARRAY_SIZE(number), US_INV); 464 number[len] = '\0'; 465 start = end + 1; 466 467 sscanf(number, "%x", &array[count++]); 468 469 // trim whitespace following the comma 470 while(u_isUWhiteSpace(numbers[start])) { 471 start += 1; 472 } 473 } 474 475 // trim trailing whitespace 476 end = numbers.length(); 477 while(u_isUWhiteSpace(numbers[end - 1])) { 478 end -= 1; 479 } 480 481 len = numbers.extract(start, end - start, number, ARRAY_SIZE(number), US_INV); 482 number[len] = '\0'; 483 sscanf(number, "%x", &array[count]); 484 485 return array; 486 } 487 488 float *getFloatArray(const UnicodeString &numbers, int32_t &arraySize) 489 { 490 int32_t offset = -1; 491 492 arraySize = 1; 493 while((offset = numbers.indexOf(CH_COMMA, offset + 1)) >= 0) { 494 arraySize += 1; 495 } 496 497 float *array = NEW_ARRAY(float, arraySize); 498 char number[32]; 499 le_int32 count = 0; 500 le_int32 start = 0, end = 0; 501 le_int32 len = 0; 502 503 // trim leading whitespace 504 while(u_isUWhiteSpace(numbers[start])) { 505 start += 1; 506 } 507 508 while((end = numbers.indexOf(CH_COMMA, start)) >= 0) { 509 len = numbers.extract(start, end - start, number, ARRAY_SIZE(number), US_INV); 510 number[len] = '\0'; 511 start = end + 1; 512 513 sscanf(number, "%f", &array[count++]); 514 515 // trim whiteapce following the comma 516 while(u_isUWhiteSpace(numbers[start])) { 517 start += 1; 518 } 519 } 520 521 while(u_isUWhiteSpace(numbers[start])) { 522 start += 1; 523 } 524 525 // trim trailing whitespace 526 end = numbers.length(); 527 while(u_isUWhiteSpace(numbers[end - 1])) { 528 end -= 1; 529 } 530 531 len = numbers.extract(start, end - start, number, ARRAY_SIZE(number), US_INV); 532 number[len] = '\0'; 533 sscanf(number, "%f", &array[count]); 534 535 return array; 536 } 537 538 LEFontInstance *openFont(const char *fontName, const char *checksum, const char *version, const char *testID) 539 { 540 char path[2048]; 541 PortableFontInstance *font; 542 LEErrorCode fontStatus = LE_NO_ERROR; 543 544 545 font = new PortableFontInstance(getPath(path, fontName), 12, fontStatus); 546 547 if (LE_FAILURE(fontStatus)) { 548 log_info("Test %s: can't open font %s - test skipped.\n", testID, fontName); 549 delete font; 550 return NULL; 551 } else { 552 le_uint32 cksum = 0; 553 554 sscanf(checksum, "%x", &cksum); 555 556 checkFontVersion(font, version, cksum, testID); 557 } 558 559 return font; 560 } 561 562 U_CDECL_BEGIN 563 static void U_CALLCONV DataDrivenTest(void) 564 { 565 #if !UCONFIG_NO_REGULAR_EXPRESSIONS 566 UErrorCode status = U_ZERO_ERROR; 567 char path[2048]; 568 const char *testFilePath = getPath(path, "letest.xml"); 569 570 UXMLParser *parser = UXMLParser::createParser(status); 571 UXMLElement *root = parser->parseFile(testFilePath, status); 572 573 if (root == NULL) { 574 log_err("Could not open the test data file: %s\n", testFilePath); 575 delete parser; 576 return; 577 } 578 579 UnicodeString test_case = UNICODE_STRING_SIMPLE("test-case"); 580 UnicodeString test_text = UNICODE_STRING_SIMPLE("test-text"); 581 UnicodeString test_font = UNICODE_STRING_SIMPLE("test-font"); 582 UnicodeString result_glyphs = UNICODE_STRING_SIMPLE("result-glyphs"); 583 UnicodeString result_indices = UNICODE_STRING_SIMPLE("result-indices"); 584 UnicodeString result_positions = UNICODE_STRING_SIMPLE("result-positions"); 585 586 // test-case attributes 587 UnicodeString id_attr = UNICODE_STRING_SIMPLE("id"); 588 UnicodeString script_attr = UNICODE_STRING_SIMPLE("script"); 589 UnicodeString lang_attr = UNICODE_STRING_SIMPLE("lang"); 590 591 // test-font attributes 592 UnicodeString name_attr = UNICODE_STRING_SIMPLE("name"); 593 UnicodeString ver_attr = UNICODE_STRING_SIMPLE("version"); 594 UnicodeString cksum_attr = UNICODE_STRING_SIMPLE("checksum"); 595 596 const UXMLElement *testCase; 597 int32_t tc = 0; 598 599 while((testCase = root->nextChildElement(tc)) != NULL) { 600 if (testCase->getTagName().compare(test_case) == 0) { 601 char *id = getCString(testCase->getAttribute(id_attr)); 602 char *script = getCString(testCase->getAttribute(script_attr)); 603 char *lang = getCString(testCase->getAttribute(lang_attr)); 604 LEFontInstance *font = NULL; 605 const UXMLElement *element; 606 int32_t ec = 0; 607 int32_t charCount = 0; 608 int32_t typoFlags = 3; // kerning + ligatures... 609 UScriptCode scriptCode; 610 le_int32 languageCode = -1; 611 UnicodeString text, glyphs, indices, positions; 612 int32_t glyphCount = 0, indexCount = 0, positionCount = 0; 613 TestResult expected = {0, NULL, NULL, NULL}; 614 TestResult actual = {0, NULL, NULL, NULL}; 615 LEErrorCode success = LE_NO_ERROR; 616 LayoutEngine *engine = NULL; 617 618 uscript_getCode(script, &scriptCode, 1, &status); 619 if (LE_FAILURE(status)) { 620 log_err("invalid script name: %s.\n", script); 621 goto free_c_strings; 622 } 623 624 if (lang != NULL) { 625 languageCode = getLanguageCode(lang); 626 627 if (languageCode < 0) { 628 log_err("invalid language name: %s.\n", lang); 629 goto free_c_strings; 630 } 631 } 632 633 while((element = testCase->nextChildElement(ec)) != NULL) { 634 UnicodeString tag = element->getTagName(); 635 636 // TODO: make sure that each element is only used once. 637 if (tag.compare(test_font) == 0) { 638 char *fontName = getCString(element->getAttribute(name_attr)); 639 char *fontVer = getCString(element->getAttribute(ver_attr)); 640 char *fontCksum = getCString(element->getAttribute(cksum_attr)); 641 642 font = openFont(fontName, fontCksum, fontVer, id); 643 freeCString(fontCksum); 644 freeCString(fontVer); 645 freeCString(fontName); 646 647 if (font == NULL) { 648 // warning message already displayed... 649 goto free_c_strings; 650 } 651 } else if (tag.compare(test_text) == 0) { 652 text = element->getText(TRUE); 653 charCount = text.length(); 654 } else if (tag.compare(result_glyphs) == 0) { 655 glyphs = element->getText(TRUE); 656 } else if (tag.compare(result_indices) == 0) { 657 indices = element->getText(TRUE); 658 } else if (tag.compare(result_positions) == 0) { 659 positions = element->getText(TRUE); 660 } else { 661 // an unknown tag... 662 char *cTag = getCString(&tag); 663 664 log_info("Test %s: unknown element with tag \"%s\"\n", id, cTag); 665 freeCString(cTag); 666 } 667 } 668 669 // TODO: make sure that the font, test-text, result-glyphs, result-indices and result-positions 670 // have all been provided 671 if (font == NULL) { 672 LEErrorCode fontStatus = LE_NO_ERROR; 673 674 font = new SimpleFontInstance(12, fontStatus); 675 typoFlags |= 0x80000000L; // use CharSubstitutionFilter... 676 } 677 678 expected.glyphs = (LEGlyphID *) getHexArray(glyphs, glyphCount); 679 expected.indices = (le_int32 *) getHexArray(indices, indexCount); 680 expected.positions = getFloatArray(positions, positionCount); 681 682 expected.glyphCount = glyphCount; 683 684 if (glyphCount < charCount || indexCount != glyphCount || positionCount < glyphCount * 2 + 2) { 685 log_err("Test %s: inconsistent input data: charCount = %d, glyphCount = %d, indexCount = %d, positionCount = %d\n", 686 id, charCount, glyphCount, indexCount, positionCount); 687 goto free_expected; 688 }; 689 690 engine = LayoutEngine::layoutEngineFactory(font, scriptCode, languageCode, typoFlags, success); 691 692 if (LE_FAILURE(success)) { 693 log_err("Test %s: could not create a LayoutEngine.\n", id); 694 goto free_expected; 695 } 696 697 actual.glyphCount = engine->layoutChars(text.getBuffer(), 0, charCount, charCount, getRTL(text), 0, 0, success); 698 699 actual.glyphs = NEW_ARRAY(LEGlyphID, actual.glyphCount); 700 actual.indices = NEW_ARRAY(le_int32, actual.glyphCount); 701 actual.positions = NEW_ARRAY(float, actual.glyphCount * 2 + 2); 702 703 engine->getGlyphs(actual.glyphs, success); 704 engine->getCharIndices(actual.indices, success); 705 engine->getGlyphPositions(actual.positions, success); 706 707 compareResults(id, &expected, &actual); 708 709 DELETE_ARRAY(actual.positions); 710 DELETE_ARRAY(actual.indices); 711 DELETE_ARRAY(actual.glyphs); 712 713 delete engine; 714 715 log_verbose("OK - %4d glyphs: %s\n", actual.glyphCount, id); 716 free_expected: 717 DELETE_ARRAY(expected.positions); 718 DELETE_ARRAY(expected.indices); 719 DELETE_ARRAY(expected.glyphs); 720 721 delete font; 722 723 free_c_strings: 724 freeCString(lang); 725 freeCString(script); 726 freeCString(id); 727 } 728 } 729 730 delete root; 731 delete parser; 732 #endif 733 } 734 U_CDECL_END 735 736 U_CDECL_BEGIN 737 /* 738 * From ticket:5923: 739 * 740 * Build a paragraph that contains a mixture of left to right and right to left text. 741 * Break it into multiple lines and make sure that the glyphToCharMap for run in each 742 * line is correct. 743 * 744 * Note: it might be a good idea to also check the glyphs and positions for each run, 745 * that we get the expected number of runs per line and that the line breaks are where 746 * we expect them to be. Really, it would be a good idea to make a whole test suite 747 * for ParagraphLayout. 748 */ 749 static void U_CALLCONV GlyphToCharTest(void) 750 { 751 LEErrorCode status = LE_NO_ERROR; 752 LEFontInstance *font; 753 FontRuns fontRuns(0); 754 ParagraphLayout *paragraphLayout; 755 const ParagraphLayout::Line *line; 756 /* 757 * This is the same text that's in <icu>/source/samples/layout/Sample.txt 758 */ 759 LEUnicode chars[] = { 760 /*BOM*/ 0x0054, 0x0068, 0x0065, 0x0020, 0x004c, 0x0061, 0x0079, 761 0x006f, 0x0075, 0x0074, 0x0045, 0x006e, 0x0067, 0x0069, 0x006e, 762 0x0065, 0x0020, 0x0064, 0x006f, 0x0065, 0x0073, 0x0020, 0x0061, 763 0x006c, 0x006c, 0x0020, 0x0074, 0x0068, 0x0065, 0x0020, 0x0077, 764 0x006f, 0x0072, 0x006b, 0x0020, 0x006e, 0x0065, 0x0063, 0x0065, 765 0x0073, 0x0073, 0x0061, 0x0072, 0x0079, 0x0020, 0x0074, 0x006f, 766 0x0020, 0x0064, 0x0069, 0x0073, 0x0070, 0x006c, 0x0061, 0x0079, 767 0x0020, 0x0055, 0x006e, 0x0069, 0x0063, 0x006f, 0x0064, 0x0065, 768 0x0020, 0x0074, 0x0065, 0x0078, 0x0074, 0x0020, 0x0077, 0x0072, 769 0x0069, 0x0074, 0x0074, 0x0065, 0x006e, 0x0020, 0x0069, 0x006e, 770 0x0020, 0x006c, 0x0061, 0x006e, 0x0067, 0x0075, 0x0061, 0x0067, 771 0x0065, 0x0073, 0x0020, 0x0077, 0x0069, 0x0074, 0x0068, 0x0020, 772 0x0063, 0x006f, 0x006d, 0x0070, 0x006c, 0x0065, 0x0078, 0x0020, 773 0x0077, 0x0072, 0x0069, 0x0074, 0x0069, 0x006e, 0x0067, 0x0020, 774 0x0073, 0x0079, 0x0073, 0x0074, 0x0065, 0x006d, 0x0073, 0x0020, 775 0x0073, 0x0075, 0x0063, 0x0068, 0x0020, 0x0061, 0x0073, 0x0020, 776 0x0048, 0x0069, 0x006e, 0x0064, 0x0069, 0x0020, 0x0028, 0x0939, 777 0x093f, 0x0928, 0x094d, 0x0926, 0x0940, 0x0029, 0x0020, 0x0054, 778 0x0068, 0x0061, 0x0069, 0x0020, 0x0028, 0x0e44, 0x0e17, 0x0e22, 779 0x0029, 0x0020, 0x0061, 0x006e, 0x0064, 0x0020, 0x0041, 0x0072, 780 0x0061, 0x0062, 0x0069, 0x0063, 0x0020, 0x0028, 0x0627, 0x0644, 781 0x0639, 0x0631, 0x0628, 0x064a, 0x0629, 0x0029, 0x002e, 0x0020, 782 0x0048, 0x0065, 0x0072, 0x0065, 0x0027, 0x0073, 0x0020, 0x0061, 783 0x0020, 0x0073, 0x0061, 0x006d, 0x0070, 0x006c, 0x0065, 0x0020, 784 0x006f, 0x0066, 0x0020, 0x0073, 0x006f, 0x006d, 0x0065, 0x0020, 785 0x0074, 0x0065, 0x0078, 0x0074, 0x0020, 0x0077, 0x0072, 0x0069, 786 0x0074, 0x0074, 0x0065, 0x006e, 0x0020, 0x0069, 0x006e, 0x0020, 787 0x0053, 0x0061, 0x006e, 0x0073, 0x006b, 0x0072, 0x0069, 0x0074, 788 0x003a, 0x0020, 0x0936, 0x094d, 0x0930, 0x0940, 0x092e, 0x0926, 789 0x094d, 0x0020, 0x092d, 0x0917, 0x0935, 0x0926, 0x094d, 0x0917, 790 0x0940, 0x0924, 0x093e, 0x0020, 0x0905, 0x0927, 0x094d, 0x092f, 791 0x093e, 0x092f, 0x0020, 0x0905, 0x0930, 0x094d, 0x091c, 0x0941, 792 0x0928, 0x0020, 0x0935, 0x093f, 0x0937, 0x093e, 0x0926, 0x0020, 793 0x092f, 0x094b, 0x0917, 0x0020, 0x0927, 0x0943, 0x0924, 0x0930, 794 0x093e, 0x0937, 0x094d, 0x091f, 0x094d, 0x0930, 0x0020, 0x0909, 795 0x0935, 0x093e, 0x091a, 0x0964, 0x0020, 0x0927, 0x0930, 0x094d, 796 0x092e, 0x0915, 0x094d, 0x0937, 0x0947, 0x0924, 0x094d, 0x0930, 797 0x0947, 0x0020, 0x0915, 0x0941, 0x0930, 0x0941, 0x0915, 0x094d, 798 0x0937, 0x0947, 0x0924, 0x094d, 0x0930, 0x0947, 0x0020, 0x0938, 799 0x092e, 0x0935, 0x0947, 0x0924, 0x093e, 0x0020, 0x092f, 0x0941, 800 0x092f, 0x0941, 0x0924, 0x094d, 0x0938, 0x0935, 0x0903, 0x0020, 801 0x092e, 0x093e, 0x092e, 0x0915, 0x093e, 0x0903, 0x0020, 0x092a, 802 0x093e, 0x0923, 0x094d, 0x0921, 0x0935, 0x093e, 0x0936, 0x094d, 803 0x091a, 0x0948, 0x0935, 0x0020, 0x0915, 0x093f, 0x092e, 0x0915, 804 0x0941, 0x0930, 0x094d, 0x0935, 0x0924, 0x0020, 0x0938, 0x0902, 805 0x091c, 0x092f, 0x0020, 0x0048, 0x0065, 0x0072, 0x0065, 0x0027, 806 0x0073, 0x0020, 0x0061, 0x0020, 0x0073, 0x0061, 0x006d, 0x0070, 807 0x006c, 0x0065, 0x0020, 0x006f, 0x0066, 0x0020, 0x0073, 0x006f, 808 0x006d, 0x0065, 0x0020, 0x0074, 0x0065, 0x0078, 0x0074, 0x0020, 809 0x0077, 0x0072, 0x0069, 0x0074, 0x0074, 0x0065, 0x006e, 0x0020, 810 0x0069, 0x006e, 0x0020, 0x0041, 0x0072, 0x0061, 0x0062, 0x0069, 811 0x0063, 0x003a, 0x0020, 0x0623, 0x0633, 0x0627, 0x0633, 0x064b, 812 0x0627, 0x060c, 0x0020, 0x062a, 0x062a, 0x0639, 0x0627, 0x0645, 813 0x0644, 0x0020, 0x0627, 0x0644, 0x062d, 0x0648, 0x0627, 0x0633, 814 0x064a, 0x0628, 0x0020, 0x0641, 0x0642, 0x0637, 0x0020, 0x0645, 815 0x0639, 0x0020, 0x0627, 0x0644, 0x0623, 0x0631, 0x0642, 0x0627, 816 0x0645, 0x060c, 0x0020, 0x0648, 0x062a, 0x0642, 0x0648, 0x0645, 817 0x0020, 0x0628, 0x062a, 0x062e, 0x0632, 0x064a, 0x0646, 0x0020, 818 0x0627, 0x0644, 0x0623, 0x062d, 0x0631, 0x0641, 0x0020, 0x0648, 819 0x0627, 0x0644, 0x0645, 0x062d, 0x0627, 0x0631, 0x0641, 0x0020, 820 0x0627, 0x0644, 0x0623, 0x062e, 0x0631, 0x0649, 0x0020, 0x0628, 821 0x0639, 0x062f, 0x0020, 0x0623, 0x0646, 0x0020, 0x062a, 0x064f, 822 0x0639, 0x0637, 0x064a, 0x0020, 0x0631, 0x0642, 0x0645, 0x0627, 823 0x0020, 0x0645, 0x0639, 0x064a, 0x0646, 0x0627, 0x0020, 0x0644, 824 0x0643, 0x0644, 0x0020, 0x0648, 0x0627, 0x062d, 0x062f, 0x0020, 825 0x0645, 0x0646, 0x0647, 0x0627, 0x002e, 0x0020, 0x0648, 0x0642, 826 0x0628, 0x0644, 0x0020, 0x0627, 0x062e, 0x062a, 0x0631, 0x0627, 827 0x0639, 0x0020, 0x0022, 0x064a, 0x0648, 0x0646, 0x0650, 0x0643, 828 0x0648, 0x062f, 0x0022, 0x060c, 0x0020, 0x0643, 0x0627, 0x0646, 829 0x0020, 0x0647, 0x0646, 0x0627, 0x0643, 0x0020, 0x0645, 0x0626, 830 0x0627, 0x062a, 0x0020, 0x0627, 0x0644, 0x0623, 0x0646, 0x0638, 831 0x0645, 0x0629, 0x0020, 0x0644, 0x0644, 0x062a, 0x0634, 0x0641, 832 0x064a, 0x0631, 0x0020, 0x0648, 0x062a, 0x062e, 0x0635, 0x064a, 833 0x0635, 0x0020, 0x0647, 0x0630, 0x0647, 0x0020, 0x0627, 0x0644, 834 0x0623, 0x0631, 0x0642, 0x0627, 0x0645, 0x0020, 0x0644, 0x0644, 835 0x0645, 0x062d, 0x0627, 0x0631, 0x0641, 0x060c, 0x0020, 0x0648, 836 0x0644, 0x0645, 0x0020, 0x064a, 0x0648, 0x062c, 0x062f, 0x0020, 837 0x0646, 0x0638, 0x0627, 0x0645, 0x0020, 0x062a, 0x0634, 0x0641, 838 0x064a, 0x0631, 0x0020, 0x0648, 0x0627, 0x062d, 0x062f, 0x0020, 839 0x064a, 0x062d, 0x062a, 0x0648, 0x064a, 0x0020, 0x0639, 0x0644, 840 0x0649, 0x0020, 0x062c, 0x0645, 0x064a, 0x0639, 0x0020, 0x0627, 841 0x0644, 0x0645, 0x062d, 0x0627, 0x0631, 0x0641, 0x0020, 0x0627, 842 0x0644, 0x0636, 0x0631, 0x0648, 0x0631, 0x064a, 0x0629, 0x0020, 843 0x0061, 0x006e, 0x0064, 0x0020, 0x0068, 0x0065, 0x0072, 0x0065, 844 0x0027, 0x0073, 0x0020, 0x0061, 0x0020, 0x0073, 0x0061, 0x006d, 845 0x0070, 0x006c, 0x0065, 0x0020, 0x006f, 0x0066, 0x0020, 0x0073, 846 0x006f, 0x006d, 0x0065, 0x0020, 0x0074, 0x0065, 0x0078, 0x0074, 847 0x0020, 0x0077, 0x0072, 0x0069, 0x0074, 0x0074, 0x0065, 0x006e, 848 0x0020, 0x0069, 0x006e, 0x0020, 0x0054, 0x0068, 0x0061, 0x0069, 849 0x003a, 0x0020, 0x0e1a, 0x0e17, 0x0e17, 0x0e35, 0x0e48, 0x0e51, 850 0x0e1e, 0x0e32, 0x0e22, 0x0e38, 0x0e44, 0x0e0b, 0x0e42, 0x0e04, 851 0x0e25, 0x0e19, 0x0e42, 0x0e14, 0x0e42, 0x0e23, 0x0e18, 0x0e35, 852 0x0e2d, 0x0e32, 0x0e28, 0x0e31, 0x0e22, 0x0e2d, 0x0e22, 0x0e39, 853 0x0e48, 0x0e17, 0x0e48, 0x0e32, 0x0e21, 0x0e01, 0x0e25, 0x0e32, 854 0x0e07, 0x0e17, 0x0e38, 0x0e48, 0x0e07, 0x0e43, 0x0e2b, 0x0e0d, 855 0x0e48, 0x0e43, 0x0e19, 0x0e41, 0x0e04, 0x0e19, 0x0e0b, 0x0e31, 856 0x0e2a, 0x0e01, 0x0e31, 0x0e1a, 0x0e25, 0x0e38, 0x0e07, 0x0e40, 857 0x0e2e, 0x0e19, 0x0e23, 0x0e35, 0x0e0a, 0x0e32, 0x0e27, 0x0e44, 858 0x0e23, 0x0e48, 0x0e41, 0x0e25, 0x0e30, 0x0e1b, 0x0e49, 0x0e32, 859 0x0e40, 0x0e2d, 0x0e47, 0x0e21, 0x0e20, 0x0e23, 0x0e23, 0x0e22, 860 0x0e32, 0x0e0a, 0x0e32, 0x0e27, 0x0e44, 0x0e23, 0x0e48, 0x0e1a, 861 0x0e49, 0x0e32, 0x0e19, 0x0e02, 0x0e2d, 0x0e07, 0x0e1e, 0x0e27, 862 0x0e01, 0x0e40, 0x0e02, 0x0e32, 0x0e2b, 0x0e25, 0x0e31, 0x0e07, 863 0x0e40, 0x0e25, 0x0e47, 0x0e01, 0x0e40, 0x0e1e, 0x0e23, 0x0e32, 864 0x0e30, 0x0e44, 0x0e21, 0x0e49, 0x0e2a, 0x0e23, 0x0e49, 0x0e32, 865 0x0e07, 0x0e1a, 0x0e49, 0x0e32, 0x0e19, 0x0e15, 0x0e49, 0x0e2d, 866 0x0e07, 0x0e02, 0x0e19, 0x0e21, 0x0e32, 0x0e14, 0x0e49, 0x0e27, 867 0x0e22, 0x0e40, 0x0e01, 0x0e27, 0x0e35, 0x0e22, 0x0e19, 0x0e40, 868 0x0e1b, 0x0e47, 0x0e19, 0x0e23, 0x0e30, 0x0e22, 0x0e30, 0x0e17, 869 0x0e32, 0x0e07, 0x0e2b, 0x0e25, 0x0e32, 0x0e22, 0x0e44, 0x0e21, 870 0x0e25, 0x0e4c 871 }; 872 le_int32 charCount = LE_ARRAY_SIZE(chars); 873 le_int32 charIndex = 0, lineNumber = 1; 874 const float lineWidth = 600; 875 876 font = new SimpleFontInstance(12, status); 877 878 if (LE_FAILURE(status)) { 879 goto finish; 880 } 881 882 fontRuns.add(font, charCount); 883 884 paragraphLayout = new ParagraphLayout(chars, charCount, &fontRuns, NULL, NULL, NULL, 0, FALSE, status); 885 886 if (LE_FAILURE(status)) { 887 goto close_font; 888 } 889 890 paragraphLayout->reflow(); 891 while ((line = paragraphLayout->nextLine(lineWidth)) != NULL) { 892 le_int32 runCount = line->countRuns(); 893 894 for(le_int32 run = 0; run < runCount; run += 1) { 895 const ParagraphLayout::VisualRun *visualRun = line->getVisualRun(run); 896 le_int32 glyphCount = visualRun->getGlyphCount(); 897 const le_int32 *glyphToCharMap = visualRun->getGlyphToCharMap(); 898 899 if (visualRun->getDirection() == UBIDI_RTL) { 900 /* 901 * For a right to left run, make sure that the character indices 902 * increase from the right most glyph to the left most glyph. If 903 * there are any one to many glyph substitutions, we might get several 904 * glyphs in a row with the same character index. 905 */ 906 for(le_int32 i = glyphCount - 1; i >= 0; i -= 1) { 907 le_int32 ix = glyphToCharMap[i]; 908 909 if (ix != charIndex) { 910 if (ix != charIndex - 1) { 911 log_err("Bad glyph to char index for glyph %d on line %d: expected %d, got %d\n", 912 i, lineNumber, charIndex, ix); 913 goto close_paragraph; // once there's one error, we can't count on anything else... 914 } 915 } else { 916 charIndex += 1; 917 } 918 } 919 } else { 920 /* 921 * We can't just check the order of the character indices 922 * for left to right runs because Indic text might have been 923 * reordered. What we can do is find the minimum and maximum 924 * character indices in the run and make sure that the minimum 925 * is equal to charIndex and then advance charIndex to the maximum. 926 */ 927 le_int32 minIndex = 0x7FFFFFFF, maxIndex = -1; 928 929 for(le_int32 i = 0; i < glyphCount; i += 1) { 930 le_int32 ix = glyphToCharMap[i]; 931 932 if (ix > maxIndex) { 933 maxIndex = ix; 934 } 935 936 if (ix < minIndex) { 937 minIndex = ix; 938 } 939 } 940 941 if (minIndex != charIndex) { 942 log_err("Bad minIndex for run %d on line %d: expected %d, got %d\n", 943 run, lineNumber, charIndex, minIndex); 944 goto close_paragraph; // once there's one error, we can't count on anything else... 945 } 946 947 charIndex = maxIndex + 1; 948 } 949 } 950 951 lineNumber += 1; 952 } 953 close_paragraph: 954 delete paragraphLayout; 955 956 close_font: 957 delete font; 958 959 finish: 960 return; 961 } 962 U_CDECL_END 963 964 static void addAllTests(TestNode **root) 965 { 966 addTest(root, &ScriptTest, "api/ScriptTest"); 967 addTest(root, &ParamTest, "api/ParameterTest"); 968 addTest(root, &FactoryTest, "api/FactoryTest"); 969 addTest(root, &AccessTest, "layout/AccessTest"); 970 addTest(root, &DataDrivenTest, "layout/DataDrivenTest"); 971 addTest(root, &GlyphToCharTest, "paragraph/GlyphToCharTest"); 972 973 addCTests(root); 974 } 975 976 /* returns the path to icu/source/data/out */ 977 static const char *ctest_dataOutDir() 978 { 979 static const char *dataOutDir = NULL; 980 981 if(dataOutDir) { 982 return dataOutDir; 983 } 984 985 /* U_TOPBUILDDIR is set by the makefiles on UNIXes when building cintltst and intltst 986 // to point to the top of the build hierarchy, which may or 987 // may not be the same as the source directory, depending on 988 // the configure options used. At any rate, 989 // set the data path to the built data from this directory. 990 // The value is complete with quotes, so it can be used 991 // as-is as a string constant. 992 */ 993 #if defined (U_TOPBUILDDIR) 994 { 995 dataOutDir = U_TOPBUILDDIR "data" U_FILE_SEP_STRING "out" U_FILE_SEP_STRING; 996 } 997 #else 998 999 /* On Windows, the file name obtained from __FILE__ includes a full path. 1000 * This file is "wherever\icu\source\test\cintltst\cintltst.c" 1001 * Change to "wherever\icu\source\data" 1002 */ 1003 { 1004 static char p[sizeof(__FILE__) + 20]; 1005 char *pBackSlash; 1006 int i; 1007 1008 strcpy(p, __FILE__); 1009 /* We want to back over three '\' chars. */ 1010 /* Only Windows should end up here, so looking for '\' is safe. */ 1011 for (i=1; i<=3; i++) { 1012 pBackSlash = strrchr(p, U_FILE_SEP_CHAR); 1013 if (pBackSlash != NULL) { 1014 *pBackSlash = 0; /* Truncate the string at the '\' */ 1015 } 1016 } 1017 1018 if (pBackSlash != NULL) { 1019 /* We found and truncated three names from the path. 1020 * Now append "source\data" and set the environment 1021 */ 1022 strcpy(pBackSlash, U_FILE_SEP_STRING "data" U_FILE_SEP_STRING "out" U_FILE_SEP_STRING); 1023 dataOutDir = p; 1024 } 1025 else { 1026 /* __FILE__ on MSVC7 does not contain the directory */ 1027 FILE *file = fopen(".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING "data" U_FILE_SEP_STRING "Makefile.in", "r"); 1028 if (file) { 1029 fclose(file); 1030 dataOutDir = ".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING "data" U_FILE_SEP_STRING "out" U_FILE_SEP_STRING; 1031 } 1032 else { 1033 dataOutDir = ".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING "data" U_FILE_SEP_STRING "out" U_FILE_SEP_STRING; 1034 } 1035 } 1036 } 1037 #endif 1038 1039 return dataOutDir; 1040 } 1041 1042 /* ctest_setICU_DATA - if the ICU_DATA environment variable is not already 1043 * set, try to deduce the directory in which ICU was built, 1044 * and set ICU_DATA to "icu/source/data" in that location. 1045 * The intent is to allow the tests to have a good chance 1046 * of running without requiring that the user manually set 1047 * ICU_DATA. Common data isn't a problem, since it is 1048 * picked up via a static (build time) reference, but the 1049 * tests dynamically load some data. 1050 */ 1051 static void ctest_setICU_DATA() { 1052 1053 /* No location for the data dir was identifiable. 1054 * Add other fallbacks for the test data location here if the need arises 1055 */ 1056 if (getenv("ICU_DATA") == NULL) { 1057 /* If ICU_DATA isn't set, set it to the usual location */ 1058 u_setDataDirectory(ctest_dataOutDir()); 1059 } 1060 } 1061 1062 int main(int argc, char* argv[]) 1063 { 1064 int32_t nerrors = 0; 1065 TestNode *root = NULL; 1066 UErrorCode errorCode = U_ZERO_ERROR; 1067 UDate startTime, endTime; 1068 int32_t diffTime; 1069 1070 startTime = uprv_getUTCtime(); 1071 1072 if (!initArgs(argc, argv, NULL, NULL)) { 1073 /* Error already displayed. */ 1074 return -1; 1075 } 1076 1077 /* Check whether ICU will initialize without forcing the build data directory into 1078 * the ICU_DATA path. Success here means either the data dll contains data, or that 1079 * this test program was run with ICU_DATA set externally. Failure of this check 1080 * is normal when ICU data is not packaged into a shared library. 1081 * 1082 * Whether or not this test succeeds, we want to cleanup and reinitialize 1083 * with a data path so that data loading from individual files can be tested. 1084 */ 1085 u_init(&errorCode); 1086 1087 if (U_FAILURE(errorCode)) { 1088 fprintf(stderr, 1089 "#### Note: ICU Init without build-specific setDataDirectory() failed.\n"); 1090 } 1091 1092 u_cleanup(); 1093 errorCode = U_ZERO_ERROR; 1094 1095 if (!initArgs(argc, argv, NULL, NULL)) { 1096 /* Error already displayed. */ 1097 return -1; 1098 } 1099 /* Initialize ICU */ 1100 ctest_setICU_DATA(); /* u_setDataDirectory() must happen Before u_init() */ 1101 u_init(&errorCode); 1102 1103 if (U_FAILURE(errorCode)) { 1104 fprintf(stderr, 1105 "#### ERROR! %s: u_init() failed with status = \"%s\".\n" 1106 "*** Check the ICU_DATA environment variable and \n" 1107 "*** check that the data files are present.\n", argv[0], u_errorName(errorCode)); 1108 return 1; 1109 } 1110 1111 addAllTests(&root); 1112 nerrors = runTestRequest(root, argc, argv); 1113 1114 cleanUpTestTree(root); 1115 u_cleanup(); 1116 1117 endTime = uprv_getUTCtime(); 1118 diffTime = (int32_t)(endTime - startTime); 1119 printf("Elapsed Time: %02d:%02d:%02d.%03d\n", 1120 (int)((diffTime%U_MILLIS_PER_DAY)/U_MILLIS_PER_HOUR), 1121 (int)((diffTime%U_MILLIS_PER_HOUR)/U_MILLIS_PER_MINUTE), 1122 (int)((diffTime%U_MILLIS_PER_MINUTE)/U_MILLIS_PER_SECOND), 1123 (int)(diffTime%U_MILLIS_PER_SECOND)); 1124 1125 return nerrors; 1126 } 1127 1128