1/***************************************************************************
2*
3*   Copyright (C) 2000-2009, International Business Machines
4*   Corporation and others.  All Rights Reserved.
5*
6************************************************************************
7*   Date        Name        Description
8*   03/09/2000   Madhu        Creation.
9************************************************************************/
10
11#include "unicode/utypes.h"
12
13#if !UCONFIG_NO_TRANSLITERATION
14
15#include "cpdtrtst.h"
16#include "unicode/utypes.h"
17#include "unicode/translit.h"
18#include "unicode/uniset.h"
19#include "cpdtrans.h"
20#include "cmemory.h"
21
22//---------------------------------------------
23// runIndexedTest
24//---------------------------------------------
25
26void
27CompoundTransliteratorTest::runIndexedTest(int32_t index, UBool exec,
28                                           const char* &name, char* /*par*/) {
29    switch (index) {
30        TESTCASE(0,TestConstruction);
31        TESTCASE(1,TestCloneEqual);
32        TESTCASE(2,TestGetCount);
33        TESTCASE(3,TestGetSetAdoptTransliterator);
34        TESTCASE(4,TestTransliterate);
35        default: name = ""; break;
36    }
37}
38
39void CompoundTransliteratorTest::TestConstruction(){
40     logln("Testing the construction of the compound Transliterator");
41   UnicodeString names[]={"Greek-Latin", "Latin-Devanagari", "Devanagari-Latin", "Latin-Greek"};
42   UParseError parseError;
43   UErrorCode status=U_ZERO_ERROR;
44   Transliterator* t1=Transliterator::createInstance(names[0], UTRANS_FORWARD, parseError, status);
45   Transliterator* t2=Transliterator::createInstance(names[1], UTRANS_FORWARD, parseError, status);
46   Transliterator* t3=Transliterator::createInstance(names[2], UTRANS_FORWARD, parseError, status);
47   Transliterator* t4=Transliterator::createInstance(names[3], UTRANS_FORWARD, parseError, status);
48   if(U_FAILURE(status)){
49       dataerrln("Transliterator construction failed - %s", u_errorName(status));
50       return;
51   }
52
53
54   Transliterator* transarray1[]={t1};
55   Transliterator* transarray2[]={t1, t4};
56   Transliterator* transarray3[]={t4, t1, t2};
57   Transliterator* transarray4[]={t1, t2, t3, t4};
58
59   Transliterator** transarray[4];
60   transarray[0] = transarray1;
61   transarray[1] = transarray2;
62   transarray[2] = transarray3;
63   transarray[3] = transarray4;
64
65   const UnicodeString IDs[]={
66       names[0],
67       names[0]+";"+names[3],
68       names[3]+";"+names[1]+";"+names[2],
69       names[0]+";"+names[1]+";"+names[2]+";"+names[3]
70   };
71
72   uint16_t i=0;
73   for(i=0; i<4; i++){
74       status = U_ZERO_ERROR;
75       CompoundTransliterator *cpdtrans=new CompoundTransliterator(IDs[i],parseError, status);
76       if (U_FAILURE(status)) {
77           errln("Construction using CompoundTransliterator(UnicodeString&, Direction, UnicodeFilter*)  failed");
78       }
79       delete cpdtrans;
80
81       CompoundTransliterator *cpdtrans2=new CompoundTransliterator(transarray[i], i+1);
82       if(cpdtrans2 == 0){
83           errln("Construction using CompoundTransliterator(Transliterator* const transliterators[], "
84                           "int32_t count, UnicodeFilter* adoptedFilter = 0)  failed");
85           continue;
86       }
87       CompoundTransliterator *copycpd=new CompoundTransliterator(*cpdtrans2);
88       if(copycpd->getCount() != cpdtrans2->getCount() || copycpd->getID() != cpdtrans2->getID()) {
89           errln("Copy construction failed");
90           continue;
91       }
92
93
94       delete copycpd;
95       delete cpdtrans2;
96
97   }
98   {
99    /*Test Jitterbug 914 */
100    UErrorCode err = U_ZERO_ERROR;
101    CompoundTransliterator  cpdTrans(UnicodeString("Latin-Hangul"),UTRANS_REVERSE,NULL,parseError,err);
102    UnicodeString newID =cpdTrans.getID();
103    if(newID!=UnicodeString("Hangul-Latin")){
104        errln(UnicodeString("Test for Jitterbug 914 for cpdTrans(UnicodeString(\"Latin-Hangul\"),UTRANS_REVERSE,NULL,err) failed"));
105    }
106   }
107   delete t1;
108   delete t2;
109   delete t3;
110   delete t4;
111
112}
113
114void CompoundTransliteratorTest::TestCloneEqual(){
115    logln("Testing the clone() and equality operator functions of Compound Transliterator");
116    UErrorCode status = U_ZERO_ERROR;
117    UParseError parseError;
118    CompoundTransliterator  *ct1=new CompoundTransliterator("Greek-Latin;Latin-Devanagari",parseError,status);
119    if(U_FAILURE(status)){
120        dataerrln("construction failed - %s", u_errorName(status));
121        delete ct1;
122        return;
123    }
124    CompoundTransliterator  *ct2=new CompoundTransliterator("Greek-Latin", parseError, status);
125    if(U_FAILURE(status)){
126        errln("construction failed");
127        delete ct1;
128        delete ct2;
129        return;
130    }
131    CompoundTransliterator *copyct1=new CompoundTransliterator(*ct1);
132    if(copyct1 == 0){
133        errln("copy construction failed");
134        return;
135    }
136    CompoundTransliterator *copyct2=new CompoundTransliterator(*ct2);
137    if(copyct2 == 0){
138        errln("copy construction failed");
139        return;
140    }
141    CompoundTransliterator equalct1=*copyct1;
142    CompoundTransliterator equalct2=*copyct2;
143
144    if(copyct1->getID()     != ct1->getID()    || copyct2->getID()    != ct2->getID()    ||
145        copyct1->getCount() != ct1->getCount() || copyct2->getCount() != ct2->getCount() ||
146        copyct2->getID()    == ct1->getID()    || copyct1->getID()    == ct2->getID()    ||
147        copyct2->getCount() == ct1->getCount() || copyct1->getCount() == ct2->getCount() ){
148        errln("Error: copy constructors failed");
149    }
150
151    if(equalct1.getID()     != ct1->getID()        || equalct2.getID()    != ct2->getID()     ||
152        equalct1.getID()    != copyct1->getID()    || equalct2.getID()    != copyct2->getID() ||
153        equalct1.getCount() != ct1->getCount()     || equalct2.getCount() != ct2->getCount()  ||
154        copyct2->getID()    == ct1->getID()        || copyct1->getID()    == ct2->getID()     ||
155        equalct1.getCount() != copyct1->getCount() || equalct2.getCount() != copyct2->getCount() ||
156        equalct2.getCount() == ct1->getCount()     || equalct1.getCount() == ct2->getCount() ) {
157        errln("Error: =operator or copy constructor failed");
158    }
159
160    CompoundTransliterator *clonect1a=(CompoundTransliterator*)ct1->clone();
161    CompoundTransliterator *clonect1b=(CompoundTransliterator*)equalct1.clone();
162    CompoundTransliterator *clonect2a=(CompoundTransliterator*)ct2->clone();
163    CompoundTransliterator *clonect2b=(CompoundTransliterator*)copyct2->clone();
164
165
166    if(clonect1a->getID()  != ct1->getID()       || clonect1a->getCount() != ct1->getCount()        ||
167        clonect1a->getID() != clonect1b->getID() || clonect1a->getCount() != clonect1b->getCount()  ||
168        clonect1a->getID() != equalct1.getID()   || clonect1a->getCount() != equalct1.getCount()    ||
169        clonect1a->getID() != copyct1->getID()   || clonect1a->getCount() != copyct1->getCount()    ||
170
171        clonect2b->getID() != ct2->getID()       || clonect2a->getCount() != ct2->getCount()        ||
172        clonect2a->getID() != clonect2b->getID() || clonect2a->getCount() != clonect2b->getCount()  ||
173        clonect2a->getID() != equalct2.getID()   || clonect2a->getCount() != equalct2.getCount()    ||
174        clonect2b->getID() != copyct2->getID()   || clonect2b->getCount() != copyct2->getCount()  ) {
175        errln("Error: clone() failed");
176    }
177
178    delete ct1;
179    delete ct2;
180    delete copyct1;
181    delete copyct2;
182    delete clonect1a;
183    delete clonect1b;
184    delete clonect2a;
185    delete clonect2b;
186
187}
188
189void CompoundTransliteratorTest::TestGetCount(){
190    logln("Testing the getCount() API of CompoundTransliterator");
191    UErrorCode status = U_ZERO_ERROR;
192    UParseError parseError;
193    CompoundTransliterator *ct1=new CompoundTransliterator("Halfwidth-Fullwidth;Fullwidth-Halfwidth", parseError, status);
194    CompoundTransliterator *ct2=new CompoundTransliterator("Any-Hex;Hex-Any;Cyrillic-Latin;Latin-Cyrillic", parseError, status);
195    CompoundTransliterator *ct3=(CompoundTransliterator*)ct1;
196    if (U_FAILURE(status)) {
197        dataerrln("FAILED: CompoundTransliterator constructor failed - %s", u_errorName(status));
198        return;
199    }
200    CompoundTransliterator *ct4=new CompoundTransliterator("Latin-Devanagari", parseError, status);
201    CompoundTransliterator *ct5=new CompoundTransliterator(*ct4);
202
203    if (U_FAILURE(status)) {
204        errln("FAILED: CompoundTransliterator constructor failed");
205        return;
206    }
207    if(ct1->getCount() == ct2->getCount() || ct1->getCount() != ct3->getCount() ||
208        ct2->getCount() == ct3->getCount() ||
209        ct4->getCount() != ct5->getCount() || ct4->getCount() == ct1->getCount() ||
210        ct4->getCount() == ct2->getCount() || ct4->getCount() == ct3->getCount()  ||
211        ct5->getCount() == ct2->getCount() || ct5->getCount() == ct3->getCount()  ) {
212        errln("Error: getCount() failed");
213    }
214
215    /* Quick test getTargetSet(), only test that it doesn't die.  TODO:  a better test. */
216    UnicodeSet ts;
217    UnicodeSet *retUS = NULL;
218    retUS = &ct1->getTargetSet(ts);
219    if (retUS != &ts || ts.size() == 0) {
220        errln("CompoundTransliterator::getTargetSet() failed.\n");
221    }
222
223    /* Quick test getSourceSet(), only test that it doesn't die.  TODO:  a better test. */
224    UnicodeSet ss;
225    retUS = NULL;
226    retUS = &ct1->getSourceSet(ss);
227    if (retUS != &ss || ss.size() == 0) {
228        errln("CompoundTransliterator::getSourceSet() failed.\n");
229    }
230
231    delete ct1;
232    delete ct2;
233    delete ct4;
234    delete ct5;
235}
236
237void CompoundTransliteratorTest::TestGetSetAdoptTransliterator(){
238    logln("Testing the getTransliterator() API of CompoundTransliterator");
239    UnicodeString ID("Latin-Greek;Greek-Latin;Latin-Devanagari;Devanagari-Latin;Latin-Cyrillic;Cyrillic-Latin;Any-Hex;Hex-Any");
240    UErrorCode status = U_ZERO_ERROR;
241    UParseError parseError;
242    CompoundTransliterator *ct1=new CompoundTransliterator(ID, parseError, status);
243    if(U_FAILURE(status)){
244        dataerrln("CompoundTransliterator construction failed - %s", u_errorName(status));
245        return;
246    }
247    int32_t count=ct1->getCount();
248    UnicodeString *array=split(ID, 0x003b, count);
249    int i;
250    for(i=0; i < count; i++){
251        UnicodeString child= ct1->getTransliterator(i).getID();
252        if(child != *(array+i)){
253            errln("Error getTransliterator() failed: Expected->" + *(array+i) + " Got->" + child);
254        }else {
255            logln("OK: getTransliterator() passed: Expected->" + *(array+i) + " Got->" + child);
256        }
257    }
258    delete []array;
259
260    logln("Testing setTransliterator() API of CompoundTransliterator");
261    UnicodeString ID2("Hex-Any;Any-Hex;Latin-Cyrillic;Cyrillic-Latin;Halfwidth-Fullwidth;Fullwidth-Halfwidth");
262    array=split(ID2, 0x003b, count);
263    Transliterator** transarray=new Transliterator*[count];
264    for(i=0;i<count;i++){
265        transarray[i]=Transliterator::createInstance(*(array+i), UTRANS_FORWARD, parseError, status);
266        if(U_FAILURE(status)){
267            errln("Error could not create Transliterator with ID :"+*(array+i));
268        }else{
269            logln("The ID for the transltierator created is " + transarray[i]->getID());
270        }
271        status = U_ZERO_ERROR;
272    }
273
274    /*setTransliterator and adoptTransliterator */
275
276    ct1->setTransliterators(transarray, count);
277    if(ct1->getCount() != count || ct1->getID() != ID2){
278        errln((UnicodeString)"Error: setTransliterators() failed.\n\t Count:- expected->" + count + (UnicodeString)".  got->" + ct1->getCount() +
279                                                   (UnicodeString)"\n\tID   :- expected->" + ID2 + (UnicodeString)".  got->" + ct1->getID());
280    }
281    else{
282        logln("OK: setTransliterators() passed");
283    }
284    /*UnicodeString temp;
285    for(i=0;i<count-1;i++){
286        temp.append(ct1->getTransliterator(i).getID());
287        temp.append(";");
288    }
289    temp.append(ct1->getTransliterator(i).getID());
290    if(temp != ID2){
291        errln("Error: setTransliterator() failed.  Expected->" + ID2 + "\nGot->" + temp);
292    }
293    else{
294        logln("OK: setTransliterator() passed");
295    }*/
296    logln("Testing adoptTransliterator() API of CompoundTransliterator");
297    UnicodeString ID3("Latin-Katakana");
298    Transliterator **transarray2=(Transliterator **)uprv_malloc(sizeof(Transliterator*)*1);
299    transarray2[0] = Transliterator::createInstance(ID3,UTRANS_FORWARD,parseError,status);
300    if (transarray2[0] != 0) {
301        ct1->adoptTransliterators(transarray2, 1);
302    }
303    if(ct1->getCount() != 1 || ct1->getID() != ID3){
304        errln((UnicodeString)"Error: adoptTransliterators() failed.\n\t Count:- expected->1" + (UnicodeString)".  got->" + ct1->getCount() +
305                                                   (UnicodeString)"\n\tID   :- expected->" + ID3 + (UnicodeString)".  got->" + ct1->getID());
306    }
307    else{
308        logln("OK: adoptTranslterator() passed");
309    }
310    delete ct1;
311    for(i=0;i<count;i++){
312        delete transarray[i];
313    }
314    delete []transarray;
315    delete []array;
316}
317
318/**
319 * Splits a UnicodeString
320 */
321UnicodeString* CompoundTransliteratorTest::split(const UnicodeString& str, UChar seperator, int32_t& count) {
322
323    //get the count
324    int32_t i;
325    count =1;
326    for(i=0; i<str.length(); i++){
327        if(str.charAt(i) == seperator)
328            count++;
329    }
330    // make an array
331    UnicodeString* result = new UnicodeString[count];
332    int32_t last = 0;
333    int32_t current = 0;
334    for (i = 0; i < str.length(); ++i) {
335        if (str.charAt(i) == seperator) {
336            str.extractBetween(last, i, result[current]);
337            last = i+1;
338            current++;
339        }
340    }
341    str.extractBetween(last, i, result[current]);
342    return result;
343}
344void CompoundTransliteratorTest::TestTransliterate(){
345    logln("Testing the handleTransliterate() API of CompoundTransliterator");
346    UErrorCode status = U_ZERO_ERROR;
347    UParseError parseError;
348    CompoundTransliterator *ct1=new CompoundTransliterator("Any-Hex;Hex-Any",parseError, status);
349    if(U_FAILURE(status)){
350        errln("CompoundTransliterator construction failed");
351    }else {
352#if 0
353    // handleTransliterate is a protected method that was erroneously made
354    // public.  It is not public API that needs to be tested.
355        UnicodeString s("abcabc");
356        expect(*ct1, s, s);
357        UTransPosition index = { 0, 0, 0, 0 };
358        UnicodeString rsource2(s);
359        UnicodeString expectedResult=s;
360        ct1->handleTransliterate(rsource2, index, FALSE);
361        expectAux(ct1->getID() + ":String, index(0,0,0), incremental=FALSE", rsource2 + "->" + rsource2, rsource2==expectedResult, expectedResult);
362        UTransPosition _index = {1,3,2,3};
363        uprv_memcpy(&index, &_index, sizeof(index));
364        UnicodeString rsource3(s);
365        ct1->handleTransliterate(rsource3, index, TRUE);
366        expectAux(ct1->getID() + ":String, index(1,2,3), incremental=TRUE", rsource3 + "->" + rsource3, rsource3==expectedResult, expectedResult);
367#endif
368    }
369    delete ct1;
370    UnicodeString Data[]={
371             //ID, input string, transliterated string
372             "Any-Hex;Hex-Any;Any-Hex",     "hello",  UnicodeString("\\u0068\\u0065\\u006C\\u006C\\u006F", ""),
373             "Any-Hex;Hex-Any",                 "hello! How are you?",  "hello! How are you?",
374             //"Devanagari-Latin;Latin-Devanagari",        CharsToUnicodeString("\\u092D\\u0948'\\u0930'\\u0935"),  CharsToUnicodeString("\\u092D\\u0948\\u0930\\u0935"), // quotes lost
375             "Latin-Cyrillic;Cyrillic-Latin",           "a'b'k'd'e'f'g'h'i'j'Shch'shch'zh'h", "a'b'k'd'e'f'g'h'i'j'Shch'shch'zh'h", //"abkdefghijShchshchzhh",
376             "Latin-Greek;Greek-Latin",                 "ABGabgAKLMN", "ABGabgAKLMN",
377             //"Latin-Arabic;Arabic-Latin",               "Ad'r'a'b'i'k'dh'dd'gh", "Adrabikdhddgh",
378             "Hiragana-Katakana",                       CharsToUnicodeString("\\u3041\\u308f\\u3099\\u306e\\u304b\\u3092\\u3099"),
379                                                                 CharsToUnicodeString("\\u30A1\\u30f7\\u30ce\\u30ab\\u30fa"),
380             "Hiragana-Katakana;Katakana-Hiragana",     CharsToUnicodeString("\\u3041\\u308f\\u3099\\u306e\\u304b\\u3051"),
381                                                                 CharsToUnicodeString("\\u3041\\u308f\\u3099\\u306e\\u304b\\u3051"),
382             "Katakana-Hiragana;Hiragana-Katakana",     CharsToUnicodeString("\\u30A1\\u30f7\\u30ce\\u30f5\\u30f6"),
383                                                                 CharsToUnicodeString("\\u30A1\\u30f7\\u30ce\\u30ab\\u30b1"),
384             "Latin-Katakana;Katakana-Latin",                   CharsToUnicodeString("vavivuvevohuzizuzonyinyunyasesuzezu"),
385                                                                 CharsToUnicodeString("vavivuvevohuzizuzonyinyunyasesuzezu"),
386    };
387    uint32_t i;
388    for(i=0; i<sizeof(Data)/sizeof(Data[0]); i=i+3){
389        UErrorCode status = U_ZERO_ERROR;
390
391        CompoundTransliterator *ct2=new CompoundTransliterator(Data[i+0], parseError, status);
392        if(U_FAILURE(status)){
393            dataerrln("CompoundTransliterator construction failed for " + Data[i+0] + " - " + u_errorName(status));
394        } else {
395            expect(*ct2, Data[i+1], Data[i+2]);
396        }
397        delete ct2;
398    }
399
400}
401
402
403
404//======================================================================
405// Support methods
406//======================================================================
407void CompoundTransliteratorTest::expect(const CompoundTransliterator& t,
408                                const UnicodeString& source,
409                                const UnicodeString& expectedResult) {
410
411    UnicodeString rsource(source);
412    t.transliterate(rsource);
413    expectAux(t.getID() + ":Replaceable", source + "->" + rsource, rsource==expectedResult, expectedResult);
414
415    // Test transliterate (incremental) transliteration --
416    rsource.remove();
417    rsource.append(source);
418    UTransPosition index;
419    index.contextStart =0;
420    index.contextLimit = source.length();
421    index.start = 0;
422    index.limit = source.length();
423    UErrorCode ec = U_ZERO_ERROR;
424    t.transliterate(rsource, index, ec);
425    t.finishTransliteration(rsource,index);
426    expectAux(t.getID() + ":handleTransliterate ", source + "->" + rsource, rsource==expectedResult, expectedResult);
427
428}
429
430void CompoundTransliteratorTest::expectAux(const UnicodeString& tag,
431                                   const UnicodeString& summary, UBool pass,
432                                   const UnicodeString& expectedResult) {
433    if (pass) {
434        logln(UnicodeString("(")+tag+") " + prettify(summary));
435    } else {
436        errln(UnicodeString("FAIL: (")+tag+") "
437              + prettify(summary)
438              + ", expected " + prettify(expectedResult));
439    }
440}
441
442#endif /* #if !UCONFIG_NO_TRANSLITERATION */
443