Home | History | Annotate | Download | only in cintltst
      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