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