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