1 // Copyright (C) 2016 and later: Unicode, Inc. and others. 2 // License & terms of use: http://www.unicode.org/copyright.html 3 /* 4 ******************************************************************************* 5 * Copyright (C) 1997-2016 International Business Machines 6 * Corporation and others. All Rights Reserved. 7 ******************************************************************************* 8 * Date Name Description 9 * 06/23/00 aliu Creation. 10 ******************************************************************************* 11 */ 12 13 #include "unicode/utypes.h" 14 15 #if !UCONFIG_NO_TRANSLITERATION 16 17 #include <stdlib.h> 18 #include <string.h> 19 #include "unicode/utrans.h" 20 #include "unicode/ustring.h" 21 #include "unicode/uset.h" 22 #include "cintltst.h" 23 #include "cmemory.h" 24 25 #define TEST(x) addTest(root, &x, "utrans/" # x) 26 27 static void TestAPI(void); 28 static void TestSimpleRules(void); 29 static void TestFilter(void); 30 static void TestOpenInverse(void); 31 static void TestClone(void); 32 static void TestRegisterUnregister(void); 33 static void TestExtractBetween(void); 34 static void TestUnicodeIDs(void); 35 static void TestGetRulesAndSourceSet(void); 36 37 static void _expectRules(const char*, const char*, const char*); 38 static void _expect(const UTransliterator* trans, const char* cfrom, const char* cto); 39 40 void addUTransTest(TestNode** root); 41 42 43 void 44 addUTransTest(TestNode** root) { 45 TEST(TestAPI); 46 TEST(TestSimpleRules); 47 TEST(TestFilter); 48 TEST(TestOpenInverse); 49 TEST(TestClone); 50 TEST(TestRegisterUnregister); 51 TEST(TestExtractBetween); 52 TEST(TestUnicodeIDs); 53 TEST(TestGetRulesAndSourceSet); 54 } 55 56 /*------------------------------------------------------------------ 57 * Replaceable glue 58 * 59 * To test the Replaceable glue we have to dummy up a C-based 60 * Replaceable callback. This code is for testing purposes only. 61 *------------------------------------------------------------------*/ 62 63 typedef struct XReplaceable { 64 UChar* text; /* MUST BE null-terminated */ 65 } XReplaceable; 66 67 static void InitXReplaceable(XReplaceable* rep, const char* cstring) { 68 rep->text = malloc(sizeof(UChar) * (strlen(cstring)+1)); 69 u_uastrcpy(rep->text, cstring); 70 } 71 72 static void FreeXReplaceable(XReplaceable* rep) { 73 if (rep->text != NULL) { 74 free(rep->text); 75 rep->text = NULL; 76 } 77 } 78 79 /* UReplaceableCallbacks callback */ 80 static int32_t Xlength(const UReplaceable* rep) { 81 const XReplaceable* x = (const XReplaceable*)rep; 82 return u_strlen(x->text); 83 } 84 85 /* UReplaceableCallbacks callback */ 86 static UChar XcharAt(const UReplaceable* rep, int32_t offset) { 87 const XReplaceable* x = (const XReplaceable*)rep; 88 return x->text[offset]; 89 } 90 91 /* UReplaceableCallbacks callback */ 92 static UChar32 Xchar32At(const UReplaceable* rep, int32_t offset) { 93 const XReplaceable* x = (const XReplaceable*)rep; 94 return x->text[offset]; 95 } 96 97 /* UReplaceableCallbacks callback */ 98 static void Xreplace(UReplaceable* rep, int32_t start, int32_t limit, 99 const UChar* text, int32_t textLength) { 100 XReplaceable* x = (XReplaceable*)rep; 101 int32_t newLen = Xlength(rep) + limit - start + textLength; 102 UChar* newText = (UChar*) malloc(sizeof(UChar) * (newLen+1)); 103 u_strncpy(newText, x->text, start); 104 u_strncpy(newText + start, text, textLength); 105 u_strcpy(newText + start + textLength, x->text + limit); 106 free(x->text); 107 x->text = newText; 108 } 109 110 /* UReplaceableCallbacks callback */ 111 static void Xcopy(UReplaceable* rep, int32_t start, int32_t limit, int32_t dest) { 112 XReplaceable* x = (XReplaceable*)rep; 113 int32_t newLen = Xlength(rep) + limit - start; 114 UChar* newText = (UChar*) malloc(sizeof(UChar) * (newLen+1)); 115 u_strncpy(newText, x->text, dest); 116 u_strncpy(newText + dest, x->text + start, limit - start); 117 u_strcpy(newText + dest + limit - start, x->text + dest); 118 free(x->text); 119 x->text = newText; 120 } 121 122 /* UReplaceableCallbacks callback */ 123 static void Xextract(UReplaceable* rep, int32_t start, int32_t limit, UChar* dst) { 124 XReplaceable* x = (XReplaceable*)rep; 125 int32_t len = limit - start; 126 u_strncpy(dst, x->text, len); 127 } 128 129 static void InitXReplaceableCallbacks(UReplaceableCallbacks* callbacks) { 130 callbacks->length = Xlength; 131 callbacks->charAt = XcharAt; 132 callbacks->char32At = Xchar32At; 133 callbacks->replace = Xreplace; 134 callbacks->extract = Xextract; 135 callbacks->copy = Xcopy; 136 } 137 138 /*------------------------------------------------------------------ 139 * Tests 140 *------------------------------------------------------------------*/ 141 142 static void TestAPI() { 143 enum { BUF_CAP = 128 }; 144 char buf[BUF_CAP], buf2[BUF_CAP]; 145 UErrorCode status = U_ZERO_ERROR; 146 UTransliterator* trans = NULL; 147 int32_t i, n; 148 149 /* Test getAvailableIDs */ 150 n = utrans_countAvailableIDs(); 151 if (n < 1) { 152 log_err("FAIL: utrans_countAvailableIDs() returned %d\n", n); 153 } else { 154 log_verbose("System ID count: %d\n", n); 155 } 156 for (i=0; i<n; ++i) { 157 utrans_getAvailableID(i, buf, BUF_CAP); 158 if (*buf == 0) { 159 log_err("FAIL: System transliterator %d: \"\"\n", i); 160 } else { 161 log_verbose("System transliterator %d: \"%s\"\n", i, buf); 162 } 163 } 164 165 /* Test open */ 166 utrans_getAvailableID(0, buf, BUF_CAP); 167 trans = utrans_open(buf, UTRANS_FORWARD,NULL,0,NULL, &status); 168 if (U_FAILURE(status)) { 169 log_err("FAIL: utrans_open(%s) failed, error=%s\n", 170 buf, u_errorName(status)); 171 } 172 173 else { 174 /* Test getID */ 175 utrans_getID(trans, buf2, BUF_CAP); 176 if (0 != strcmp(buf, buf2)) { 177 log_err("FAIL: utrans_getID(%s) returned %s\n", 178 buf, buf2); 179 } 180 utrans_close(trans); 181 } 182 } 183 184 static void TestUnicodeIDs() { 185 UEnumeration *uenum; 186 UTransliterator *utrans; 187 const UChar *id, *id2; 188 int32_t idLength, id2Length, count, count2; 189 190 UErrorCode errorCode; 191 192 errorCode=U_ZERO_ERROR; 193 uenum=utrans_openIDs(&errorCode); 194 if(U_FAILURE(errorCode)) { 195 log_err("utrans_openIDs() failed - %s\n", u_errorName(errorCode)); 196 return; 197 } 198 199 count=uenum_count(uenum, &errorCode); 200 if(U_FAILURE(errorCode) || count<1) { 201 log_err("uenum_count(transliterator IDs)=%d - %s\n", count, u_errorName(errorCode)); 202 } 203 204 count=0; 205 for(;;) { 206 id=uenum_unext(uenum, &idLength, &errorCode); 207 if(U_FAILURE(errorCode)) { 208 log_err("uenum_unext(transliterator ID %d) failed - %s\n", count, u_errorName(errorCode)); 209 break; 210 } 211 if(id==NULL) { 212 break; 213 } 214 215 if(++count>10) { 216 /* try to actually open only a few transliterators */ 217 continue; 218 } 219 220 utrans=utrans_openU(id, idLength, UTRANS_FORWARD, NULL, 0, NULL, &errorCode); 221 if(U_FAILURE(errorCode)) { 222 log_err("utrans_openU(%s) failed - %s\n", aescstrdup(id, idLength), u_errorName(errorCode)); 223 continue; 224 } 225 226 id2=utrans_getUnicodeID(utrans, &id2Length); 227 if(idLength!=id2Length || 0!=u_memcmp(id, id2, idLength)) { 228 log_err("utrans_getUnicodeID(%s) does not match the original ID\n", aescstrdup(id, idLength)); 229 } 230 231 utrans_close(utrans); 232 } 233 234 uenum_reset(uenum, &errorCode); 235 if(U_FAILURE(errorCode) || count<1) { 236 log_err("uenum_reset(transliterator IDs) failed - %s\n", u_errorName(errorCode)); 237 } else { 238 count2=uenum_count(uenum, &errorCode); 239 if(U_FAILURE(errorCode) || count<1) { 240 log_err("2nd uenum_count(transliterator IDs)=%d - %s\n", count2, u_errorName(errorCode)); 241 } else if(count!=count2) { 242 log_err("uenum_unext(transliterator IDs) returned %d IDs but uenum_count() after uenum_reset() claims there are %d\n", count, count2); 243 } 244 } 245 246 uenum_close(uenum); 247 } 248 249 static void TestOpenInverse(){ 250 UErrorCode status=U_ZERO_ERROR; 251 UTransliterator* t1=NULL; 252 UTransliterator* inverse1=NULL; 253 enum { BUF_CAP = 128 }; 254 char buf1[BUF_CAP]; 255 int32_t i=0; 256 257 const char TransID[][25]={ 258 "Halfwidth-Fullwidth", 259 "Fullwidth-Halfwidth", 260 "Greek-Latin" , 261 "Latin-Greek", 262 /*"Arabic-Latin", // Removed in 2.0*/ 263 /*"Latin-Arabic", // Removed in 2.0*/ 264 "Katakana-Latin", 265 "Latin-Katakana", 266 /*"Hebrew-Latin", // Removed in 2.0*/ 267 /*"Latin-Hebrew", // Removed in 2.0*/ 268 "Cyrillic-Latin", 269 "Latin-Cyrillic", 270 "Devanagari-Latin", 271 "Latin-Devanagari", 272 "Any-Hex", 273 "Hex-Any" 274 }; 275 276 for(i=0; i<UPRV_LENGTHOF(TransID); i=i+2){ 277 status = U_ZERO_ERROR; 278 t1=utrans_open(TransID[i], UTRANS_FORWARD,NULL,0,NULL, &status); 279 if(t1 == NULL || U_FAILURE(status)){ 280 log_data_err("FAIL: in instantiation for id=%s -> %s (Are you missing data?)\n", TransID[i], u_errorName(status)); 281 continue; 282 } 283 inverse1=utrans_openInverse(t1, &status); 284 if(U_FAILURE(status)){ 285 log_err("FAIL: utrans_openInverse() failed for id=%s. Error=%s\n", TransID[i], myErrorName(status)); 286 continue; 287 } 288 utrans_getID(inverse1, buf1, BUF_CAP); 289 if(strcmp(buf1, TransID[i+1]) != 0){ 290 log_err("FAIL :openInverse() for %s returned %s instead of %s\n", TransID[i], buf1, TransID[i+1]); 291 } 292 utrans_close(t1); 293 utrans_close(inverse1); 294 } 295 } 296 297 static void TestClone(){ 298 UErrorCode status=U_ZERO_ERROR; 299 UTransliterator* t1=NULL; 300 UTransliterator* t2=NULL; 301 UTransliterator* t3=NULL; 302 UTransliterator* t4=NULL; 303 enum { BUF_CAP = 128 }; 304 char buf1[BUF_CAP], buf2[BUF_CAP], buf3[BUF_CAP]; 305 306 t1=utrans_open("Latin-Devanagari", UTRANS_FORWARD, NULL,0,NULL,&status); 307 if(U_FAILURE(status)){ 308 log_data_err("FAIL: construction -> %s (Are you missing data?)\n", u_errorName(status)); 309 return; 310 } 311 t2=utrans_open("Latin-Greek", UTRANS_FORWARD, NULL,0,NULL,&status); 312 if(U_FAILURE(status)){ 313 log_err("FAIL: construction\n"); 314 utrans_close(t1); 315 return; 316 } 317 318 t3=utrans_clone(t1, &status); 319 t4=utrans_clone(t2, &status); 320 321 utrans_getID(t1, buf1, BUF_CAP); 322 utrans_getID(t2, buf2, BUF_CAP); 323 utrans_getID(t3, buf3, BUF_CAP); 324 325 if(strcmp(buf1, buf3) != 0 || 326 strcmp(buf1, buf2) == 0) { 327 log_err("FAIL: utrans_clone() failed\n"); 328 } 329 330 utrans_getID(t4, buf3, BUF_CAP); 331 332 if(strcmp(buf2, buf3) != 0 || 333 strcmp(buf1, buf3) == 0) { 334 log_err("FAIL: utrans_clone() failed\n"); 335 } 336 337 utrans_close(t1); 338 utrans_close(t2); 339 utrans_close(t3); 340 utrans_close(t4); 341 342 } 343 344 static void TestRegisterUnregister(){ 345 UErrorCode status=U_ZERO_ERROR; 346 UTransliterator* t1=NULL; 347 UTransliterator* rules=NULL, *rules2; 348 UTransliterator* inverse1=NULL; 349 UChar rule[]={ 0x0061, 0x003c, 0x003e, 0x0063}; /*a<>b*/ 350 351 U_STRING_DECL(ID, "TestA-TestB", 11); 352 U_STRING_INIT(ID, "TestA-TestB", 11); 353 354 /* Make sure it doesn't exist */ 355 t1=utrans_open("TestA-TestB", UTRANS_FORWARD,NULL,0,NULL, &status); 356 if(t1 != NULL || U_SUCCESS(status)) { 357 log_err("FAIL: TestA-TestB already registered\n"); 358 return; 359 } 360 status=U_ZERO_ERROR; 361 /* Check inverse too */ 362 inverse1=utrans_open("TestA-TestB", UTRANS_REVERSE, NULL,0,NULL,&status); 363 if(inverse1 != NULL || U_SUCCESS(status)) { 364 log_err("FAIL: TestA-TestB already registered\n"); 365 return; 366 } 367 status=U_ZERO_ERROR; 368 /* Create it */ 369 rules=utrans_open("TestA-TestB",UTRANS_FORWARD, rule, 4, NULL, &status); 370 if(U_FAILURE(status)){ 371 log_err("FAIL: utrans_openRules(a<>B) failed with error=%s\n", myErrorName(status)); 372 return; 373 } 374 375 /* clone it so we can register it a second time */ 376 rules2=utrans_clone(rules, &status); 377 if(U_FAILURE(status)) { 378 log_err("FAIL: utrans_clone(a<>B) failed with error=%s\n", myErrorName(status)); 379 return; 380 } 381 382 status=U_ZERO_ERROR; 383 /* Register it */ 384 utrans_register(rules, &status); 385 if(U_FAILURE(status)){ 386 log_err("FAIL: utrans_register failed with error=%s\n", myErrorName(status)); 387 return; 388 } 389 status=U_ZERO_ERROR; 390 /* Now check again -- should exist now*/ 391 t1= utrans_open("TestA-TestB", UTRANS_FORWARD, NULL,0,NULL,&status); 392 if(U_FAILURE(status) || t1 == NULL){ 393 log_err("FAIL: TestA-TestB not registered\n"); 394 return; 395 } 396 utrans_close(t1); 397 398 /*unregister the instance*/ 399 status=U_ZERO_ERROR; 400 utrans_unregister("TestA-TestB"); 401 /* now Make sure it doesn't exist */ 402 t1=utrans_open("TestA-TestB", UTRANS_FORWARD,NULL,0,NULL, &status); 403 if(U_SUCCESS(status) || t1 != NULL) { 404 log_err("FAIL: TestA-TestB isn't unregistered\n"); 405 return; 406 } 407 utrans_close(t1); 408 409 /* now with utrans_unregisterID(const UChar *) */ 410 status=U_ZERO_ERROR; 411 utrans_register(rules2, &status); 412 if(U_FAILURE(status)){ 413 log_err("FAIL: 2nd utrans_register failed with error=%s\n", myErrorName(status)); 414 return; 415 } 416 status=U_ZERO_ERROR; 417 /* Now check again -- should exist now*/ 418 t1= utrans_open("TestA-TestB", UTRANS_FORWARD, NULL,0,NULL,&status); 419 if(U_FAILURE(status) || t1 == NULL){ 420 log_err("FAIL: 2nd TestA-TestB not registered\n"); 421 return; 422 } 423 utrans_close(t1); 424 425 /*unregister the instance*/ 426 status=U_ZERO_ERROR; 427 utrans_unregisterID(ID, -1); 428 /* now Make sure it doesn't exist */ 429 t1=utrans_openU(ID, -1, UTRANS_FORWARD,NULL,0,NULL, &status); 430 if(U_SUCCESS(status) || t1 != NULL) { 431 log_err("FAIL: 2nd TestA-TestB isn't unregistered\n"); 432 return; 433 } 434 435 utrans_close(t1); 436 utrans_close(inverse1); 437 } 438 439 static void TestSimpleRules() { 440 /* Test rules */ 441 /* Example: rules 1. ab>x|y 442 * 2. yc>z 443 * 444 * []|eabcd start - no match, copy e to tranlated buffer 445 * [e]|abcd match rule 1 - copy output & adjust cursor 446 * [ex|y]cd match rule 2 - copy output & adjust cursor 447 * [exz]|d no match, copy d to transliterated buffer 448 * [exzd]| done 449 */ 450 _expectRules("ab>x|y;" 451 "yc>z", 452 "eabcd", "exzd"); 453 454 /* Another set of rules: 455 * 1. ab>x|yzacw 456 * 2. za>q 457 * 3. qc>r 458 * 4. cw>n 459 * 460 * []|ab Rule 1 461 * [x|yzacw] No match 462 * [xy|zacw] Rule 2 463 * [xyq|cw] Rule 4 464 * [xyqn]| Done 465 */ 466 _expectRules("ab>x|yzacw;" 467 "za>q;" 468 "qc>r;" 469 "cw>n", 470 "ab", "xyqn"); 471 472 /* Test categories 473 */ 474 _expectRules("$dummy=" "\\uE100" ";" /* careful here with E100 */ 475 "$vowel=[aeiouAEIOU];" 476 "$lu=[:Lu:];" 477 "$vowel } $lu > '!';" 478 "$vowel > '&';" 479 "'!' { $lu > '^';" 480 "$lu > '*';" 481 "a > ERROR", 482 "abcdefgABCDEFGU", "&bcd&fg!^**!^*&"); 483 484 /* Test multiple passes 485 */ 486 _expectRules("abc > xy;" 487 "::Null;" 488 "aba > z;", 489 "abc ababc aba", "xy abxy z"); 490 } 491 492 static void TestFilter() { 493 UErrorCode status = U_ZERO_ERROR; 494 UChar filt[128]; 495 UChar buf[128]; 496 UChar exp[128]; 497 char *cbuf; 498 int32_t limit; 499 const char* DATA[] = { 500 "[^c]", /* Filter out 'c' */ 501 "abcde", 502 "\\u0061\\u0062c\\u0064\\u0065", 503 504 "", /* No filter */ 505 "abcde", 506 "\\u0061\\u0062\\u0063\\u0064\\u0065" 507 }; 508 int32_t DATA_length = UPRV_LENGTHOF(DATA); 509 int32_t i; 510 511 UTransliterator* hex = utrans_open("Any-Hex", UTRANS_FORWARD, NULL,0,NULL,&status); 512 513 if (hex == 0 || U_FAILURE(status)) { 514 log_err("FAIL: utrans_open(Unicode-Hex) failed, error=%s\n", 515 u_errorName(status)); 516 goto exit; 517 } 518 519 for (i=0; i<DATA_length; i+=3) { 520 /*u_uastrcpy(filt, DATA[i]);*/ 521 u_charsToUChars(DATA[i], filt, (int32_t)strlen(DATA[i])+1); 522 utrans_setFilter(hex, filt, -1, &status); 523 524 if (U_FAILURE(status)) { 525 log_err("FAIL: utrans_setFilter() failed, error=%s\n", 526 u_errorName(status)); 527 goto exit; 528 } 529 530 /*u_uastrcpy(buf, DATA[i+1]);*/ 531 u_charsToUChars(DATA[i+1], buf, (int32_t)strlen(DATA[i+1])+1); 532 limit = 5; 533 utrans_transUChars(hex, buf, NULL, 128, 0, &limit, &status); 534 535 if (U_FAILURE(status)) { 536 log_err("FAIL: utrans_transUChars() failed, error=%s\n", 537 u_errorName(status)); 538 goto exit; 539 } 540 541 cbuf=aescstrdup(buf, -1); 542 u_charsToUChars(DATA[i+2], exp, (int32_t)strlen(DATA[i+2])+1); 543 if (0 == u_strcmp(buf, exp)) { 544 log_verbose("Ok: %s | %s -> %s\n", DATA[i+1], DATA[i], cbuf); 545 } else { 546 log_err("FAIL: %s | %s -> %s, expected %s\n", DATA[i+1], DATA[i], cbuf, DATA[i+2]); 547 } 548 } 549 550 exit: 551 utrans_close(hex); 552 } 553 554 /** 555 * Test the UReplaceableCallback extractBetween support. We use a 556 * transliterator known to rely on this call. 557 */ 558 static void TestExtractBetween() { 559 560 UTransliterator *trans; 561 UErrorCode status = U_ZERO_ERROR; 562 UParseError parseErr; 563 564 trans = utrans_open("Lower", UTRANS_FORWARD, NULL, -1, 565 &parseErr, &status); 566 567 if (U_FAILURE(status)) { 568 log_err("FAIL: utrans_open(Lower) failed, error=%s\n", 569 u_errorName(status)); 570 } else { 571 _expect(trans, "ABC", "abc"); 572 573 utrans_close(trans); 574 } 575 } 576 577 /** 578 * Test utrans_toRules, utrans_getSourceSet 579 */ 580 581 /* A simple transform with a small filter & source set: rules 50-100 chars unescaped, 100-200 chars escaped, 582 filter & source set 4-20 chars */ 583 static const UChar transSimpleID[] = { 0x79,0x6F,0x2D,0x79,0x6F,0x5F,0x42,0x4A,0 }; /* "yo-yo_BJ" */ 584 static const char* transSimpleCName = "yo-yo_BJ"; 585 586 enum { kUBufMax = 256 }; 587 static void TestGetRulesAndSourceSet() { 588 UErrorCode status = U_ZERO_ERROR; 589 UTransliterator *utrans = utrans_openU(transSimpleID, -1, UTRANS_FORWARD, NULL, 0, NULL, &status); 590 if ( U_SUCCESS(status) ) { 591 USet* uset; 592 UChar ubuf[kUBufMax]; 593 int32_t ulen; 594 595 status = U_ZERO_ERROR; 596 ulen = utrans_toRules(utrans, FALSE, ubuf, kUBufMax, &status); 597 if ( U_FAILURE(status) || ulen <= 50 || ulen >= 100) { 598 log_err("FAIL: utrans_toRules unescaped, expected noErr and len 50-100, got error=%s and len=%d\n", 599 u_errorName(status), ulen); 600 } 601 602 status = U_ZERO_ERROR; 603 ulen = utrans_toRules(utrans, FALSE, NULL, 0, &status); 604 if ( status != U_BUFFER_OVERFLOW_ERROR || ulen <= 50 || ulen >= 100) { 605 log_err("FAIL: utrans_toRules unescaped, expected U_BUFFER_OVERFLOW_ERROR and len 50-100, got error=%s and len=%d\n", 606 u_errorName(status), ulen); 607 } 608 609 status = U_ZERO_ERROR; 610 ulen = utrans_toRules(utrans, TRUE, ubuf, kUBufMax, &status); 611 if ( U_FAILURE(status) || ulen <= 100 || ulen >= 200) { 612 log_err("FAIL: utrans_toRules escaped, expected noErr and len 100-200, got error=%s and len=%d\n", 613 u_errorName(status), ulen); 614 } 615 616 status = U_ZERO_ERROR; 617 uset = utrans_getSourceSet(utrans, FALSE, NULL, &status); 618 ulen = uset_toPattern(uset, ubuf, kUBufMax, FALSE, &status); 619 uset_close(uset); 620 if ( U_FAILURE(status) || ulen <= 4 || ulen >= 20) { 621 log_err("FAIL: utrans_getSourceSet useFilter, expected noErr and len 4-20, got error=%s and len=%d\n", 622 u_errorName(status), ulen); 623 } 624 625 status = U_ZERO_ERROR; 626 uset = utrans_getSourceSet(utrans, TRUE, NULL, &status); 627 ulen = uset_toPattern(uset, ubuf, kUBufMax, FALSE, &status); 628 uset_close(uset); 629 if ( U_FAILURE(status) || ulen <= 4 || ulen >= 20) { 630 log_err("FAIL: utrans_getSourceSet ignoreFilter, expected noErr and len 4-20, got error=%s and len=%d\n", 631 u_errorName(status), ulen); 632 } 633 634 utrans_close(utrans); 635 } else { 636 log_data_err("FAIL: utrans_openRules(%s) failed, error=%s (Are you missing data?)\n", 637 transSimpleCName, u_errorName(status)); 638 } 639 } 640 641 642 static void _expectRules(const char* crules, 643 const char* cfrom, 644 const char* cto) { 645 /* u_uastrcpy has no capacity param for the buffer -- so just 646 * make all buffers way too big */ 647 enum { CAP = 256 }; 648 UChar rules[CAP]; 649 UTransliterator *trans; 650 UErrorCode status = U_ZERO_ERROR; 651 UParseError parseErr; 652 653 u_uastrcpy(rules, crules); 654 655 trans = utrans_open(crules /*use rules as ID*/, UTRANS_FORWARD, rules, -1, 656 &parseErr, &status); 657 if (U_FAILURE(status)) { 658 utrans_close(trans); 659 log_data_err("FAIL: utrans_openRules(%s) failed, error=%s (Are you missing data?)\n", 660 crules, u_errorName(status)); 661 return; 662 } 663 664 _expect(trans, cfrom, cto); 665 666 utrans_close(trans); 667 } 668 669 static void _expect(const UTransliterator* trans, 670 const char* cfrom, 671 const char* cto) { 672 /* u_uastrcpy has no capacity param for the buffer -- so just 673 * make all buffers way too big */ 674 enum { CAP = 256 }; 675 UChar from[CAP]; 676 UChar to[CAP]; 677 UChar buf[CAP]; 678 const UChar *ID; 679 int32_t IDLength; 680 const char *id; 681 682 UErrorCode status = U_ZERO_ERROR; 683 int32_t limit; 684 UTransPosition pos; 685 XReplaceable xrep; 686 XReplaceable *xrepPtr = &xrep; 687 UReplaceableCallbacks xrepVtable; 688 689 u_uastrcpy(from, cfrom); 690 u_uastrcpy(to, cto); 691 692 ID = utrans_getUnicodeID(trans, &IDLength); 693 id = aescstrdup(ID, IDLength); 694 695 /* utrans_transUChars() */ 696 u_strcpy(buf, from); 697 limit = u_strlen(buf); 698 utrans_transUChars(trans, buf, NULL, CAP, 0, &limit, &status); 699 if (U_FAILURE(status)) { 700 log_err("FAIL: utrans_transUChars() failed, error=%s\n", 701 u_errorName(status)); 702 return; 703 } 704 705 if (0 == u_strcmp(buf, to)) { 706 log_verbose("Ok: utrans_transUChars(%s) x %s -> %s\n", 707 id, cfrom, cto); 708 } else { 709 char actual[CAP]; 710 u_austrcpy(actual, buf); 711 log_err("FAIL: utrans_transUChars(%s) x %s -> %s, expected %s\n", 712 id, cfrom, actual, cto); 713 } 714 715 /* utrans_transIncrementalUChars() */ 716 u_strcpy(buf, from); 717 pos.start = pos.contextStart = 0; 718 pos.limit = pos.contextLimit = u_strlen(buf); 719 utrans_transIncrementalUChars(trans, buf, NULL, CAP, &pos, &status); 720 utrans_transUChars(trans, buf, NULL, CAP, pos.start, &pos.limit, &status); 721 if (U_FAILURE(status)) { 722 log_err("FAIL: utrans_transIncrementalUChars() failed, error=%s\n", 723 u_errorName(status)); 724 return; 725 } 726 727 if (0 == u_strcmp(buf, to)) { 728 log_verbose("Ok: utrans_transIncrementalUChars(%s) x %s -> %s\n", 729 id, cfrom, cto); 730 } else { 731 char actual[CAP]; 732 u_austrcpy(actual, buf); 733 log_err("FAIL: utrans_transIncrementalUChars(%s) x %s -> %s, expected %s\n", 734 id, cfrom, actual, cto); 735 } 736 737 /* utrans_trans() */ 738 InitXReplaceableCallbacks(&xrepVtable); 739 InitXReplaceable(&xrep, cfrom); 740 limit = u_strlen(from); 741 utrans_trans(trans, (UReplaceable*)xrepPtr, &xrepVtable, 0, &limit, &status); 742 if (U_FAILURE(status)) { 743 log_err("FAIL: utrans_trans() failed, error=%s\n", 744 u_errorName(status)); 745 FreeXReplaceable(&xrep); 746 return; 747 } 748 749 if (0 == u_strcmp(xrep.text, to)) { 750 log_verbose("Ok: utrans_trans(%s) x %s -> %s\n", 751 id, cfrom, cto); 752 } else { 753 char actual[CAP]; 754 u_austrcpy(actual, xrep.text); 755 log_err("FAIL: utrans_trans(%s) x %s -> %s, expected %s\n", 756 id, cfrom, actual, cto); 757 } 758 FreeXReplaceable(&xrep); 759 760 /* utrans_transIncremental() */ 761 InitXReplaceable(&xrep, cfrom); 762 pos.start = pos.contextStart = 0; 763 pos.limit = pos.contextLimit = u_strlen(from); 764 utrans_transIncremental(trans, (UReplaceable*)xrepPtr, &xrepVtable, &pos, &status); 765 utrans_trans(trans, (UReplaceable*)xrepPtr, &xrepVtable, pos.start, &pos.limit, &status); 766 if (U_FAILURE(status)) { 767 log_err("FAIL: utrans_transIncremental() failed, error=%s\n", 768 u_errorName(status)); 769 FreeXReplaceable(&xrep); 770 return; 771 } 772 773 if (0 == u_strcmp(xrep.text, to)) { 774 log_verbose("Ok: utrans_transIncremental(%s) x %s -> %s\n", 775 id, cfrom, cto); 776 } else { 777 char actual[CAP]; 778 u_austrcpy(actual, xrep.text); 779 log_err("FAIL: utrans_transIncremental(%s) x %s -> %s, expected %s\n", 780 id, cfrom, actual, cto); 781 } 782 FreeXReplaceable(&xrep); 783 } 784 785 #endif /* #if !UCONFIG_NO_TRANSLITERATION */ 786