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