1/************************************************************************
2 * COPYRIGHT:
3 * Copyright (c) 2000-2009, International Business Machines Corporation
4 * and others. All Rights Reserved.
5 ************************************************************************/
6/************************************************************************
7*   Date        Name        Description
8*   1/03/2000   Madhu        Creation.
9************************************************************************/
10
11#include "unicode/utypes.h"
12
13#if !UCONFIG_NO_TRANSLITERATION
14
15#include "ittrans.h"
16#include "transapi.h"
17#include "unicode/utypes.h"
18#include "unicode/translit.h"
19#include "unicode/unifilt.h"
20#include "cpdtrans.h"
21#include <string.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include "unicode/rep.h"
25#include "unicode/locid.h"
26#include "unicode/uniset.h"
27
28int32_t getInt(UnicodeString str)
29{
30    char buffer[20];
31    int len=str.length();
32    if(len>=20) {
33        len=19;
34    }
35    str.extract(0, len, buffer, "");
36    buffer[len]=0;
37    return atoi(buffer);
38}
39
40//---------------------------------------------
41// runIndexedTest
42//---------------------------------------------
43
44void
45TransliteratorAPITest::runIndexedTest(int32_t index, UBool exec,
46                                      const char* &name, char* /*par*/) {
47    switch (index) {
48        TESTCASE(0,TestgetInverse);
49        TESTCASE(1,TestgetID);
50        TESTCASE(2,TestGetDisplayName);
51        TESTCASE(3,TestTransliterate1);
52        TESTCASE(4,TestTransliterate2);
53        TESTCASE(5,TestTransliterate3);
54        TESTCASE(6,TestSimpleKeyboardTransliterator);
55        TESTCASE(7,TestKeyboardTransliterator1);
56        TESTCASE(8,TestKeyboardTransliterator2);
57        TESTCASE(9,TestKeyboardTransliterator3);
58        TESTCASE(10,TestGetAdoptFilter);
59        TESTCASE(11,TestClone);
60        TESTCASE(12,TestNullTransliterator);
61        TESTCASE(13,TestRegisterUnregister);
62        TESTCASE(14,TestUnicodeFunctor);
63        default: name = ""; break;
64    }
65}
66
67
68void TransliteratorAPITest::TestgetID() {
69    UnicodeString trans="Latin-Greek";
70    UnicodeString ID;
71    UParseError parseError;
72    UErrorCode status = U_ZERO_ERROR;
73    Transliterator* t= Transliterator::createInstance(trans, UTRANS_FORWARD, parseError, status);
74    if(t==0 || U_FAILURE(status)){
75        dataerrln("FAIL: construction of Latin-Greek -  %s",u_errorName(status));
76        return;
77    }else{
78        ID= t->getID();
79        if(ID != trans)
80            errln("FAIL: getID returned " + ID + " instead of Latin-Greek");
81        delete t;
82    }
83    int i;
84    for (i=0; i<Transliterator::countAvailableIDs(); i++){
85        status = U_ZERO_ERROR;
86        ID = (UnicodeString) Transliterator::getAvailableID(i);
87        if(ID.indexOf("Thai")>-1){
88            continue;
89        }
90        t = Transliterator::createInstance(ID, UTRANS_FORWARD, parseError, status);
91        if(t == 0){
92            errln("FAIL: " + ID);
93            continue;
94        }
95        if(ID != t->getID())
96            errln("FAIL: getID() returned " + t->getID() + " instead of " + ID);
97        delete t;
98    }
99    ID=(UnicodeString)Transliterator::getAvailableID(i);
100    if(ID != (UnicodeString)Transliterator::getAvailableID(0)){
101        errln("FAIL: calling getAvailableID(index > coundAvailableIDs) should make index=0\n");
102    }
103
104    Transliterator* t1=Transliterator::createInstance("Latin-Devanagari", UTRANS_FORWARD, parseError, status);
105    Transliterator* t2=Transliterator::createInstance("Latin-Greek", UTRANS_FORWARD, parseError, status);
106    if(t1 ==0 || t2 == 0){
107        errln("FAIL: construction");
108        return;
109    }
110    Transliterator* t3=t1->clone();
111    Transliterator* t4=t2->clone();
112
113    if(t1->getID() != t3->getID() || t2->getID() != t4->getID() ||
114       t1->getID() == t4->getID() || t2->getID() == t3->getID() ||
115       t1->getID()== t4->getID() )
116            errln("FAIL: getID or clone failed");
117
118
119    Transliterator* t5=Transliterator::createInstance("Latin-Devanagari", UTRANS_FORWARD, parseError, status);
120    if(t5 == 0)
121        errln("FAIL: construction");
122    else if(t1->getID() != t5->getID() || t5->getID() != t3->getID() || t1->getID() != t3->getID())
123        errln("FAIL: getID or clone failed");
124
125
126    delete t1;
127    delete t2;
128    delete t3;
129    delete t4;
130    delete t5;
131}
132
133void TransliteratorAPITest::TestgetInverse() {
134     UErrorCode status = U_ZERO_ERROR;
135     UParseError parseError;
136     Transliterator* t1    = Transliterator::createInstance("Katakana-Latin", UTRANS_FORWARD, parseError, status);
137     Transliterator* invt1 = Transliterator::createInstance("Latin-Katakana", UTRANS_FORWARD, parseError, status);
138     Transliterator* t2    = Transliterator::createInstance("Latin-Devanagari", UTRANS_FORWARD, parseError, status);
139     Transliterator* invt2 = Transliterator::createInstance("Devanagari-Latin", UTRANS_FORWARD, parseError, status);
140     if(t1 == 0 || invt1 == 0 || t2 == 0 || invt2 == 0) {
141         dataerrln("FAIL: in instantiation - %s", u_errorName(status));
142         return;
143     }
144
145     Transliterator* inverse1=t1->createInverse(status);
146     Transliterator* inverse2=t2->createInverse(status);
147     if(inverse1->getID() != invt1->getID() || inverse2->getID() != invt2->getID()
148        || inverse1->getID() == invt2->getID() || inverse2->getID() == invt1->getID() )
149        errln("FAIL: getInverse() ");
150
151     UnicodeString TransID[]={
152       "Halfwidth-Fullwidth",
153       "Fullwidth-Halfwidth",
154       "Greek-Latin" ,
155       "Latin-Greek",
156       //"Arabic-Latin", // removed in 2.0
157       //"Latin-Arabic",
158       "Katakana-Latin",
159       "Latin-Katakana",
160       //"Hebrew-Latin", // removed in 2.0
161       //"Latin-Hebrew",
162       "Cyrillic-Latin",
163       "Latin-Cyrillic",
164       "Devanagari-Latin",
165       "Latin-Devanagari",
166       "Any-Hex",
167       "Hex-Any"
168     };
169     for(uint32_t i=0; i<sizeof(TransID)/sizeof(TransID[0]); i=i+2){
170         Transliterator *trans1=Transliterator::createInstance(TransID[i], UTRANS_FORWARD, parseError, status);
171         if(t1 == 0){
172           errln("FAIL: in instantiation for" + TransID[i]);
173           continue;
174         }
175         Transliterator *inver1=trans1->createInverse(status);
176         if(inver1->getID() != TransID[i+1] )
177             errln("FAIL :getInverse() for " + TransID[i] + " returned " + inver1->getID() + " instead of " + TransID[i+1]);
178         delete inver1;
179         delete trans1;
180     }
181     delete t1;
182     delete t2;
183     delete invt1;
184     delete invt2;
185     delete inverse1;
186     delete inverse2;
187
188}
189
190void TransliteratorAPITest::TestClone(){
191    Transliterator *t1, *t2, *t3, *t4;
192    UErrorCode status = U_ZERO_ERROR;
193    UParseError parseError;
194    t1=Transliterator::createInstance("Latin-Devanagari", UTRANS_FORWARD, parseError, status);
195    t2=Transliterator::createInstance("Latin-Greek", UTRANS_FORWARD, parseError, status);
196    if(t1 == 0 || t2 == 0){
197        dataerrln("FAIL: construction - %s", u_errorName(status));
198        return;
199    }
200    t3=t1->clone();
201    t4=t2->clone();
202
203    if(t1->getID() != t3->getID() || t2->getID() != t4->getID() )
204        errln("FAIL: clone or getID failed");
205    if(t1->getID()==t4->getID() || t2->getID()==t3->getID() ||  t1->getID()==t4->getID())
206        errln("FAIL: clone or getID failed");
207
208    delete t1;
209    delete t2;
210    delete t3;
211    delete t4;
212
213}
214
215void TransliteratorAPITest::TestGetDisplayName() {
216    UnicodeString dispNames[]= {
217         //ID, displayName
218        //"CurlyQuotes-StraightQuotes" ,"CurlyQuotes to StraightQuotes",
219          "Any-Hex"                ,"Any to Hex Escape",
220          "Halfwidth-Fullwidth"        ,"Halfwidth to Fullwidth" ,
221          //"Latin-Arabic"               ,"Latin to Arabic"      ,
222          "Latin-Devanagari"           ,"Latin to Devanagari"  ,
223          "Greek-Latin"                ,"Greek to Latin"       ,
224          //"Arabic-Latin"               ,"Arabic to Latin"      ,
225          "Hex-Any"                ,"Hex Escape to Any",
226          "Cyrillic-Latin"             ,"Cyrillic to Latin"    ,
227          "Latin-Greek"                ,"Latin to Greek"       ,
228          "Latin-Katakana"                 ,"Latin to Katakana"        ,
229          //"Latin-Hebrew"               ,"Latin to Hebrew"      ,
230          "Katakana-Latin"                 ,"Katakana to Latin"
231      };
232    UnicodeString name="";
233    Transliterator* t;
234    UnicodeString message;
235    UErrorCode status = U_ZERO_ERROR;
236    UParseError parseError;
237
238#if UCONFIG_NO_FORMATTING
239    logln("Skipping, UCONFIG_NO_FORMATTING is set\n");
240    return;
241#else
242
243    for (uint32_t i=0; i<sizeof(dispNames)/sizeof(dispNames[0]); i=i+2 ) {
244        t = Transliterator::createInstance(dispNames[i+0], UTRANS_FORWARD, parseError, status);
245        if(t==0){
246             dataerrln("FAIL: construction: " + dispNames[i+0] + " - " + u_errorName(status));
247             status = U_ZERO_ERROR;
248             continue;
249        }
250        t->getDisplayName(t->getID(), name);
251        message="Display name for ID:" + t->getID();
252      //  doTest(message, name, dispNames[i+1]); //!!! This will obviously fail for any locale other than english and its children!!!
253        name="";
254        t->getDisplayName(t->getID(), Locale::getUS(), name);
255        message.remove();
256        message.append("Display name for on english locale ID:");
257        message.append(t->getID());
258    // message="Display name for on english locale ID:" + t->getID();
259        doTest(message, name, dispNames[i+1]);
260        name="";
261
262        delete t;
263    }
264#endif
265
266}
267
268void TransliteratorAPITest::TestTransliterate1(){
269
270    UnicodeString Data[]={
271         //ID, input string, transliterated string
272         "Any-Hex",         "hello",    UnicodeString("\\u0068\\u0065\\u006C\\u006C\\u006F", "") ,
273         "Hex-Any",         UnicodeString("\\u0068\\u0065\\u006C\\u006C\\u006F", ""), "hello"  ,
274         "Latin-Devanagari",CharsToUnicodeString("bha\\u0304rata"), CharsToUnicodeString("\\u092D\\u093E\\u0930\\u0924") ,
275         "Latin-Devanagari",UnicodeString("kra ksha khra gra cra dya dhya",""), CharsToUnicodeString("\\u0915\\u094D\\u0930 \\u0915\\u094D\\u0936 \\u0916\\u094D\\u0930 \\u0917\\u094D\\u0930 \\u091a\\u094D\\u0930 \\u0926\\u094D\\u092F \\u0927\\u094D\\u092F") ,
276
277         "Devanagari-Latin",    CharsToUnicodeString("\\u092D\\u093E\\u0930\\u0924"),        CharsToUnicodeString("bh\\u0101rata"),
278     //  "Contracted-Expanded", CharsToUnicodeString("\\u00C0\\u00C1\\u0042"),               CharsToUnicodeString("\\u0041\\u0300\\u0041\\u0301\\u0042") ,
279     //  "Expanded-Contracted", CharsToUnicodeString("\\u0041\\u0300\\u0041\\u0301\\u0042"), CharsToUnicodeString("\\u00C0\\u00C1\\u0042") ,
280         //"Latin-Arabic",        "aap",                                 CharsToUnicodeString("\\u0627\\u06A4")     ,
281         //"Arabic-Latin",        CharsToUnicodeString("\\u0627\\u06A4"),                      "aap"
282    };
283
284    UnicodeString gotResult;
285    UnicodeString temp;
286    UnicodeString message;
287    Transliterator* t;
288    logln("Testing transliterate");
289    UErrorCode status = U_ZERO_ERROR;
290    UParseError parseError;
291
292    for(uint32_t i=0;i<sizeof(Data)/sizeof(Data[0]); i=i+3){
293        t=Transliterator::createInstance(Data[i+0], UTRANS_FORWARD, parseError, status);
294        if(t==0){
295            dataerrln("FAIL: construction: " + Data[i+0] + " Error: "  + u_errorName(status));
296            dataerrln("PreContext: " + prettify(parseError.preContext) + " PostContext: " + prettify( parseError.postContext) );
297            status = U_ZERO_ERROR;
298            continue;
299        }
300        gotResult = Data[i+1];
301        t->transliterate(gotResult);
302        message=t->getID() + "->transliterate(UnicodeString, UnicodeString) for\n\t Source:" + prettify(Data[i+1]);
303        doTest(message, gotResult, Data[i+2]);
304
305        //doubt here
306        temp=Data[i+1];
307        t->transliterate(temp);
308        message.remove();
309        message.append(t->getID());
310        message.append("->transliterate(Replaceable) for \n\tSource:");
311        message.append(Data[i][1]);
312        doTest(message, temp, Data[i+2]);
313
314        callEverything(t, __LINE__);
315        delete t;
316    }
317}
318
319void TransliteratorAPITest::TestTransliterate2(){
320     //testing tranliterate(String text, int start, int limit, StringBuffer result)
321   UnicodeString Data2[]={
322         //ID, input string, start, limit, transliterated string
323         "Any-Hex",         "hello! How are you?",  "0", "5", UnicodeString("\\u0068\\u0065\\u006C\\u006C\\u006F", ""), UnicodeString("\\u0068\\u0065\\u006C\\u006C\\u006F! How are you?", "") ,
324         "Any-Hex",         "hello! How are you?",  "7", "12", UnicodeString("\\u0048\\u006F\\u0077\\u0020\\u0061", ""), UnicodeString("hello! \\u0048\\u006F\\u0077\\u0020\\u0061re you?", ""),
325         "Hex-Any",         CharsToUnicodeString("\\u0068\\u0065\\u006C\\u006C\\u006F\\u0021\\u0020"), "0", "5",  "hello", "hello! "  ,
326       //  "Contracted-Expanded", CharsToUnicodeString("\\u00C0\\u00C1\\u0042"),        "1", "2",  CharsToUnicodeString("\\u0041\\u0301"), CharsToUnicodeString("\\u00C0\\u0041\\u0301\\u0042") ,
327         "Devanagari-Latin",    CharsToUnicodeString("\\u092D\\u093E\\u0930\\u0924"), "0", "1",  "bha", CharsToUnicodeString("bha\\u093E\\u0930\\u0924") ,
328         "Devanagari-Latin",    CharsToUnicodeString("\\u092D\\u093E\\u0930\\u0924"), "1", "2",  CharsToUnicodeString("\\u0314\\u0101"), CharsToUnicodeString("\\u092D\\u0314\\u0101\\u0930\\u0924")
329
330    };
331    logln("\n   Testing transliterate(String, int, int, StringBuffer)");
332    Transliterator* t;
333    UnicodeString gotResBuf;
334    UnicodeString temp;
335    int32_t start, limit;
336    UErrorCode status = U_ZERO_ERROR;
337    UParseError parseError;
338
339    for(uint32_t i=0; i<sizeof(Data2)/sizeof(Data2[0]); i=i+6){
340        t=Transliterator::createInstance(Data2[i+0], UTRANS_FORWARD, parseError, status);
341        if(t==0){
342            dataerrln("FAIL: construction: " + prettify(Data2[i+0]) + " - " + u_errorName(status));
343            continue;
344        }
345        start=getInt(Data2[i+2]);
346        limit=getInt(Data2[i+3]);
347        Data2[i+1].extractBetween(start, limit, gotResBuf);
348        t->transliterate(gotResBuf);
349        //  errln("FAIL: calling transliterate on " + t->getID());
350        doTest(t->getID() + ".transliterate(UnicodeString, int32_t, int32_t, UnicodeString):(" + start + "," + limit + ")  for \n\t source: " + prettify(Data2[i+1]), gotResBuf, Data2[i+4]);
351
352        temp=Data2[i+1];
353        t->transliterate(temp, start, limit);
354        doTest(t->getID() + ".transliterate(Replaceable, int32_t, int32_t, ):(" + start + "," + limit + ")  for \n\t source: " + prettify(Data2[i+1]), temp, Data2[i+5]);
355        status = U_ZERO_ERROR;
356        callEverything(t, __LINE__);
357        delete t;
358        t = NULL;
359    }
360
361    status = U_ZERO_ERROR;
362    logln("\n   Try calling transliterate with illegal start and limit values");
363    t=Transliterator::createInstance("Any-Hex", UTRANS_FORWARD, parseError, status);
364    if(U_FAILURE(status)) {
365      errln("Error creating transliterator %s", u_errorName(status));
366      delete t;
367      return;
368    }
369    gotResBuf = temp = "try start greater than limit";
370    t->transliterate(gotResBuf, 10, 5);
371    if(gotResBuf == temp) {
372        logln("OK: start greater than limit value handled correctly");
373    } else {
374        errln("FAIL: start greater than limit value returned" + gotResBuf);
375    }
376
377    callEverything(t, __LINE__);
378    delete t;
379
380}
381void TransliteratorAPITest::TestTransliterate3(){
382    UnicodeString rs="This is the replaceable String";
383    UnicodeString Data[] = {
384        "0",  "0",  "This is the replaceable String",
385        "2",  "3",  UnicodeString("Th\\u0069s is the replaceable String", ""),
386        "21", "23", UnicodeString("Th\\u0069s is the repl\\u0061\\u0063eable String", ""),
387        "14", "17", UnicodeString("Th\\u0069s is t\\u0068\\u0065\\u0020repl\\u0061\\u0063eable String", ""),
388    };
389    int start, limit;
390    UnicodeString message;
391    UParseError parseError;
392    UErrorCode status = U_ZERO_ERROR;
393    Transliterator *t=Transliterator::createInstance("Any-Hex", UTRANS_FORWARD, parseError, status);
394    if(U_FAILURE(status)) {
395      errln("Error creating transliterator %s", u_errorName(status));
396      delete t;
397      return;
398    }
399
400    if(t == 0)
401        errln("FAIL : construction");
402    for(uint32_t i=0; i<sizeof(Data)/sizeof(Data[0]); i=i+3){
403        start=getInt(Data[i+0]);
404        limit=getInt(Data[i+1]);
405        t->transliterate(rs, start, limit);
406        message=t->getID() + ".transliterate(ReplaceableString, start, limit):("+start+","+limit+"):";
407        doTest(message, rs, Data[i+2]);
408    }
409    delete t;
410}
411
412void TransliteratorAPITest::TestSimpleKeyboardTransliterator(){
413    logln("simple call to transliterate");
414    UErrorCode status=U_ZERO_ERROR;
415    UParseError parseError;
416    Transliterator* t=Transliterator::createInstance("Any-Hex", UTRANS_FORWARD, parseError, status);
417    if(t == 0) {
418        UnicodeString context;
419
420        if (parseError.preContext[0]) {
421            context += (UnicodeString)" at " + parseError.preContext;
422        }
423        if (parseError.postContext[0]) {
424            context += (UnicodeString)" | " + parseError.postContext;
425        }
426        errln((UnicodeString)"FAIL: can't create Any-Hex, " +
427              (UnicodeString)u_errorName(status) + context);
428        return;
429    }
430    UTransPosition index={19,20,20,20};
431    UnicodeString rs= "Transliterate this-''";
432    UnicodeString insertion="abc";
433    UnicodeString expected=UnicodeString("Transliterate this-'\\u0061\\u0062\\u0063'", "");
434    t->transliterate(rs, index, insertion, status);
435    if(U_FAILURE(status))
436        errln("FAIL: " + t->getID()+ ".translitere(Replaceable, int[], UnicodeString, UErrorCode)-->" + (UnicodeString)u_errorName(status));
437    t->finishTransliteration(rs, index);
438    UnicodeString message="transliterate";
439    doTest(message, rs, expected);
440
441    logln("try calling transliterate with invalid index values");
442    UTransPosition index1[]={
443        //START, LIMIT, CURSOR
444        {10, 10, 12, 10},   //invalid since CURSOR>LIMIT valid:-START <= CURSOR <= LIMIT
445        {17, 16, 17, 17},   //invalid since START>LIMIT valid:-0<=START<=LIMIT
446        {-1, 16, 14, 16},   //invalid since START<0
447        {3,  50, 2,  50}    //invalid since LIMIT>text.length()
448    };
449    for(uint32_t i=0; i<sizeof(index1)/sizeof(index1[0]); i++){
450        status=U_ZERO_ERROR;
451        t->transliterate(rs, index1[i], insertion, status);
452        if(status == U_ILLEGAL_ARGUMENT_ERROR)
453            logln("OK: invalid index values handled correctly");
454        else
455            errln("FAIL: invalid index values didn't throw U_ILLEGAL_ARGUMENT_ERROR throw" + (UnicodeString)u_errorName(status));
456    }
457
458    delete t;
459}
460void TransliteratorAPITest::TestKeyboardTransliterator1(){
461    UnicodeString Data[]={
462        //insertion, buffer
463        "a",   UnicodeString("\\u0061", "")                                           ,
464        "bbb", UnicodeString("\\u0061\\u0062\\u0062\\u0062", "")                      ,
465        "ca",  UnicodeString("\\u0061\\u0062\\u0062\\u0062\\u0063\\u0061", "")        ,
466        " ",   UnicodeString("\\u0061\\u0062\\u0062\\u0062\\u0063\\u0061\\u0020", "") ,
467        "",    UnicodeString("\\u0061\\u0062\\u0062\\u0062\\u0063\\u0061\\u0020", "")   ,
468
469        "a",   UnicodeString("\\u0061", "")                                           ,
470        "b",   UnicodeString("\\u0061\\u0062", "")                                    ,
471        "z",   UnicodeString("\\u0061\\u0062\\u007A", "")                             ,
472        "",    UnicodeString("\\u0061\\u0062\\u007A", "")
473
474    };
475    UParseError parseError;
476    UErrorCode status = U_ZERO_ERROR;
477    Transliterator* t=Transliterator::createInstance("Any-Hex", UTRANS_FORWARD, parseError, status);
478    if(U_FAILURE(status)) {
479      errln("Error creating transliterator %s", u_errorName(status));
480      delete t;
481      return;
482    }
483    //keyboardAux(t, Data);
484    UTransPosition index={0, 0, 0, 0};
485    UnicodeString s;
486    uint32_t i;
487    logln("Testing transliterate(Replaceable, int32_t, UnicodeString, UErrorCode)");
488    for (i=0; i<10; i=i+2) {
489       UnicodeString log;
490       if (Data[i+0] != "") {
491           log = s + " + " + Data[i+0] + " -> ";
492           t->transliterate(s, index, Data[i+0], status);
493           if(U_FAILURE(status)){
494               errln("FAIL: " + t->getID()+ ".transliterate(Replaceable, int32_t[], UnicodeString, UErrorCode)-->" + (UnicodeString)u_errorName(status));
495           continue;
496           }
497       }else {
498           log = s + " => ";
499           t->finishTransliteration(s, index);
500       }
501       // Show the start index '{' and the cursor '|'
502       displayOutput(s, Data[i+1], log, index);
503
504    }
505
506    s="";
507    status=U_ZERO_ERROR;
508    index.contextStart = index.contextLimit = index.start = index.limit = 0;
509    logln("Testing transliterate(Replaceable, int32_t, UChar, UErrorCode)");
510    for(i=10; i<sizeof(Data)/sizeof(Data[0]); i=i+2){
511        UnicodeString log;
512         if (Data[i+0] != "") {
513           log = s + " + " + Data[i+0] + " -> ";
514           UChar c=Data[i+0].charAt(0);
515           t->transliterate(s, index, c, status);
516           if(U_FAILURE(status))
517               errln("FAIL: " + t->getID()+ ".transliterate(Replaceable, int32_t[], UChar, UErrorCode)-->" + (UnicodeString)u_errorName(status));
518               continue;
519         }else {
520           log = s + " => ";
521           t->finishTransliteration(s, index);
522         }
523        // Show the start index '{' and the cursor '|'
524        displayOutput(s, Data[i+1], log, index);
525    }
526
527    delete t;
528}
529
530void TransliteratorAPITest::TestKeyboardTransliterator2(){
531    UnicodeString Data[]={
532        //insertion, buffer, index[START], index[LIMIT], index[CURSOR]
533        //data for Any-Hex
534        "abc",    UnicodeString("Initial String: add-\\u0061\\u0062\\u0063-", ""),                     "19", "20", "20",
535        "a",      UnicodeString("In\\u0069\\u0061tial String: add-\\u0061\\u0062\\u0063-", ""),        "2",  "3",  "2" ,
536        "b",      UnicodeString("\\u0062In\\u0069\\u0061tial String: add-\\u0061\\u0062\\u0063-", ""), "0",  "0",  "0" ,
537        "",       UnicodeString("\\u0062In\\u0069\\u0061tial String: add-\\u0061\\u0062\\u0063-", ""), "0",  "0",  "0" ,
538        //data for Latin-Devanagiri
539        CharsToUnicodeString("a\\u0304"),     CharsToUnicodeString("Hindi -\\u0906-"),                            "6", "7", "6",
540        CharsToUnicodeString("ma\\u0304"),    CharsToUnicodeString("Hindi -\\u0906\\u092E\\u093E-"),              "7", "8", "7",
541        CharsToUnicodeString("ra\\u0304"),    CharsToUnicodeString("Hi\\u0930\\u093Endi -\\u0906\\u092E\\u093E-"),"1", "2", "2",
542        CharsToUnicodeString(""),       CharsToUnicodeString("Hi\\u0930\\u093Endi -\\u0906\\u092E\\u093E-"),"1", "2", "2"
543        //data for contracted-Expanded
544     //   CharsToUnicodeString("\\u00C1"), CharsToUnicodeString("Ad\\u0041\\u0301d here:"),             "1",  "2",  "1" ,
545     //   CharsToUnicodeString("\\u00C0"), CharsToUnicodeString("Ad\\u0041\\u0301d here:\\u0041\\u0300"), "11", "11", "11",
546     //   "",     CharsToUnicodeString("Ad\\u0041\\u0301d here:\\u0041\\u0300"), "11", "11", "11",
547    };
548    Transliterator *t;
549    UnicodeString rs;
550    UnicodeString dataStr;
551    logln("Testing transliterate(Replaceable, int32_t, UnicodeString, UErrorCode)");
552    UErrorCode status = U_ZERO_ERROR;
553    UParseError parseError;
554    rs="Initial String: add--";
555    t=Transliterator::createInstance("Any-Hex", UTRANS_FORWARD, parseError, status);
556    if(t == 0)
557        dataerrln("FAIL : construction - %s", u_errorName(status));
558    else {
559        keyboardAux(t, Data, rs, 0, 20);
560        delete t;
561    }
562
563    rs="Hindi --";
564    t=Transliterator::createInstance("Latin-Devanagari", UTRANS_FORWARD, parseError, status);
565    if(t == 0)
566        dataerrln("FAIL : construction - %s", u_errorName(status));
567    else
568        keyboardAux(t, Data, rs, 20, 40);
569
570
571  //  rs="Add here:";
572 //   t=Transliterator::createInstance("Contracted-Expanded");
573 //   keyboardAux(t, Data, rs, 35, 55);
574
575
576    delete t;
577}
578
579void TransliteratorAPITest::TestKeyboardTransliterator3(){
580    UnicodeString s="This is the main string";
581    UnicodeString Data[] = {
582        "0", "0", "0",  "This is the main string",
583        "1", "3", "2",  UnicodeString("Th\\u0069s is the main string", ""),
584        "20", "21", "20",  UnicodeString("Th\\u0069s is the mai\\u006E string", "")
585    };
586
587    UErrorCode status=U_ZERO_ERROR;
588    UParseError parseError;
589    UTransPosition index={0, 0, 0, 0};
590    logln("Testing transliterate(Replaceable, int32_t, UErrorCode)");
591    Transliterator *t=Transliterator::createInstance("Any-Hex", UTRANS_FORWARD, parseError, status);
592    if(t == 0 || U_FAILURE(status)) {
593      errln("Error creating transliterator %s", u_errorName(status));
594      delete t;
595      return;
596    }
597    for(uint32_t i=0; i<sizeof(Data)/sizeof(Data[0]); i=i+4){
598        UnicodeString log;
599        index.contextStart=getInt(Data[i+0]);
600        index.contextLimit=index.limit=getInt(Data[i+1]);
601        index.start=getInt(Data[i+2]);
602        t->transliterate(s, index, status);
603        if(U_FAILURE(status)){
604           errln("FAIL: " + t->getID()+ ".transliterate(Replaceable, int32_t[], UErrorCode)-->" + (UnicodeString)u_errorName(status));
605           continue;
606        }
607        t->finishTransliteration(s, index);
608        log = s + " => ";
609        // Show the start index '{' and the cursor '|'
610        displayOutput(s, Data[i+3], log, index);
611    }
612
613    delete t;
614}
615void TransliteratorAPITest::TestNullTransliterator(){
616    UErrorCode status=U_ZERO_ERROR;
617    UnicodeString s("Transliterate using null transliterator");
618    Transliterator *nullTrans=Transliterator::createInstance("Any-Null", UTRANS_FORWARD, status);
619    int32_t transLimit;
620    int32_t start=0;
621    int32_t limit=s.length();
622    UnicodeString replaceable=s;
623    transLimit=nullTrans->transliterate(replaceable, start, limit);
624    if(transLimit != limit){
625        errln("ERROR: NullTransliterator->transliterate() failed");
626    }
627    doTest((UnicodeString)"nulTrans->transliterate", replaceable, s);
628    replaceable.remove();
629    replaceable.append(s);
630    UTransPosition index;
631    index.contextStart =start;
632    index.contextLimit = limit;
633    index.start = 0;
634    index.limit = limit;
635    nullTrans->finishTransliteration(replaceable, index);
636    if(index.start != limit){
637        errln("ERROR: NullTransliterator->handleTransliterate() failed");
638    }
639    doTest((UnicodeString)"NullTransliterator->handleTransliterate", replaceable, s);
640    callEverything(nullTrans, __LINE__);
641    delete nullTrans;
642
643
644}
645void TransliteratorAPITest::TestRegisterUnregister(){
646
647   UErrorCode status=U_ZERO_ERROR;
648    /* Make sure it doesn't exist */
649   if (Transliterator::createInstance("TestA-TestB", UTRANS_FORWARD, status) != NULL) {
650      errln("FAIL: TestA-TestB already registered\n");
651      return;
652   }
653   /* Check inverse too
654   if (Transliterator::createInstance("TestA-TestB",
655                                      (UTransDirection)UTRANS_REVERSE) != NULL) {
656      errln("FAIL: TestA-TestB inverse already registered\n");
657      return;
658   }
659   */
660   status =U_ZERO_ERROR;
661
662   /* Create it */
663   UParseError parseError;
664   Transliterator *t = Transliterator::createFromRules("TestA-TestB",
665                                                   "a<>b",
666                                                   UTRANS_FORWARD, parseError,
667                                                   status);
668   /* Register it */
669   Transliterator::registerInstance(t);
670
671   /* Now check again -- should exist now*/
672   Transliterator *s = Transliterator::createInstance("TestA-TestB", UTRANS_FORWARD, status);
673   if (s == NULL) {
674      errln("FAIL: TestA-TestB not registered\n");
675      return;
676   }
677   callEverything(s, __LINE__);
678   callEverything(t, __LINE__);
679   delete s;
680
681   /* Check inverse too
682   s = Transliterator::createInstance("TestA-TestB",
683                                      (UTransDirection)UTRANS_REVERSE);
684   if (s == NULL) {
685      errln("FAIL: TestA-TestB inverse not registered\n");
686      return;
687   }
688   delete s;
689   */
690
691   /*unregister the instance*/
692   Transliterator::unregister("TestA-TestB");
693   /* now Make sure it doesn't exist */
694   if (Transliterator::createInstance("TestA-TestB", UTRANS_FORWARD, status) != NULL) {
695      errln("FAIL: TestA-TestB isn't unregistered\n");
696      return;
697   }
698
699}
700
701
702int gTestFilter1ClassID = 0;
703int gTestFilter2ClassID = 0;
704int gTestFilter3ClassID = 0;
705
706/**
707 * Used by TestFiltering().
708 */
709class TestFilter1 : public UnicodeFilter {
710    UClassID getDynamicClassID()const { return &gTestFilter1ClassID; }
711    virtual UnicodeFunctor* clone() const {
712        return new TestFilter1(*this);
713    }
714    virtual UBool contains(UChar32 c) const {
715       if(c==0x63 || c==0x61 || c==0x43 || c==0x41)
716          return FALSE;
717       else
718          return TRUE;
719    }
720    // Stubs
721    virtual UnicodeString& toPattern(UnicodeString& result,
722                                     UBool /*escapeUnprintable*/) const {
723        return result;
724    }
725    virtual UBool matchesIndexValue(uint8_t /*v*/) const {
726        return FALSE;
727    }
728    virtual void addMatchSetTo(UnicodeSet& /*toUnionTo*/) const {}
729};
730class TestFilter2 : public UnicodeFilter {
731    UClassID getDynamicClassID()const { return &gTestFilter2ClassID; }
732    virtual UnicodeFunctor* clone() const {
733        return new TestFilter2(*this);
734    }
735    virtual UBool contains(UChar32 c) const {
736        if(c==0x65 || c==0x6c)
737           return FALSE;
738        else
739           return TRUE;
740    }
741    // Stubs
742    virtual UnicodeString& toPattern(UnicodeString& result,
743                                     UBool /*escapeUnprintable*/) const {
744        return result;
745    }
746    virtual UBool matchesIndexValue(uint8_t /*v*/) const {
747        return FALSE;
748    }
749    virtual void addMatchSetTo(UnicodeSet& /*toUnionTo*/) const {}
750};
751class TestFilter3 : public UnicodeFilter {
752    UClassID getDynamicClassID()const { return &gTestFilter3ClassID; }
753    virtual UnicodeFunctor* clone() const {
754        return new TestFilter3(*this);
755    }
756    virtual UBool contains(UChar32 c) const {
757        if(c==0x6f || c==0x77)
758           return FALSE;
759        else
760           return TRUE;
761    }
762    // Stubs
763    virtual UnicodeString& toPattern(UnicodeString& result,
764                                     UBool /*escapeUnprintable*/) const {
765        return result;
766    }
767    virtual UBool matchesIndexValue(uint8_t /*v*/) const {
768        return FALSE;
769    }
770    virtual void addMatchSetTo(UnicodeSet& /*toUnionTo*/) const {}
771};
772
773
774void TransliteratorAPITest::TestGetAdoptFilter(){
775    UErrorCode status = U_ZERO_ERROR;
776    UParseError parseError;
777    Transliterator *t=Transliterator::createInstance("Any-Hex", UTRANS_FORWARD, parseError, status);
778    if(t == 0 || U_FAILURE(status)) {
779        errln("Error creating transliterator %s", u_errorName(status));
780        delete t;
781        return;
782    }
783    const UnicodeFilter *u=t->getFilter();
784    if(u != NULL){
785        errln("FAIL: getFilter failed. Didn't return null when the transliterator used no filtering");
786        delete t;
787        return;
788    }
789
790    UnicodeString got, temp, message;
791    UnicodeString data="ABCabcbbCBa";
792    temp = data;
793    t->transliterate(temp);
794    t->adoptFilter(new TestFilter1);
795
796    got = data;
797    t->transliterate(got);
798    UnicodeString exp=UnicodeString("A\\u0042Ca\\u0062c\\u0062\\u0062C\\u0042a", "");
799    message="transliteration after adoptFilter(a,A,c,C) ";
800    doTest(message, got, exp);
801
802    logln("Testing round trip");
803    t->adoptFilter((UnicodeFilter*)u);
804    if(t->getFilter() == NULL)
805       logln("OK: adoptFilter and getFilter round trip worked");
806    else
807       errln("FAIL: adoptFilter or getFilter round trip failed");
808
809    got = data;
810    t->transliterate(got);
811    exp=UnicodeString("\\u0041\\u0042\\u0043\\u0061\\u0062\\u0063\\u0062\\u0062\\u0043\\u0042\\u0061", "");
812    message="transliteration after adopting null filter";
813    doTest(message, got, exp);
814    message="adoptFilter round trip";
815    doTest("adoptFilter round trip", got, temp);
816
817    t->adoptFilter(new TestFilter2);
818    callEverything(t, __LINE__);
819    data="heelloe";
820    exp=UnicodeString("\\u0068eell\\u006Fe", "");
821    got = data;
822    t->transliterate(got);
823    message="transliteration using (e,l) filter";
824    doTest("transliteration using (e,l) filter", got, exp);
825
826    data="are well";
827    exp=UnicodeString("\\u0061\\u0072e\\u0020\\u0077ell", "");
828    got = data;
829    t->transliterate(got);
830    doTest(message, got, exp);
831
832    t->adoptFilter(new TestFilter3);
833    data="ho, wow!";
834    exp=UnicodeString("\\u0068o\\u002C\\u0020wow\\u0021", "");
835    got = data;
836    t->transliterate(got);
837    message="transliteration using (o,w) filter";
838    doTest("transliteration using (o,w) filter", got, exp);
839
840    data="owl";
841    exp=UnicodeString("ow\\u006C", "");
842    got = data;
843    t->transliterate(got);
844    doTest("transliteration using (o,w) filter", got, exp);
845
846    delete t;
847
848}
849
850
851
852void TransliteratorAPITest::keyboardAux(Transliterator *t, UnicodeString DATA[], UnicodeString& s, int32_t begin, int32_t end) {
853    UTransPosition index={0, 0, 0, 0};
854    UErrorCode status=U_ZERO_ERROR;
855    for (int32_t i=begin; i<end; i=i+5) {
856        UnicodeString log;
857        if (DATA[i+0] != "") {
858             log = s + " + " + DATA[i] + " -> ";
859             index.contextStart=getInt(DATA[i+2]);
860             index.contextLimit=index.limit=getInt(DATA[i+3]);
861             index.start=getInt(DATA[i+4]);
862             t->transliterate(s, index, DATA[i+0], status);
863             if(U_FAILURE(status)){
864                 errln("FAIL: " + t->getID()+ ".transliterate(Replaceable, int32_t[], UnicodeString, UErrorCode)-->" + (UnicodeString)u_errorName(status));
865             continue;
866             }
867           log = s + " => ";
868           t->finishTransliteration(s, index);
869        }
870         // Show the start index '{' and the cursor '|'
871      displayOutput(s, DATA[i+1], log, index);
872
873    }
874}
875
876void TransliteratorAPITest::displayOutput(const UnicodeString& got, const UnicodeString& expected, UnicodeString& log, UTransPosition& index){
877 // Show the start index '{' and the cursor '|'
878    UnicodeString a, b, c, d, e;
879    got.extractBetween(0, index.contextStart, a);
880    got.extractBetween(index.contextStart, index.start, b);
881    got.extractBetween(index.start, index.limit, c);
882    got.extractBetween(index.limit, index.contextLimit, d);
883    got.extractBetween(index.contextLimit, got.length(), e);
884    log.append(a).
885        append((UChar)0x7b/*{*/).
886        append(b).
887        append((UChar)0x7c/*|*/).
888        append(c).
889        append((UChar)0x7c).
890        append(d).
891        append((UChar)0x7d/*}*/).
892        append(e);
893    if (got == expected)
894        logln("OK:" + prettify(log));
895    else
896        errln("FAIL: " + prettify(log)  + ", expected " + prettify(expected));
897}
898
899
900/*Internal Functions used*/
901void TransliteratorAPITest::doTest(const UnicodeString& message, const UnicodeString& result, const UnicodeString& expected){
902    if (prettify(result) == prettify(expected))
903        logln((UnicodeString)"Ok: " + prettify(message) + " passed \"" + prettify(expected) + "\"");
904    else
905        dataerrln((UnicodeString)"FAIL:" + message + " failed  Got-->" + prettify(result)+ ", Expected--> " + prettify(expected) );
906}
907
908
909//
910//  callEverything    call all of the const (non-destructive) methods on a
911//                    transliterator, just to verify that they don't fail in some
912//                    destructive way.
913//
914#define CEASSERT(a) {if (!(a)) { \
915errln("FAIL at line %d from line %d: %s", __LINE__, line, #a);  return; }}
916
917void TransliteratorAPITest::callEverything(const Transliterator *tr, int line) {
918    Transliterator *clonedTR = tr->clone();
919    CEASSERT(clonedTR != NULL);
920
921    int32_t  maxcl = tr->getMaximumContextLength();
922    CEASSERT(clonedTR->getMaximumContextLength() == maxcl);
923
924    UnicodeString id;
925    UnicodeString clonedId;
926    id = tr->getID();
927    clonedId = clonedTR->getID();
928    CEASSERT(id == clonedId);
929
930    const UnicodeFilter *filter = tr->getFilter();
931    const UnicodeFilter *clonedFilter = clonedTR->getFilter();
932    if (filter == NULL || clonedFilter == NULL) {
933        // If one filter is NULL they better both be NULL.
934        CEASSERT(filter == clonedFilter);
935    } else {
936        CEASSERT(filter != clonedFilter);
937    }
938
939    UnicodeString rules;
940    UnicodeString clonedRules;
941    rules = tr->toRules(rules, FALSE);
942    clonedRules = clonedTR->toRules(clonedRules, FALSE);
943    CEASSERT(rules == clonedRules);
944
945    UnicodeSet sourceSet;
946    UnicodeSet clonedSourceSet;
947    tr->getSourceSet(sourceSet);
948    clonedTR->getSourceSet(clonedSourceSet);
949    CEASSERT(clonedSourceSet == sourceSet);
950
951    UnicodeSet targetSet;
952    UnicodeSet clonedTargetSet;
953    tr->getTargetSet(targetSet);
954    clonedTR->getTargetSet(clonedTargetSet);
955    CEASSERT(targetSet == clonedTargetSet);
956
957    UClassID classID = tr->getDynamicClassID();
958    CEASSERT(classID == clonedTR->getDynamicClassID());
959    CEASSERT(classID != 0);
960
961    delete clonedTR;
962}
963
964static const int MyUnicodeFunctorTestClassID = 0;
965class MyUnicodeFunctorTestClass : public UnicodeFunctor {
966public:
967    virtual UnicodeFunctor* clone() const {return NULL;}
968    static UClassID getStaticClassID(void) {return (UClassID)&MyUnicodeFunctorTestClassID;}
969    virtual UClassID getDynamicClassID(void) const {return getStaticClassID();};
970    virtual void setData(const TransliterationRuleData*) {}
971};
972
973void TransliteratorAPITest::TestUnicodeFunctor() {
974    MyUnicodeFunctorTestClass myClass;
975    if (myClass.toMatcher() != NULL) {
976        errln("FAIL: UnicodeFunctor::toMatcher did not return NULL");
977    }
978    if (myClass.toReplacer() != NULL) {
979        errln("FAIL: UnicodeFunctor::toReplacer did not return NULL");
980    }
981}
982
983
984#endif /* #if !UCONFIG_NO_TRANSLITERATION */
985