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) 1997-2014, International Business Machines Corporation and
6  * others. All Rights Reserved.
7  ********************************************************************/
8 /*   file name:  cbiditst.c
9 *   encoding:   UTF-8
10 *   tab size:   8 (not used)
11 *   indentation:4
12 *
13 *   created on: 1999sep27
14 *   created by: Markus W. Scherer, updated by Matitiahu Allouche
15 */
16 
17 #include "cintltst.h"
18 #include "unicode/utypes.h"
19 #include "unicode/uchar.h"
20 #include "unicode/ustring.h"
21 #include "unicode/ubidi.h"
22 #include "unicode/ushape.h"
23 #include "cbiditst.h"
24 #include "cstring.h"
25 /* the following include is needed for sprintf */
26 #include <stdio.h>
27 
28 #define MAXLEN      MAX_STRING_LENGTH
29 
30 /* prototypes ---------------------------------------------------------------*/
31 
32 void addComplexTest(TestNode** root);
33 
34 static void testCharFromDirProp(void);
35 
36 static void testBidi(void);
37 
38 static void doTests(UBiDi *pBiDi, UBiDi *pLine, UBool countRunsFirst);
39 
40 static void doMisc(void);
41 
42 static void doTest(UBiDi *pBiDi, int testNumber, const BiDiTestData *test,
43                    int32_t lineStart, UBool countRunsFirst);
44 
45 static void _testReordering(UBiDi *pBiDi, int testNumber);
46 
47 static void testInverse(void);
48 
49 static void _testManyInverseBidi(UBiDi *pBiDi, UBiDiLevel direction);
50 
51 static void _testInverseBidi(UBiDi *pBiDi, const UChar *src, int32_t srcLength,
52                              UBiDiLevel direction, UErrorCode *pErrorCode);
53 
54 static void _testWriteReverse(void);
55 
56 static void _testManyAddedPoints(void);
57 
58 static void _testMisc(void);
59 
60 static void doArabicShapingTest(void);
61 
62 static void doLamAlefSpecialVLTRArabicShapingTest(void);
63 
64 static void doTashkeelSpecialVLTRArabicShapingTest(void);
65 
66 static void doLOGICALArabicDeShapingTest(void);
67 
68 static void doArabicShapingTestForBug5421(void);
69 
70 static void doArabicShapingTestForBug8703(void);
71 
72 static void doArabicShapingTestForBug9024(void);
73 
74 static void _testPresentationForms(const UChar *in);
75 
76 static void doArabicShapingTestForNewCharacters(void);
77 
78 static void testReorder(void);
79 
80 static void testReorderArabicMathSymbols(void);
81 
82 static void testFailureRecovery(void);
83 
84 static void testMultipleParagraphs(void);
85 
86 static void testGetBaseDirection(void);
87 
88 static void testContext(void);
89 
90 static void doTailTest(void);
91 
92 static void testBracketOverflow(void);
93 static void TestExplicitLevel0(void);
94 
95 /* new BIDI API */
96 static void testReorderingMode(void);
97 static void testReorderRunsOnly(void);
98 static void testStreaming(void);
99 static void testClassOverride(void);
100 static const char* inverseBasic(UBiDi *pBiDi, const char *src, int32_t srcLen,
101                                 uint32_t option, UBiDiLevel level, char *result);
102 static UBool assertRoundTrip(UBiDi *pBiDi, int32_t tc, int32_t outIndex,
103                              const char *srcChars, const char *destChars,
104                              const UChar *dest, int32_t destLen, int mode,
105                              int option, UBiDiLevel level);
106 static UBool checkResultLength(UBiDi *pBiDi, const char *srcChars,
107                                const char *destChars,
108                                int32_t destLen, const char *mode,
109                                const char *option, UBiDiLevel level);
110 static UBool checkMaps(UBiDi *pBiDi, int32_t stringIndex, const char *src,
111                        const char *dest, const char *mode, const char* option,
112                        UBiDiLevel level, UBool forward);
113 
114 /* helpers ------------------------------------------------------------------ */
115 
116 static const char *levelString="...............................................................";
117 
118 static void initCharFromDirProps(void);
119 
120 static UChar *
121 getStringFromDirProps(const uint8_t *dirProps, int32_t length, UChar *buffer);
122 
123 static void printUnicode(const UChar *s, int32_t length, const UBiDiLevel *levels);
124 
125 /* regression tests ---------------------------------------------------------*/
126 
127 void
addComplexTest(TestNode ** root)128 addComplexTest(TestNode** root) {
129     addTest(root, testCharFromDirProp, "complex/bidi/TestCharFromDirProp");
130     addTest(root, testBidi, "complex/bidi/TestBidi");
131     addTest(root, testInverse, "complex/bidi/TestInverse");
132     addTest(root, testReorder,"complex/bidi/TestReorder");
133     addTest(root, testFailureRecovery,"complex/bidi/TestFailureRecovery");
134     addTest(root, testMultipleParagraphs,"complex/bidi/TestMultipleParagraphs");
135     addTest(root, testReorderingMode, "complex/bidi/TestReorderingMode");
136     addTest(root, testReorderRunsOnly, "complex/bidi/TestReorderRunsOnly");
137     addTest(root, testStreaming, "complex/bidi/TestStreaming");
138     addTest(root, testClassOverride, "complex/bidi/TestClassOverride");
139     addTest(root, testGetBaseDirection, "complex/bidi/testGetBaseDirection");
140     addTest(root, testContext, "complex/bidi/testContext");
141     addTest(root, testBracketOverflow, "complex/bidi/TestBracketOverflow");
142     addTest(root, TestExplicitLevel0, "complex/bidi/TestExplicitLevel0");
143 
144     addTest(root, doArabicShapingTest, "complex/arabic-shaping/ArabicShapingTest");
145     addTest(root, doLamAlefSpecialVLTRArabicShapingTest, "complex/arabic-shaping/lamalef");
146     addTest(root, doTashkeelSpecialVLTRArabicShapingTest, "complex/arabic-shaping/tashkeel");
147     addTest(root, doLOGICALArabicDeShapingTest, "complex/arabic-shaping/unshaping");
148     addTest(root, doArabicShapingTestForBug5421, "complex/arabic-shaping/bug-5421");
149     addTest(root, doTailTest, "complex/arabic-shaping/tailtest");
150     addTest(root, doArabicShapingTestForBug8703, "complex/arabic-shaping/bug-8703");
151     addTest(root, testReorderArabicMathSymbols, "complex/bidi/bug-9024");
152     addTest(root, doArabicShapingTestForBug9024, "complex/arabic-shaping/bug-9024");
153     addTest(root, doArabicShapingTestForNewCharacters, "complex/arabic-shaping/shaping2");
154 }
155 
156 static void
testCharFromDirProp(void)157 testCharFromDirProp(void) {
158     /* verify that the exemplar characters have the expected bidi classes */
159     int32_t i;
160 
161     log_verbose("\nEntering TestCharFromDirProp\n\n");
162     initCharFromDirProps();
163 
164     for(i=0; i<U_CHAR_DIRECTION_COUNT; ++i) {
165         if(u_charDirection(charFromDirProp[i])!=(UCharDirection)i) {
166             log_err("\nu_charDirection(charFromDirProp[%d]=U+%04x)==%d!=%d\n",
167                     i, charFromDirProp[i], u_charDirection(charFromDirProp[i]), i);
168         }
169     }
170     log_verbose("\nExiting TestCharFromDirProp\n\n");
171 }
172 
173 static void
testBidi(void)174 testBidi(void) {
175     UBiDi *pBiDi, *pLine=NULL;
176     UErrorCode errorCode=U_ZERO_ERROR;
177 
178     log_verbose("\nEntering TestBidi\n\n");
179 
180     pBiDi=ubidi_openSized(MAXLEN, 0, &errorCode);
181     if(pBiDi!=NULL) {
182         pLine=ubidi_open();
183         if(pLine!=NULL) {
184             doTests(pBiDi, pLine, FALSE);
185             doTests(pBiDi, pLine, TRUE);
186         } else {
187             log_err("ubidi_open() returned NULL, out of memory\n");
188         }
189     } else {
190         log_err("ubidi_openSized() returned NULL, errorCode %s\n", myErrorName(errorCode));
191     }
192     doMisc();
193 
194     if(pLine!=NULL) {
195         ubidi_close(pLine);
196     }
197     if(pBiDi!=NULL) {
198         ubidi_close(pBiDi);
199     }
200 
201     log_verbose("\nExiting TestBidi\n\n");
202 }
203 
204 static void
doTests(UBiDi * pBiDi,UBiDi * pLine,UBool countRunsFirst)205 doTests(UBiDi *pBiDi, UBiDi *pLine, UBool countRunsFirst) {
206     int testNumber;
207     UChar string[MAXLEN];
208     UErrorCode errorCode;
209     int32_t lineStart;
210     UBiDiLevel paraLevel;
211 
212     for(testNumber=0; testNumber<bidiTestCount; ++testNumber) {
213         errorCode=U_ZERO_ERROR;
214         getStringFromDirProps(tests[testNumber].text, tests[testNumber].length, string);
215         paraLevel=tests[testNumber].paraLevel;
216         ubidi_setPara(pBiDi, string, -1, paraLevel, NULL, &errorCode);
217         if(U_SUCCESS(errorCode)) {
218             log_verbose("ubidi_setPara(tests[%d], paraLevel %d) ok, direction %d paraLevel=%d\n",
219                     testNumber, paraLevel, ubidi_getDirection(pBiDi), paraLevel);
220             lineStart=tests[testNumber].lineStart;
221             if(lineStart==-1) {
222                 doTest(pBiDi, testNumber, tests+testNumber, 0, countRunsFirst);
223             } else {
224                 ubidi_setLine(pBiDi, lineStart, tests[testNumber].lineLimit, pLine, &errorCode);
225                 if(U_SUCCESS(errorCode)) {
226                     log_verbose("ubidi_setLine(%d, %d) ok, direction %d paraLevel=%d\n",
227                             lineStart, tests[testNumber].lineLimit, ubidi_getDirection(pLine), ubidi_getParaLevel(pLine));
228                     doTest(pLine, testNumber, tests+testNumber, lineStart, countRunsFirst);
229                 } else {
230                     log_err("ubidi_setLine(tests[%d], %d, %d) failed with errorCode %s\n",
231                             testNumber, lineStart, tests[testNumber].lineLimit, myErrorName(errorCode));
232                 }
233             }
234         } else {
235             log_err("ubidi_setPara(tests[%d], paraLevel %d) failed with errorCode %s\n",
236                     testNumber, paraLevel, myErrorName(errorCode));
237         }
238     }
239 }
240 
241 static const char columns[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
242 
243 #define TABLE_SIZE  256
244 static UBool   tablesInitialized = FALSE;
245 static UChar   pseudoToUChar[TABLE_SIZE];
246 static uint8_t UCharToPseudo[TABLE_SIZE];    /* used for Unicode chars < 0x0100 */
247 static uint8_t UCharToPseud2[TABLE_SIZE];    /* used for Unicode chars >=0x0100 */
248 
buildPseudoTables(void)249 static void buildPseudoTables(void)
250 /*
251     The rules for pseudo-Bidi are as follows:
252     - [ == LRE
253     - ] == RLE
254     - { == LRO
255     - } == RLO
256     - ^ == PDF
257     - @ == LRM
258     - & == RLM
259     - A-F == Arabic Letters 0631-0636
260     - G-V == Hebrew letters 05d7-05e6
261     - W-Z == Unassigned RTL 05CC..05CF
262         originally 08D0..08D3
263         Unicode 6.1 changes U+08A0..U+08FF from R to AL which works ok.
264         Unicode 11 adds U+08D3 ARABIC SMALL LOW WAW which has bc=NSM
265             so we stop using Z in this test.
266         Unicode 14 assigns 08D0..08D2 to diacritics (bc=NSM) so we switch to 05CC..05CF.
267     - 0-5 == western digits 0030-0035
268     - 6-9 == Arabic-Indic digits 0666-0669
269     - ` == Combining Grave Accent 0300 (NSM)
270     - ~ == Delete 007f (BN)
271     - | == Paragraph Separator 2029 (B)
272     - _ == Info Separator 1 001f (S)
273     All other characters represent themselves as Latin-1, with the corresponding
274     Bidi properties.
275 */
276 {
277     int             i;
278     UChar           uchar;
279     uint8_t         c;
280     /* initialize all tables to unknown */
281     for (i=0; i < TABLE_SIZE; i++) {
282         pseudoToUChar[i] = 0xFFFD;
283         UCharToPseudo[i] = '?';
284         UCharToPseud2[i] = '?';
285     }
286     /* initialize non letters or digits */
287     pseudoToUChar[(uint8_t) 0 ] = 0x0000;    UCharToPseudo[0x00] = (uint8_t) 0 ;
288     pseudoToUChar[(uint8_t)' '] = 0x0020;    UCharToPseudo[0x20] = (uint8_t)' ';
289     pseudoToUChar[(uint8_t)'!'] = 0x0021;    UCharToPseudo[0x21] = (uint8_t)'!';
290     pseudoToUChar[(uint8_t)'"'] = 0x0022;    UCharToPseudo[0x22] = (uint8_t)'"';
291     pseudoToUChar[(uint8_t)'#'] = 0x0023;    UCharToPseudo[0x23] = (uint8_t)'#';
292     pseudoToUChar[(uint8_t)'$'] = 0x0024;    UCharToPseudo[0x24] = (uint8_t)'$';
293     pseudoToUChar[(uint8_t)'%'] = 0x0025;    UCharToPseudo[0x25] = (uint8_t)'%';
294     pseudoToUChar[(uint8_t)'\'']= 0x0027;    UCharToPseudo[0x27] = (uint8_t)'\'';
295     pseudoToUChar[(uint8_t)'('] = 0x0028;    UCharToPseudo[0x28] = (uint8_t)'(';
296     pseudoToUChar[(uint8_t)')'] = 0x0029;    UCharToPseudo[0x29] = (uint8_t)')';
297     pseudoToUChar[(uint8_t)'*'] = 0x002A;    UCharToPseudo[0x2A] = (uint8_t)'*';
298     pseudoToUChar[(uint8_t)'+'] = 0x002B;    UCharToPseudo[0x2B] = (uint8_t)'+';
299     pseudoToUChar[(uint8_t)','] = 0x002C;    UCharToPseudo[0x2C] = (uint8_t)',';
300     pseudoToUChar[(uint8_t)'-'] = 0x002D;    UCharToPseudo[0x2D] = (uint8_t)'-';
301     pseudoToUChar[(uint8_t)'.'] = 0x002E;    UCharToPseudo[0x2E] = (uint8_t)'.';
302     pseudoToUChar[(uint8_t)'/'] = 0x002F;    UCharToPseudo[0x2F] = (uint8_t)'/';
303     pseudoToUChar[(uint8_t)':'] = 0x003A;    UCharToPseudo[0x3A] = (uint8_t)':';
304     pseudoToUChar[(uint8_t)';'] = 0x003B;    UCharToPseudo[0x3B] = (uint8_t)';';
305     pseudoToUChar[(uint8_t)'<'] = 0x003C;    UCharToPseudo[0x3C] = (uint8_t)'<';
306     pseudoToUChar[(uint8_t)'='] = 0x003D;    UCharToPseudo[0x3D] = (uint8_t)'=';
307     pseudoToUChar[(uint8_t)'>'] = 0x003E;    UCharToPseudo[0x3E] = (uint8_t)'>';
308     pseudoToUChar[(uint8_t)'?'] = 0x003F;    UCharToPseudo[0x3F] = (uint8_t)'?';
309     pseudoToUChar[(uint8_t)'\\']= 0x005C;    UCharToPseudo[0x5C] = (uint8_t)'\\';
310     /* initialize specially used characters */
311     pseudoToUChar[(uint8_t)'`'] = 0x0300;    UCharToPseud2[0x00] = (uint8_t)'`';  /* NSM */
312     pseudoToUChar[(uint8_t)'@'] = 0x200E;    UCharToPseud2[0x0E] = (uint8_t)'@';  /* LRM */
313     pseudoToUChar[(uint8_t)'&'] = 0x200F;    UCharToPseud2[0x0F] = (uint8_t)'&';  /* RLM */
314     pseudoToUChar[(uint8_t)'_'] = 0x001F;    UCharToPseudo[0x1F] = (uint8_t)'_';  /* S   */
315     pseudoToUChar[(uint8_t)'|'] = 0x2029;    UCharToPseud2[0x29] = (uint8_t)'|';  /* B   */
316     pseudoToUChar[(uint8_t)'['] = 0x202A;    UCharToPseud2[0x2A] = (uint8_t)'[';  /* LRE */
317     pseudoToUChar[(uint8_t)']'] = 0x202B;    UCharToPseud2[0x2B] = (uint8_t)']';  /* RLE */
318     pseudoToUChar[(uint8_t)'^'] = 0x202C;    UCharToPseud2[0x2C] = (uint8_t)'^';  /* PDF */
319     pseudoToUChar[(uint8_t)'{'] = 0x202D;    UCharToPseud2[0x2D] = (uint8_t)'{';  /* LRO */
320     pseudoToUChar[(uint8_t)'}'] = 0x202E;    UCharToPseud2[0x2E] = (uint8_t)'}';  /* RLO */
321     pseudoToUChar[(uint8_t)'~'] = 0x007F;    UCharToPseudo[0x7F] = (uint8_t)'~';  /* BN  */
322     /* initialize western digits */
323     for (i = 0, uchar = 0x0030; i < 6; i++, uchar++) {
324         c = (uint8_t)columns[i];
325         pseudoToUChar[c] = uchar;
326         UCharToPseudo[uchar & 0x00ff] = c;
327     }
328     /* initialize Hindi digits */
329     for (i = 6, uchar = 0x0666; i < 10; i++, uchar++) {
330         c = (uint8_t)columns[i];
331         pseudoToUChar[c] = uchar;
332         UCharToPseud2[uchar & 0x00ff] = c;
333     }
334     /* initialize Arabic letters */
335     for (i = 10, uchar = 0x0631; i < 16; i++, uchar++) {
336         c = (uint8_t)columns[i];
337         pseudoToUChar[c] = uchar;
338         UCharToPseud2[uchar & 0x00ff] = c;
339     }
340     /* initialize Hebrew letters */
341     for (i = 16, uchar = 0x05D7; i < 32; i++, uchar++) {
342         c = (uint8_t)columns[i];
343         pseudoToUChar[c] = uchar;
344         UCharToPseud2[uchar & 0x00ff] = c;
345     }
346     /* initialize Unassigned code points */
347     for (i = 32, uchar=0x05CC; i < 36; i++, uchar++) {
348         c = (uint8_t)columns[i];
349         pseudoToUChar[c] = uchar;
350         UCharToPseud2[uchar & 0x00ff] = c;
351     }
352     /* initialize Latin lower case letters */
353     for (i = 36, uchar = 0x0061; i < 62; i++, uchar++) {
354         c = (uint8_t)columns[i];
355         pseudoToUChar[c] = uchar;
356         UCharToPseudo[uchar & 0x00ff] = c;
357     }
358     tablesInitialized = TRUE;
359 }
360 
361 /*----------------------------------------------------------------------*/
362 
pseudoToU16(const int length,const char * input,UChar * output)363 static int pseudoToU16(const int length, const char * input, UChar * output)
364 /*  This function converts a pseudo-Bidi string into a UChar string.
365     It returns the length of the UChar string.
366 */
367 {
368     int             i;
369     if (!tablesInitialized) {
370         buildPseudoTables();
371     }
372     for (i = 0; i < length; i++)
373         output[i] = pseudoToUChar[(uint8_t)input[i]];
374     output[length] = 0;
375     return length;
376 }
377 
378 /*----------------------------------------------------------------------*/
379 
u16ToPseudo(const int length,const UChar * input,char * output)380 static int u16ToPseudo(const int length, const UChar * input, char * output)
381 /*  This function converts a UChar string into a pseudo-Bidi string.
382     It returns the length of the pseudo-Bidi string.
383 */
384 {
385     int             i;
386     UChar           uchar;
387     if (!tablesInitialized) {
388         buildPseudoTables();
389     }
390     for (i = 0; i < length; i++)
391     {
392         uchar = input[i];
393         output[i] = uchar < 0x0100 ? UCharToPseudo[uchar] :
394                                         UCharToPseud2[uchar & 0x00ff];
395     }
396     output[length] = '\0';
397     return length;
398 }
399 
formatLevels(UBiDi * bidi,char * buffer)400 static char * formatLevels(UBiDi *bidi, char *buffer) {
401     UErrorCode ec = U_ZERO_ERROR;
402     const UBiDiLevel* gotLevels = ubidi_getLevels(bidi, &ec);
403     int32_t len = ubidi_getLength(bidi);
404     char c;
405     int32_t i, k;
406 
407     if(U_FAILURE(ec)) {
408         strcpy(buffer, "BAD LEVELS");
409         return buffer;
410     }
411     for (i=0; i<len; i++) {
412         k = gotLevels[i];
413         if (k >= (int32_t)sizeof(columns))
414             c = '+';
415         else
416             c = columns[k];
417         buffer[i] = c;
418     }
419     buffer[len] = '\0';
420     return buffer;
421 }
422 static const char *reorderingModeNames[] = {
423     "UBIDI_REORDER_DEFAULT",
424     "UBIDI_REORDER_NUMBERS_SPECIAL",
425     "UBIDI_REORDER_GROUP_NUMBERS_WITH_R",
426     "UBIDI_REORDER_RUNS_ONLY",
427     "UBIDI_REORDER_INVERSE_NUMBERS_AS_L",
428     "UBIDI_REORDER_INVERSE_LIKE_DIRECT",
429     "UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL"};
430 
reorderingOptionNames(char * buffer,int options)431 static char *reorderingOptionNames(char *buffer, int options) {
432     buffer[0] = 0;
433     if (options & UBIDI_OPTION_INSERT_MARKS) {
434         strcat(buffer, " UBIDI_OPTION_INSERT_MARKS");
435     }
436     if (options & UBIDI_OPTION_REMOVE_CONTROLS) {
437         strcat(buffer, " UBIDI_OPTION_REMOVE_CONTROLS");
438     }
439     if (options & UBIDI_OPTION_STREAMING) {
440         strcat(buffer, " UBIDI_OPTION_STREAMING");
441     }
442     return buffer;
443 }
444 
printCaseInfo(UBiDi * bidi,const char * src,const char * dst)445 static void printCaseInfo(UBiDi *bidi, const char *src, const char *dst)
446 /* src and dst are char arrays encoded as pseudo Bidi */
447 {
448     /* Since calls to log_err with a \n within the pattern increment the
449      * error count, new lines are issued via fputs, except when we want the
450      * increment to happen.
451      */
452     UErrorCode errorCode=U_ZERO_ERROR;
453     int32_t i, length = ubidi_getProcessedLength(bidi);
454     const UBiDiLevel *levels;
455     char levelChars[MAXLEN];
456     UBiDiLevel lev;
457     int32_t runCount;
458     char buffer[100];
459     log_err("========================================"); fputs("\n", stderr);
460     levels = ubidi_getLevels(bidi, &errorCode);
461     if (U_FAILURE(errorCode)) {
462         strcpy(levelChars, "BAD LEVELS");
463     } else {
464         log_err("Processed length: %d", length); fputs("\n", stderr);
465         for (i = 0; i < length; i++) {
466             lev = levels[i];
467             if (lev < sizeof(columns)) {
468                 levelChars[i] = columns[lev];
469             } else {
470                 levelChars[i] = '+';
471             }
472         }
473         levelChars[length] = 0;
474     }
475     log_err("Levels: %s", levelChars); fputs("\n", stderr);
476     log_err("Source: %s", src); fputs("\n", stderr);
477     log_err("Result: %s", dst); fputs("\n", stderr);
478     log_err("Direction: %d", ubidi_getDirection(bidi)); fputs("\n", stderr);
479     log_err("paraLevel: %d", ubidi_getParaLevel(bidi)); fputs("\n", stderr);
480     i = ubidi_getReorderingMode(bidi);
481     log_err("reorderingMode: %d = %s", i, reorderingModeNames[i]);
482     fputs("\n", stderr);
483     i = ubidi_getReorderingOptions(bidi);
484     log_err("reorderingOptions: %d = %s", i, reorderingOptionNames(buffer, i));
485     fputs("\n", stderr);
486     runCount = ubidi_countRuns(bidi, &errorCode);
487     if (U_FAILURE(errorCode)) {
488         log_err( "BAD RUNS");
489     } else {
490         log_err("Runs: %d => logicalStart.length/level: ", runCount);
491         for (i = 0; i < runCount; i++) {
492             UBiDiDirection dir;
493             int32_t start, len;
494             dir = ubidi_getVisualRun(bidi, i, &start, &len);
495             log_err(" %d.%d/%d", start, len, dir);
496         }
497     }
498     fputs("\n", stderr);
499 }
500 
matchingPair(UBiDi * bidi,int32_t i,char c1,char c2)501 static UBool matchingPair(UBiDi *bidi, int32_t i, char c1, char c2)
502 {
503     /* No test for []{} since they have special meaning for pseudo Bidi */
504     static char mates1Chars[] = "<>()";
505     static char mates2Chars[] = "><)(";
506     UBiDiLevel level;
507     int k, len;
508 
509     if (c1 == c2) {
510         return TRUE;
511     }
512     /* For UBIDI_REORDER_RUNS_ONLY, it would not be correct to check levels[i],
513        so we use the appropriate run's level, which is good for all cases.
514      */
515     ubidi_getLogicalRun(bidi, i, NULL, &level);
516     if ((level & 1) == 0) {
517         return FALSE;
518     }
519     len = (int)strlen(mates1Chars);
520     for (k = 0; k < len; k++) {
521         if ((c1 == mates1Chars[k]) && (c2 == mates2Chars[k])) {
522             return TRUE;
523         }
524     }
525     return FALSE;
526 }
527 
checkWhatYouCan(UBiDi * bidi,const char * srcChars,const char * dstChars)528 static UBool checkWhatYouCan(UBiDi *bidi, const char *srcChars, const char *dstChars)
529 /* srcChars and dstChars are char arrays encoded as pseudo Bidi */
530 {
531     int32_t i, idx, logLimit, visLimit;
532     UBool testOK, errMap, errDst;
533     UErrorCode errorCode=U_ZERO_ERROR;
534     int32_t visMap[MAXLEN];
535     int32_t logMap[MAXLEN];
536     char accumSrc[MAXLEN];
537     char accumDst[MAXLEN];
538     ubidi_getVisualMap(bidi, visMap, &errorCode);
539     ubidi_getLogicalMap(bidi, logMap, &errorCode);
540     if (U_FAILURE(errorCode)) {
541         log_err("Error #1 invoking ICU within checkWhatYouCan\n");
542         return FALSE;
543     }
544 
545     testOK = TRUE;
546     errMap = errDst = FALSE;
547     logLimit = ubidi_getProcessedLength(bidi);
548     visLimit = ubidi_getResultLength(bidi);
549     memset(accumSrc, '?', logLimit);
550     memset(accumDst, '?', visLimit);
551 
552     for (i = 0; i < logLimit; i++) {
553         idx = ubidi_getVisualIndex(bidi, i, &errorCode);
554         if (idx != logMap[i]) {
555             errMap = TRUE;
556         }
557         if (idx == UBIDI_MAP_NOWHERE) {
558             continue;
559         }
560         if (idx >= visLimit) {
561             continue;
562         }
563         accumDst[idx] = srcChars[i];
564         if (!matchingPair(bidi, i, srcChars[i], dstChars[idx])) {
565             errDst = TRUE;
566         }
567     }
568     accumDst[visLimit] = 0;
569     if (U_FAILURE(errorCode)) {
570         log_err("Error #2 invoking ICU within checkWhatYouCan\n");
571         return FALSE;
572     }
573     if (errMap) {
574         if (testOK) {
575             printCaseInfo(bidi, srcChars, dstChars);
576             testOK = FALSE;
577         }
578         log_err("Mismatch between getLogicalMap() and getVisualIndex()\n");
579         log_err("Map    :");
580         for (i = 0; i < logLimit; i++) {
581             log_err(" %d", logMap[i]);
582         }
583         fputs("\n", stderr);
584         log_err("Indexes:");
585         for (i = 0; i < logLimit; i++) {
586             log_err(" %d", ubidi_getVisualIndex(bidi, i, &errorCode));
587         }
588         fputs("\n", stderr);
589     }
590     if (errDst) {
591         if (testOK) {
592             printCaseInfo(bidi, srcChars, dstChars);
593             testOK = FALSE;
594         }
595         log_err("Source does not map to Result\n");
596         log_err("We got: %s", accumDst); fputs("\n", stderr);
597     }
598 
599     errMap = errDst = FALSE;
600     for (i = 0; i < visLimit; i++) {
601         idx = ubidi_getLogicalIndex(bidi, i, &errorCode);
602         if (idx != visMap[i]) {
603             errMap = TRUE;
604         }
605         if (idx == UBIDI_MAP_NOWHERE) {
606             continue;
607         }
608         if (idx >= logLimit) {
609             continue;
610         }
611         accumSrc[idx] = dstChars[i];
612         if (!matchingPair(bidi, idx, srcChars[idx], dstChars[i])) {
613             errDst = TRUE;
614         }
615     }
616     accumSrc[logLimit] = 0;
617     if (U_FAILURE(errorCode)) {
618         log_err("Error #3 invoking ICU within checkWhatYouCan\n");
619         return FALSE;
620     }
621     if (errMap) {
622         if (testOK) {
623             printCaseInfo(bidi, srcChars, dstChars);
624             testOK = FALSE;
625         }
626         log_err("Mismatch between getVisualMap() and getLogicalIndex()\n");
627         log_err("Map    :");
628         for (i = 0; i < visLimit; i++) {
629             log_err(" %d", visMap[i]);
630         }
631         fputs("\n", stderr);
632         log_err("Indexes:");
633         for (i = 0; i < visLimit; i++) {
634             log_err(" %d", ubidi_getLogicalIndex(bidi, i, &errorCode));
635         }
636         fputs("\n", stderr);
637     }
638     if (errDst) {
639         if (testOK) {
640             printCaseInfo(bidi, srcChars, dstChars);
641             testOK = FALSE;
642         }
643         log_err("Result does not map to Source\n");
644         log_err("We got: %s", accumSrc);
645         fputs("\n", stderr);
646     }
647     return testOK;
648 }
649 
650 static void
testReorder(void)651 testReorder(void) {
652     static const char* const logicalOrder[] ={
653             "del(KC)add(K.C.&)",
654             "del(QDVT) add(BVDL)",
655             "del(PQ)add(R.S.)T)U.&",
656             "del(LV)add(L.V.) L.V.&",
657             "day  0  R  DPDHRVR dayabbr",
658             "day  1  H  DPHPDHDA dayabbr",
659             "day  2   L  DPBLENDA dayabbr",
660             "day  3  J  DPJQVM  dayabbr",
661             "day  4   I  DPIQNF    dayabbr",
662             "day  5  M  DPMEG  dayabbr",
663             "helloDPMEG",
664             "hello WXY"
665     };
666     static const char* const visualOrder[]={
667             "del(CK)add(&.C.K)",
668             "del(TVDQ) add(LDVB)",
669             "del(QP)add(S.R.)&.U(T",            /* updated for Unicode 6.3 matching brackets */
670             "del(VL)add(V.L.) &.V.L",           /* updated for Unicode 6.3 matching brackets */
671             "day  0  RVRHDPD  R dayabbr",
672             "day  1  ADHDPHPD  H dayabbr",
673             "day  2   ADNELBPD  L dayabbr",
674             "day  3  MVQJPD  J  dayabbr",
675             "day  4   FNQIPD  I    dayabbr",
676             "day  5  GEMPD  M  dayabbr",
677             "helloGEMPD",
678             "hello YXW"
679     };
680     static const char* const visualOrder1[]={
681             ")K.C.&(dda)KC(led",
682             ")BVDL(dda )QDVT(led",
683             "T(U.&).R.S(dda)PQ(led",            /* updated for Unicode 6.3 matching brackets */
684             "L.V.& ).L.V(dda)LV(led",           /* updated for Unicode 6.3 matching brackets */
685             "rbbayad R  DPDHRVR  0  yad",
686             "rbbayad H  DPHPDHDA  1  yad",
687             "rbbayad L  DPBLENDA   2  yad",
688             "rbbayad  J  DPJQVM  3  yad",
689             "rbbayad    I  DPIQNF   4  yad",
690             "rbbayad  M  DPMEG  5  yad",
691             "DPMEGolleh",
692             "WXY olleh"
693     };
694 
695     static const char* const visualOrder2[]={
696             "@)@K.C.&@(dda)@KC@(led",
697             "@)@BVDL@(dda )@QDVT@(led",
698             "R.S.)T)U.&@(dda)@PQ@(led",
699             "L.V.) L.V.&@(dda)@LV@(led",
700             "rbbayad @R  DPDHRVR@  0  yad",
701             "rbbayad @H  DPHPDHDA@  1  yad",
702             "rbbayad @L  DPBLENDA@   2  yad",
703             "rbbayad  @J  DPJQVM@  3  yad",
704             "rbbayad    @I  DPIQNF@   4  yad",
705             "rbbayad  @M  DPMEG@  5  yad",
706             "DPMEGolleh",
707             "WXY@ olleh"
708     };
709     static const char* const visualOrder3[]={
710             ")K.C.&(KC)dda(led",
711             ")BVDL(ddaQDVT) (led",
712             "R.S.)T)U.&(PQ)dda(led",
713             "L.V.) L.V.&(LV)dda(led",
714             "rbbayad DPDHRVR   R  0 yad",
715             "rbbayad DPHPDHDA   H  1 yad",
716             "rbbayad DPBLENDA     L 2 yad",
717             "rbbayad  DPJQVM   J  3 yad",
718             "rbbayad    DPIQNF     I 4 yad",
719             "rbbayad  DPMEG   M  5 yad",
720             "DPMEGolleh",
721             "WXY olleh"
722     };
723     static const char* const visualOrder4[]={
724             "del(add(CK(.C.K)",
725             "del( (TVDQadd(LDVB)",
726             "del(add(QP(.U(T(.S.R",
727             "del(add(VL(.V.L (.V.L",
728             "day 0  R   RVRHDPD dayabbr",
729             "day 1  H   ADHDPHPD dayabbr",
730             "day 2 L     ADNELBPD dayabbr",
731             "day 3  J   MVQJPD  dayabbr",
732             "day 4 I     FNQIPD    dayabbr",
733             "day 5  M   GEMPD  dayabbr",
734             "helloGEMPD",
735             "hello YXW"
736     };
737     char formatChars[MAXLEN];
738     UErrorCode ec = U_ZERO_ERROR;
739     UBiDi* bidi = ubidi_open();
740     int i;
741 
742     log_verbose("\nEntering TestReorder\n\n");
743 
744     for(i=0;i<UPRV_LENGTHOF(logicalOrder);i++){
745         int32_t srcSize = (int32_t)strlen(logicalOrder[i]);
746         int32_t destSize = srcSize*2;
747         UChar src[MAXLEN];
748         UChar dest[MAXLEN];
749         char chars[MAXLEN];
750         log_verbose("Testing L2V #1 for case %d\n", i);
751         pseudoToU16(srcSize,logicalOrder[i],src);
752         ec = U_ZERO_ERROR;
753         ubidi_setPara(bidi,src,srcSize,UBIDI_DEFAULT_LTR ,NULL,&ec);
754         if(U_FAILURE(ec)){
755             log_err("ubidi_setPara(tests[%d], paraLevel %d) failed with errorCode %s\n",
756                     i, UBIDI_DEFAULT_LTR, u_errorName(ec));
757         }
758         /* try pre-flighting */
759         destSize = ubidi_writeReordered(bidi,dest,0,UBIDI_DO_MIRRORING,&ec);
760         if(ec!=U_BUFFER_OVERFLOW_ERROR){
761             log_err("Pre-flighting did not give expected error: Expected: U_BUFFER_OVERFLOW_ERROR. Got: %s \n",u_errorName(ec));
762         }else if(destSize!=srcSize){
763             log_err("Pre-flighting did not give expected size: Expected: %d. Got: %d \n",srcSize,destSize);
764         }else{
765             ec= U_ZERO_ERROR;
766         }
767         destSize=ubidi_writeReordered(bidi,dest,destSize+1,UBIDI_DO_MIRRORING,&ec);
768         u16ToPseudo(destSize,dest,chars);
769         if(destSize!=srcSize){
770             log_err("ubidi_writeReordered() destSize and srcSize do not match\n");
771         }else if(strcmp(visualOrder[i],chars)!=0){
772             log_err("ubidi_writeReordered() did not give expected results for UBIDI_DO_MIRRORING.\n"
773                     "Input   : %s\nExpected: %s\nGot     : %s\nLevels  : %s\nAt Index: %d\n",
774                     logicalOrder[i],visualOrder[i],chars,formatLevels(bidi, formatChars),i);
775         }
776         checkWhatYouCan(bidi, logicalOrder[i], chars);
777     }
778 
779     for(i=0;i<UPRV_LENGTHOF(logicalOrder);i++){
780         int32_t srcSize = (int32_t)strlen(logicalOrder[i]);
781         int32_t destSize = srcSize*2;
782         UChar src[MAXLEN];
783         UChar dest[MAXLEN];
784         char chars[MAXLEN];
785         log_verbose("Testing L2V #2 for case %d\n", i);
786         pseudoToU16(srcSize,logicalOrder[i],src);
787         ec = U_ZERO_ERROR;
788         ubidi_setPara(bidi,src,srcSize,UBIDI_DEFAULT_LTR ,NULL,&ec);
789         if(U_FAILURE(ec)){
790             log_err("ubidi_setPara(tests[%d], paraLevel %d) failed with errorCode %s\n",
791                     i, UBIDI_DEFAULT_LTR, u_errorName(ec));
792         }
793         /* try pre-flighting */
794         destSize = ubidi_writeReordered(bidi,dest,0,UBIDI_DO_MIRRORING+UBIDI_OUTPUT_REVERSE,&ec);
795         if(ec!=U_BUFFER_OVERFLOW_ERROR){
796             log_err("Pre-flighting did not give expected error: Expected: U_BUFFER_OVERFLOW_ERROR. Got: %s \n",u_errorName(ec));
797         }else if(destSize!=srcSize){
798             log_err("Pre-flighting did not give expected size: Expected: %d. Got: %d \n",srcSize,destSize);
799         }else{
800             ec= U_ZERO_ERROR;
801         }
802         destSize=ubidi_writeReordered(bidi,dest,destSize+1,UBIDI_DO_MIRRORING+UBIDI_OUTPUT_REVERSE,&ec);
803         u16ToPseudo(destSize,dest,chars);
804         if(destSize!=srcSize){
805             log_err("ubidi_writeReordered() destSize and srcSize do not match\n");
806         }else if(strcmp(visualOrder1[i],chars)!=0){
807             log_err("ubidi_writeReordered() did not give expected results for UBIDI_DO_MIRRORING+UBIDI_OUTPUT_REVERSE.\n"
808                     "Input   : %s\nExpected: %s\nGot     : %s\nLevels  : %s\nAt Index: %d\n",
809                     logicalOrder[i],visualOrder1[i],chars,formatLevels(bidi, formatChars),i);
810         }
811     }
812 
813     for(i=0;i<UPRV_LENGTHOF(logicalOrder);i++){
814         int32_t srcSize = (int32_t)strlen(logicalOrder[i]);
815         int32_t destSize = srcSize*2;
816         UChar src[MAXLEN];
817         UChar dest[MAXLEN];
818         char chars[MAXLEN];
819         log_verbose("Testing V2L #3 for case %d\n", i);
820         pseudoToU16(srcSize,logicalOrder[i],src);
821         ec = U_ZERO_ERROR;
822         ubidi_setInverse(bidi,TRUE);
823         ubidi_setPara(bidi,src,srcSize,UBIDI_DEFAULT_LTR ,NULL,&ec);
824         if(U_FAILURE(ec)){
825             log_err("ubidi_setPara(tests[%d], paraLevel %d) failed with errorCode %s\n",
826                     i, UBIDI_DEFAULT_LTR, u_errorName(ec));
827         }
828                 /* try pre-flighting */
829         destSize = ubidi_writeReordered(bidi,dest,0,UBIDI_INSERT_LRM_FOR_NUMERIC+UBIDI_OUTPUT_REVERSE,&ec);
830         if(ec!=U_BUFFER_OVERFLOW_ERROR){
831             log_err("Pre-flighting did not give expected error: Expected: U_BUFFER_OVERFLOW_ERROR. Got: %s \n",u_errorName(ec));
832         }else{
833             ec= U_ZERO_ERROR;
834         }
835         destSize=ubidi_writeReordered(bidi,dest,destSize+1,UBIDI_INSERT_LRM_FOR_NUMERIC+UBIDI_OUTPUT_REVERSE,&ec);
836         u16ToPseudo(destSize,dest,chars);
837         if(strcmp(visualOrder2[i],chars)!=0){
838             log_err("ubidi_writeReordered() did not give expected results for UBIDI_INSERT_LRM_FOR_NUMERIC+UBIDI_OUTPUT_REVERSE.\n"
839                     "Input   : %s\nExpected: %s\nGot     : %s\nLevels  : %s\nAt Index: %d\n",
840                     logicalOrder[i],visualOrder2[i],chars,formatLevels(bidi, formatChars),i);
841         }
842     }
843         /* Max Explicit level */
844     for(i=0;i<UPRV_LENGTHOF(logicalOrder);i++){
845         int32_t srcSize = (int32_t)strlen(logicalOrder[i]);
846         int32_t destSize = srcSize*2;
847         UChar src[MAXLEN];
848         UChar dest[MAXLEN];
849         char chars[MAXLEN];
850         UBiDiLevel levels[UBIDI_MAX_EXPLICIT_LEVEL]={1,2,3,4,5,6,7,8,9,10};
851         log_verbose("Testing V2L #4 for case %d\n", i);
852         pseudoToU16(srcSize,logicalOrder[i],src);
853         ec = U_ZERO_ERROR;
854         ubidi_setPara(bidi,src,srcSize,UBIDI_DEFAULT_LTR,levels,&ec);
855         if(U_FAILURE(ec)){
856             log_err("ubidi_setPara(tests[%d], paraLevel %d) failed with errorCode %s\n",
857                     i, UBIDI_MAX_EXPLICIT_LEVEL, u_errorName(ec));
858         }
859                 /* try pre-flighting */
860         destSize = ubidi_writeReordered(bidi,dest,0,UBIDI_OUTPUT_REVERSE,&ec);
861         if(ec!=U_BUFFER_OVERFLOW_ERROR){
862             log_err("Pre-flighting did not give expected error: Expected: U_BUFFER_OVERFLOW_ERROR. Got: %s \n",u_errorName(ec));
863         }else if(destSize!=srcSize){
864             log_err("Pre-flighting did not give expected size: Expected: %d. Got: %d \n",srcSize,destSize);
865         }else{
866             ec = U_ZERO_ERROR;
867         }
868         destSize=ubidi_writeReordered(bidi,dest,destSize+1,UBIDI_OUTPUT_REVERSE,&ec);
869         u16ToPseudo(destSize,dest,chars);
870         if(destSize!=srcSize){
871             log_err("ubidi_writeReordered() destSize and srcSize do not match. Dest Size = %d Source Size = %d\n",destSize,srcSize );
872         }else if(strcmp(visualOrder3[i],chars)!=0){
873             log_err("ubidi_writeReordered() did not give expected results for UBIDI_OUTPUT_REVERSE.\n"
874                     "Input   : %s\nExpected: %s\nGot     : %s\nLevels  : %s\nAt Index: %d\n",
875                     logicalOrder[i],visualOrder3[i],chars,formatLevels(bidi, formatChars),i);
876         }
877     }
878     for(i=0;i<UPRV_LENGTHOF(logicalOrder);i++){
879         int32_t srcSize = (int32_t)strlen(logicalOrder[i]);
880         int32_t destSize = srcSize*2;
881         UChar src[MAXLEN];
882         UChar dest[MAXLEN];
883         char chars[MAXLEN];
884         UBiDiLevel levels[UBIDI_MAX_EXPLICIT_LEVEL]={1,2,3,4,5,6,7,8,9,10};
885         log_verbose("Testing V2L #5 for case %d\n", i);
886         pseudoToU16(srcSize,logicalOrder[i],src);
887         ec = U_ZERO_ERROR;
888         ubidi_setPara(bidi,src,srcSize,UBIDI_DEFAULT_LTR,levels,&ec);
889         if(U_FAILURE(ec)){
890             log_err("ubidi_setPara(tests[%d], paraLevel %d) failed with errorCode %s\n",
891                     i, UBIDI_MAX_EXPLICIT_LEVEL, u_errorName(ec));
892         }
893         /* try pre-flighting */
894         destSize = ubidi_writeReordered(bidi,dest,0,UBIDI_DO_MIRRORING+UBIDI_REMOVE_BIDI_CONTROLS,&ec);
895         if(ec!=U_BUFFER_OVERFLOW_ERROR){
896             log_err("Pre-flighting did not give expected error: Expected: U_BUFFER_OVERFLOW_ERROR. Got: %s \n",u_errorName(ec));
897         }else{
898             ec= U_ZERO_ERROR;
899         }
900         destSize=ubidi_writeReordered(bidi,dest,destSize+1,UBIDI_DO_MIRRORING+UBIDI_REMOVE_BIDI_CONTROLS,&ec);
901         u16ToPseudo(destSize,dest,chars);
902         if(strcmp(visualOrder4[i],chars)!=0){
903             log_err("ubidi_writeReordered() did not give expected results for UBIDI_DO_MIRRORING+UBIDI_REMOVE_BIDI_CONTROLS.\n"
904                     "Input   : %s\nExpected: %s\nGot     : %s\nLevels  : %s\nAt Index: %d\n",
905                     logicalOrder[i],visualOrder4[i],chars,formatLevels(bidi, formatChars),i);
906         }
907     }
908     ubidi_close(bidi);
909 
910     log_verbose("\nExiting TestReorder\n\n");
911 }
912 
913 static void
testReorderArabicMathSymbols(void)914 testReorderArabicMathSymbols(void) {
915     static const UChar logicalOrder[][MAXLEN]={
916         /* Arabic mathematical Symbols 0x1EE00 - 0x1EE1B */
917         {0xD83B, 0xDE00, 0xD83B, 0xDE01, 0xD83B, 0xDE02, 0xD83B, 0xDE03, 0x20,
918         0xD83B, 0xDE24, 0xD83B, 0xDE05, 0xD83B, 0xDE06, 0x20,
919         0xD83B, 0xDE07, 0xD83B, 0xDE08, 0xD83B, 0xDE09, 0x20,
920         0xD83B, 0xDE0A, 0xD83B, 0xDE0B, 0xD83B, 0xDE0C, 0xD83B, 0xDE0D, 0x20,
921         0xD83B, 0xDE0E, 0xD83B, 0xDE0F, 0xD83B, 0xDE10, 0xD83B, 0xDE11, 0x20,
922         0xD83B, 0xDE12, 0xD83B, 0xDE13, 0xD83B, 0xDE14, 0xD83B, 0xDE15, 0x20,
923         0xD83B, 0xDE16, 0xD83B, 0xDE17, 0xD83B, 0xDE18, 0x20,
924         0xD83B, 0xDE19, 0xD83B, 0xDE1A, 0xD83B, 0xDE1B},
925         /* Arabic mathematical Symbols - Looped Symbols, 0x1EE80 - 0x1EE9B */
926         {0xD83B, 0xDE80, 0xD83B, 0xDE81, 0xD83B, 0xDE82, 0xD83B, 0xDE83, 0x20,
927         0xD83B, 0xDE84, 0xD83B, 0xDE85, 0xD83B, 0xDE86, 0x20,
928         0xD83B, 0xDE87, 0xD83B, 0xDE88, 0xD83B, 0xDE89, 0x20,
929         0xD83B, 0xDE8B, 0xD83B, 0xDE8C, 0xD83B, 0xDE8D, 0x20,
930         0xD83B, 0xDE8E, 0xD83B, 0xDE8F, 0xD83B, 0xDE90, 0xD83B, 0xDE91, 0x20,
931         0xD83B, 0xDE92, 0xD83B, 0xDE93, 0xD83B, 0xDE94, 0xD83B, 0xDE95, 0x20,
932         0xD83B, 0xDE96, 0xD83B, 0xDE97, 0xD83B, 0xDE98, 0x20,
933         0xD83B, 0xDE99, 0xD83B, 0xDE9A, 0xD83B, 0xDE9B},
934         /* Arabic mathematical Symbols - Double-struck Symbols, 0x1EEA1 - 0x1EEBB */
935         {0xD83B, 0xDEA1, 0xD83B, 0xDEA2, 0xD83B, 0xDEA3, 0x20,
936         0xD83B, 0xDEA5, 0xD83B, 0xDEA6, 0x20,
937         0xD83B, 0xDEA7, 0xD83B, 0xDEA8, 0xD83B, 0xDEA9, 0x20,
938         0xD83B, 0xDEAB, 0xD83B, 0xDEAC, 0xD83B, 0xDEAD, 0x20,
939         0xD83B, 0xDEAE, 0xD83B, 0xDEAF, 0xD83B, 0xDEB0, 0xD83B, 0xDEB1, 0x20,
940         0xD83B, 0xDEB2, 0xD83B, 0xDEB3, 0xD83B, 0xDEB4, 0xD83B, 0xDEB5, 0x20,
941         0xD83B, 0xDEB6, 0xD83B, 0xDEB7, 0xD83B, 0xDEB8, 0x20,
942         0xD83B, 0xDEB9, 0xD83B, 0xDEBA, 0xD83B, 0xDEBB},
943         /* Arabic mathematical Symbols - Initial Symbols, 0x1EE21 - 0x1EE3B */
944         {0xD83B, 0xDE21, 0xD83B, 0xDE22, 0x20,
945         0xD83B, 0xDE27, 0xD83B, 0xDE29, 0x20,
946         0xD83B, 0xDE2A, 0xD83B, 0xDE2B, 0xD83B, 0xDE2C, 0xD83B, 0xDE2D, 0x20,
947         0xD83B, 0xDE2E, 0xD83B, 0xDE2F, 0xD83B, 0xDE30, 0xD83B, 0xDE31, 0x20,
948         0xD83B, 0xDE32, 0xD83B, 0xDE34, 0xD83B, 0xDE35, 0x20,
949         0xD83B, 0xDE36, 0xD83B, 0xDE37, 0x20,
950         0xD83B, 0xDE39, 0xD83B, 0xDE3B},
951         /* Arabic mathematical Symbols - Tailed Symbols */
952         {0xD83B, 0xDE42, 0xD83B, 0xDE47, 0xD83B, 0xDE49, 0xD83B, 0xDE4B, 0x20,
953         0xD83B, 0xDE4D, 0xD83B, 0xDE4E, 0xD83B, 0xDE4F, 0x20,
954         0xD83B, 0xDE51, 0xD83B, 0xDE52, 0xD83B, 0xDE54, 0xD83B, 0xDE57, 0x20,
955         0xD83B, 0xDE59, 0xD83B, 0xDE5B, 0xD83B, 0xDE5D, 0xD83B, 0xDE5F}
956     };
957     static const UChar visualOrder[][MAXLEN]={
958         /* Arabic mathematical Symbols 0x1EE00 - 0x1EE1B */
959         {0xD83B, 0xDE1B, 0xD83B, 0xDE1A, 0xD83B, 0xDE19, 0x20,
960         0xD83B, 0xDE18, 0xD83B, 0xDE17, 0xD83B, 0xDE16, 0x20,
961         0xD83B, 0xDE15, 0xD83B, 0xDE14, 0xD83B, 0xDE13, 0xD83B, 0xDE12, 0x20,
962         0xD83B, 0xDE11, 0xD83B, 0xDE10, 0xD83B, 0xDE0F, 0xD83B, 0xDE0E, 0x20,
963         0xD83B, 0xDE0D, 0xD83B, 0xDE0C, 0xD83B, 0xDE0B, 0xD83B, 0xDE0A, 0x20,
964         0xD83B, 0xDE09, 0xD83B, 0xDE08, 0xD83B, 0xDE07, 0x20,
965         0xD83B, 0xDE06, 0xD83B, 0xDE05, 0xD83B, 0xDE24, 0x20,
966         0xD83B, 0xDE03, 0xD83B, 0xDE02, 0xD83B, 0xDE01, 0xD83B, 0xDE00},
967         /* Arabic mathematical Symbols - Looped Symbols, 0x1EE80 - 0x1EE9B */
968         {0xD83B, 0xDE9B, 0xD83B, 0xDE9A, 0xD83B, 0xDE99, 0x20,
969         0xD83B, 0xDE98, 0xD83B, 0xDE97, 0xD83B, 0xDE96, 0x20,
970         0xD83B, 0xDE95, 0xD83B, 0xDE94, 0xD83B, 0xDE93, 0xD83B, 0xDE92, 0x20,
971         0xD83B, 0xDE91, 0xD83B, 0xDE90, 0xD83B, 0xDE8F, 0xD83B, 0xDE8E, 0x20,
972         0xD83B, 0xDE8D, 0xD83B, 0xDE8C, 0xD83B, 0xDE8B, 0x20,
973         0xD83B, 0xDE89, 0xD83B, 0xDE88, 0xD83B, 0xDE87, 0x20,
974         0xD83B, 0xDE86, 0xD83B, 0xDE85, 0xD83B, 0xDE84, 0x20,
975         0xD83B, 0xDE83, 0xD83B, 0xDE82, 0xD83B, 0xDE81, 0xD83B, 0xDE80},
976         /* Arabic mathematical Symbols - Double-struck Symbols, 0x1EEA1 - 0x1EEBB */
977         {0xD83B, 0xDEBB, 0xD83B, 0xDEBA, 0xD83B, 0xDEB9, 0x20,
978         0xD83B, 0xDEB8, 0xD83B, 0xDEB7, 0xD83B, 0xDEB6, 0x20,
979         0xD83B, 0xDEB5, 0xD83B, 0xDEB4, 0xD83B, 0xDEB3, 0xD83B, 0xDEB2, 0x20,
980         0xD83B, 0xDEB1, 0xD83B, 0xDEB0, 0xD83B, 0xDEAF, 0xD83B, 0xDEAE, 0x20,
981         0xD83B, 0xDEAD, 0xD83B, 0xDEAC, 0xD83B, 0xDEAB, 0x20,
982         0xD83B, 0xDEA9, 0xD83B, 0xDEA8, 0xD83B, 0xDEA7, 0x20,
983         0xD83B, 0xDEA6, 0xD83B, 0xDEA5, 0x20,
984         0xD83B, 0xDEA3, 0xD83B, 0xDEA2, 0xD83B, 0xDEA1},
985         /* Arabic mathematical Symbols - Initial Symbols, 0x1EE21 - 0x1EE3B */
986         {0xD83B, 0xDE3B, 0xD83B, 0xDE39, 0x20,
987         0xD83B, 0xDE37, 0xD83B, 0xDE36, 0x20,
988         0xD83B, 0xDE35, 0xD83B, 0xDE34, 0xD83B, 0xDE32, 0x20,
989         0xD83B, 0xDE31, 0xD83B, 0xDE30, 0xD83B, 0xDE2F, 0xD83B, 0xDE2E, 0x20,
990         0xD83B, 0xDE2D, 0xD83B, 0xDE2C, 0xD83B, 0xDE2B, 0xD83B, 0xDE2A, 0x20,
991         0xD83B, 0xDE29, 0xD83B, 0xDE27, 0x20,
992         0xD83B, 0xDE22, 0xD83B, 0xDE21},
993         /* Arabic mathematical Symbols - Tailed Symbols */
994         {0xD83B, 0xDE5F, 0xD83B, 0xDE5D, 0xD83B, 0xDE5B, 0xD83B, 0xDE59, 0x20,
995         0xD83B, 0xDE57, 0xD83B, 0xDE54, 0xD83B, 0xDE52, 0xD83B, 0xDE51, 0x20,
996         0xD83B, 0xDE4F, 0xD83B, 0xDE4E, 0xD83B, 0xDE4D, 0x20,
997         0xD83B, 0xDE4B, 0xD83B, 0xDE49, 0xD83B, 0xDE47, 0xD83B, 0xDE42}
998     };
999     char formatChars[MAXLEN];
1000     UErrorCode ec = U_ZERO_ERROR;
1001     UBiDi* bidi = ubidi_open();
1002     int i;
1003 
1004     log_verbose("\nEntering TestReorderArabicMathSymbols\n\n");
1005 
1006     for(i=0;i<UPRV_LENGTHOF(logicalOrder);i++){
1007         int32_t srcSize = u_strlen(logicalOrder[i]);
1008         int32_t destSize = srcSize*2;
1009         UChar dest[MAXLEN];
1010         log_verbose("Testing L2V #1 for case %d\n", i);
1011         ec = U_ZERO_ERROR;
1012         ubidi_setPara(bidi,logicalOrder[i],srcSize,UBIDI_DEFAULT_LTR ,NULL,&ec);
1013         if(U_FAILURE(ec)){
1014             log_err("ubidi_setPara(tests[%d], paraLevel %d) failed with errorCode %s\n",
1015                     i, UBIDI_DEFAULT_LTR, u_errorName(ec));
1016         }
1017         /* try pre-flighting */
1018         destSize = ubidi_writeReordered(bidi,dest,0,UBIDI_DO_MIRRORING,&ec);
1019         if(ec!=U_BUFFER_OVERFLOW_ERROR){
1020             log_err("Pre-flighting did not give expected error: Expected: U_BUFFER_OVERFLOW_ERROR. Got: %s \n",u_errorName(ec));
1021         }else if(destSize!=srcSize){
1022             log_err("Pre-flighting did not give expected size: Expected: %d. Got: %d \n",srcSize,destSize);
1023         }else{
1024             ec= U_ZERO_ERROR;
1025         }
1026         destSize=ubidi_writeReordered(bidi,dest,destSize+1,UBIDI_DO_MIRRORING,&ec);
1027         if(destSize!=srcSize){
1028             log_err("ubidi_writeReordered() destSize and srcSize do not match\n");
1029         }else if(memcmp(dest, visualOrder[i], destSize*U_SIZEOF_UCHAR)!=0){
1030             log_err("ubidi_writeReordered() did not give expected results for UBIDI_DO_MIRRORING.\n"
1031                     "Input   : %s\nExpected: %s\nGot     : %s\nLevels  : %s\nAt Index: %d\n",
1032                     logicalOrder[i],visualOrder[i],dest,formatLevels(bidi, formatChars),i);
1033         }
1034     }
1035 
1036     ubidi_close(bidi);
1037 
1038     log_verbose("\nExiting TestReorderArabicMathSymbols\n\n");
1039 }
1040 
1041 static void
doTest(UBiDi * pBiDi,int testNumber,const BiDiTestData * test,int32_t lineStart,UBool countRunsFirst)1042 doTest(UBiDi *pBiDi, int testNumber, const BiDiTestData *test, int32_t lineStart, UBool countRunsFirst) {
1043     const uint8_t *dirProps=test->text+lineStart;
1044     const UBiDiLevel *levels=test->levels;
1045     const uint8_t *visualMap=test->visualMap;
1046     int32_t i, len=ubidi_getLength(pBiDi), logicalIndex, runCount = 0;
1047     UErrorCode errorCode=U_ZERO_ERROR;
1048     UBiDiLevel level, level2;
1049 
1050     if (countRunsFirst) {
1051         log_verbose("Calling ubidi_countRuns() first.\n");
1052 
1053         runCount = ubidi_countRuns(pBiDi, &errorCode);
1054 
1055         if(U_FAILURE(errorCode)) {
1056             log_err("ubidi_countRuns(tests[%d]): error %s\n", testNumber, myErrorName(errorCode));
1057             return;
1058         }
1059     } else {
1060         log_verbose("Calling ubidi_getLogicalMap() first.\n");
1061     }
1062 
1063     _testReordering(pBiDi, testNumber);
1064 
1065     for(i=0; i<len; ++i) {
1066         log_verbose("%3d %3d %.*s%-3s @%d\n",
1067                 i, ubidi_getLevelAt(pBiDi, i), ubidi_getLevelAt(pBiDi, i), levelString,
1068                 dirPropNames[dirProps[i]],
1069                 ubidi_getVisualIndex(pBiDi, i, &errorCode));
1070     }
1071 
1072     log_verbose("\n-----levels:");
1073     for(i=0; i<len; ++i) {
1074         if(i>0) {
1075             log_verbose(",");
1076         }
1077         log_verbose(" %d", ubidi_getLevelAt(pBiDi, i));
1078     }
1079 
1080     log_verbose("\n--reordered:");
1081     for(i=0; i<len; ++i) {
1082         if(i>0) {
1083             log_verbose(",");
1084         }
1085         log_verbose(" %d", ubidi_getVisualIndex(pBiDi, i, &errorCode));
1086     }
1087     log_verbose("\n");
1088 
1089     if(test->direction!=ubidi_getDirection(pBiDi)) {
1090         log_err("ubidi_getDirection(tests[%d]): wrong direction %d\n", testNumber, ubidi_getDirection(pBiDi));
1091     }
1092 
1093     if(test->resultLevel!=ubidi_getParaLevel(pBiDi)) {
1094         log_err("ubidi_getParaLevel(tests[%d]): wrong paragraph level %d\n", testNumber, ubidi_getParaLevel(pBiDi));
1095     }
1096 
1097     for(i=0; i<len; ++i) {
1098         if(levels[i]!=ubidi_getLevelAt(pBiDi, i)) {
1099             log_err("ubidi_getLevelAt(tests[%d], %d): wrong level %d, expected %d\n", testNumber, i, ubidi_getLevelAt(pBiDi, i), levels[i]);
1100             return;
1101         }
1102     }
1103 
1104     for(i=0; i<len; ++i) {
1105         logicalIndex=ubidi_getVisualIndex(pBiDi, i, &errorCode);
1106         if(U_FAILURE(errorCode)) {
1107             log_err("ubidi_getVisualIndex(tests[%d], %d): error %s\n", testNumber, i, myErrorName(errorCode));
1108             return;
1109         }
1110         if(visualMap[i]!=logicalIndex) {
1111             log_err("ubidi_getVisualIndex(tests[%d], %d): wrong index %d\n", testNumber, i, logicalIndex);
1112             return;
1113         }
1114     }
1115 
1116     if (! countRunsFirst) {
1117         runCount=ubidi_countRuns(pBiDi, &errorCode);
1118         if(U_FAILURE(errorCode)) {
1119             log_err("ubidi_countRuns(tests[%d]): error %s\n", testNumber, myErrorName(errorCode));
1120             return;
1121         }
1122     }
1123 
1124     for(logicalIndex=0; logicalIndex<len;) {
1125         level=ubidi_getLevelAt(pBiDi, logicalIndex);
1126         ubidi_getLogicalRun(pBiDi, logicalIndex, &logicalIndex, &level2);
1127         if(level!=level2) {
1128             log_err("ubidi_getLogicalRun(tests[%d], run ending at index %d): "
1129                     "wrong level %d instead of %d\n",
1130                     testNumber, logicalIndex, level, level2);
1131         }
1132         if(--runCount<0) {
1133             log_err("\nubidi_getLogicalRun(tests[%d]): wrong number of runs "
1134                     "compared to %d=ubidi_countRuns()\n",
1135                     testNumber, ubidi_countRuns(pBiDi, &errorCode));
1136             return;
1137         }
1138     }
1139     if(runCount!=0) {
1140         log_err("\nubidi_getLogicalRun(tests[%d]): wrong number of runs "
1141                 "compared to %d=ubidi_getRunCount()\n",
1142                 testNumber, ubidi_countRuns(pBiDi, &errorCode));
1143         return;
1144     }
1145 
1146     log_verbose("\n\n");
1147 }
1148 
1149 static void
_testReordering(UBiDi * pBiDi,int testNumber)1150 _testReordering(UBiDi *pBiDi, int testNumber) {
1151     int32_t
1152         logicalMap1[MAXLEN], logicalMap2[MAXLEN], logicalMap3[MAXLEN],
1153         visualMap1[MAXLEN], visualMap2[MAXLEN], visualMap3[MAXLEN], visualMap4[MAXLEN];
1154     UErrorCode errorCode=U_ZERO_ERROR;
1155     const UBiDiLevel *levels;
1156     int32_t i, length=ubidi_getLength(pBiDi),
1157                destLength=ubidi_getResultLength(pBiDi);
1158     int32_t runCount, visualIndex, logicalStart, runLength;
1159     UBool odd;
1160 
1161     if(length<=0) {
1162         return;
1163     }
1164 
1165     /* get the logical and visual maps from the object */
1166     ubidi_getLogicalMap(pBiDi, logicalMap1, &errorCode);
1167     if(U_FAILURE(errorCode)) {
1168         log_err("ubidi_getLogicalMap(tests[%d]): error %s\n", testNumber, myErrorName(errorCode));
1169         return;
1170     }
1171 
1172     ubidi_getVisualMap(pBiDi, visualMap1, &errorCode);
1173     if(U_FAILURE(errorCode)) {
1174         log_err("ubidi_getVisualMap(tests[%d]): error %s\n", testNumber, myErrorName(errorCode));
1175         return;
1176     }
1177 
1178     /* invert them both */
1179     ubidi_invertMap(logicalMap1, visualMap2, length);
1180     ubidi_invertMap(visualMap1, logicalMap2, destLength);
1181 
1182     /* get them from the levels array, too */
1183     levels=ubidi_getLevels(pBiDi, &errorCode);
1184 
1185     if(U_FAILURE(errorCode)) {
1186         log_err("ubidi_getLevels(tests[%d]): error %s\n", testNumber, myErrorName(errorCode));
1187         return;
1188     }
1189 
1190     ubidi_reorderLogical(levels, length, logicalMap3);
1191     ubidi_reorderVisual(levels, length, visualMap3);
1192 
1193     /* get the visual map from the runs, too */
1194     runCount=ubidi_countRuns(pBiDi, &errorCode);
1195     if(U_FAILURE(errorCode)) {
1196         log_err("ubidi_countRuns(tests[%d]): error %s\n", testNumber, myErrorName(errorCode));
1197         return;
1198     }
1199     log_verbose("\n----%2d runs:", runCount);
1200     visualIndex=0;
1201     for(i=0; i<runCount; ++i) {
1202         odd=(UBool)ubidi_getVisualRun(pBiDi, i, &logicalStart, &runLength);
1203         log_verbose(" (%c @%d[%d])", odd ? 'R' : 'L', logicalStart, runLength);
1204         if(UBIDI_LTR==odd) {
1205             do { /* LTR */
1206                 visualMap4[visualIndex++]=logicalStart++;
1207             } while(--runLength>0);
1208         } else {
1209             logicalStart+=runLength;   /* logicalLimit */
1210             do { /* RTL */
1211                 visualMap4[visualIndex++]=--logicalStart;
1212             } while(--runLength>0);
1213         }
1214     }
1215     log_verbose("\n");
1216 
1217     /* print all the maps */
1218     log_verbose("logical maps:\n");
1219     for(i=0; i<length; ++i) {
1220         log_verbose("%4d", logicalMap1[i]);
1221     }
1222     log_verbose("\n");
1223     for(i=0; i<length; ++i) {
1224         log_verbose("%4d", logicalMap2[i]);
1225     }
1226     log_verbose("\n");
1227     for(i=0; i<length; ++i) {
1228         log_verbose("%4d", logicalMap3[i]);
1229     }
1230 
1231     log_verbose("\nvisual maps:\n");
1232     for(i=0; i<destLength; ++i) {
1233         log_verbose("%4d", visualMap1[i]);
1234     }
1235     log_verbose("\n");
1236     for(i=0; i<destLength; ++i) {
1237         log_verbose("%4d", visualMap2[i]);
1238     }
1239     log_verbose("\n");
1240     for(i=0; i<length; ++i) {
1241         log_verbose("%4d", visualMap3[i]);
1242     }
1243     log_verbose("\n");
1244     for(i=0; i<length; ++i) {
1245         log_verbose("%4d", visualMap4[i]);
1246     }
1247     log_verbose("\n");
1248 
1249     /* check that the indexes are the same between these and ubidi_getLogical/VisualIndex() */
1250     for(i=0; i<length; ++i) {
1251         if(logicalMap1[i]!=logicalMap2[i]) {
1252             log_err("bidi reordering error in tests[%d]: logicalMap1[i]!=logicalMap2[i] at i=%d\n", testNumber, i);
1253             break;
1254         }
1255         if(logicalMap1[i]!=logicalMap3[i]) {
1256             log_err("bidi reordering error in tests[%d]: logicalMap1[i]!=logicalMap3[i] at i=%d\n", testNumber, i);
1257             break;
1258         }
1259 
1260         if(visualMap1[i]!=visualMap2[i]) {
1261             log_err("bidi reordering error in tests[%d]: visualMap1[i]!=visualMap2[i] at i=%d\n", testNumber, i);
1262             break;
1263         }
1264         if(visualMap1[i]!=visualMap3[i]) {
1265             log_err("bidi reordering error in tests[%d]: visualMap1[i]!=visualMap3[i] at i=%d\n", testNumber, i);
1266             break;
1267         }
1268         if(visualMap1[i]!=visualMap4[i]) {
1269             log_err("bidi reordering error in tests[%d]: visualMap1[i]!=visualMap4[i] at i=%d\n", testNumber, i);
1270             break;
1271         }
1272 
1273         if(logicalMap1[i]!=ubidi_getVisualIndex(pBiDi, i, &errorCode)) {
1274             log_err("bidi reordering error in tests[%d]: logicalMap1[i]!=ubidi_getVisualIndex(i) at i=%d\n", testNumber, i);
1275             break;
1276         }
1277         if(U_FAILURE(errorCode)) {
1278             log_err("ubidi_getVisualIndex(tests[%d], %d): error %s\n", testNumber, i, myErrorName(errorCode));
1279             break;
1280         }
1281         if(visualMap1[i]!=ubidi_getLogicalIndex(pBiDi, i, &errorCode)) {
1282             log_err("bidi reordering error in tests[%d]: visualMap1[i]!=ubidi_getLogicalIndex(i) at i=%d\n", testNumber, i);
1283             break;
1284         }
1285         if(U_FAILURE(errorCode)) {
1286             log_err("ubidi_getLogicalIndex(tests[%d], %d): error %s\n", testNumber, i, myErrorName(errorCode));
1287             break;
1288         }
1289     }
1290 }
1291 
1292 #define RETURN_IF_BAD_ERRCODE(x) UPRV_BLOCK_MACRO_BEGIN { \
1293     if (U_FAILURE(errorCode)) {      \
1294         log_err("\nbad errorCode %d at %s\n", errorCode, (x));  \
1295         return;     \
1296     }               \
1297 } UPRV_BLOCK_MACRO_END
1298 
1299 #define STRING_TEST_CASE(s) { (s), UPRV_LENGTHOF(s) }
1300 
testGetBaseDirection(void)1301 static void testGetBaseDirection(void) {
1302     UBiDiDirection dir;
1303     int i;
1304 
1305 /* Test Data */
1306     static const UChar
1307 /*Mixed Start with L*/
1308     stringMixedEnglishFirst[]={ 0x61, 0x627, 0x32, 0x6f3, 0x61, 0x34, 0 },
1309 /*Mixed Start with AL*/
1310     stringMixedArabicFirst[]={ 0x661, 0x627, 0x662, 0x6f3, 0x61, 0x664, 0 },
1311 /*Mixed Start with R*/
1312     stringMixedHebrewFirst[]={ 0x05EA, 0x627, 0x662, 0x6f3, 0x61, 0x664, 0 },
1313 /*All AL (Arabic. Persian)*/
1314     stringPersian[]={0x0698, 0x067E, 0x0686, 0x06AF, 0},
1315 /*All R (Hebrew etc.)*/
1316     stringHebrew[]={0x0590, 0x05D5, 0x05EA, 0x05F1, 0},
1317 /*All L (English)*/
1318     stringEnglish[]={0x71, 0x61, 0x66, 0},
1319 /*Mixed Start with weak AL an then L*/
1320     stringStartWeakAL[]={ 0x0663, 0x71, 0x61, 0x66, 0},
1321 /*Mixed Start with weak L and then AL*/
1322     stringStartWeakL[]={0x31, 0x0698, 0x067E, 0x0686, 0x06AF, 0},
1323 /*Empty*/
1324     stringEmpty[]={0},
1325 /*Surrogate Char.*/
1326     stringSurrogateChar[]={0xD800, 0xDC00, 0},
1327 /*Invalid UChar*/
1328     stringInvalidUchar[]={-1},
1329 /*All weak L (English Digits)*/
1330     stringAllEnglishDigits[]={0x31, 0x32, 0x33, 0},
1331 /*All weak AL (Arabic Digits)*/
1332     stringAllArabicDigits[]={0x0663, 0x0664, 0x0665, 0},
1333 /*First L (English) others are R (Hebrew etc.) */
1334     stringFirstL[] = {0x71, 0x0590, 0x05D5, 0x05EA, 0x05F1, 0},
1335 /*Last R (Hebrew etc.) others are weak L (English Digits)*/
1336     stringLastR[] = {0x31, 0x32, 0x33, 0x05F1, 0};
1337 
1338     static const struct {
1339         const UChar *s;
1340         int32_t length;
1341     } testCases[]={
1342         STRING_TEST_CASE(stringMixedEnglishFirst),
1343         STRING_TEST_CASE(stringMixedArabicFirst),
1344         STRING_TEST_CASE(stringMixedHebrewFirst),
1345         STRING_TEST_CASE(stringPersian),
1346         STRING_TEST_CASE(stringHebrew),
1347         STRING_TEST_CASE(stringEnglish),
1348         STRING_TEST_CASE(stringStartWeakAL),
1349         STRING_TEST_CASE(stringStartWeakL),
1350         STRING_TEST_CASE(stringEmpty),
1351         STRING_TEST_CASE(stringSurrogateChar),
1352         STRING_TEST_CASE(stringInvalidUchar),
1353         STRING_TEST_CASE(stringAllEnglishDigits),
1354         STRING_TEST_CASE(stringAllArabicDigits),
1355         STRING_TEST_CASE(stringFirstL),
1356         STRING_TEST_CASE(stringLastR),
1357     };
1358 
1359 /* Expected results */
1360     static const UBiDiDirection expectedDir[] ={
1361         UBIDI_LTR, UBIDI_RTL, UBIDI_RTL,
1362         UBIDI_RTL, UBIDI_RTL, UBIDI_LTR,
1363         UBIDI_LTR, UBIDI_RTL, UBIDI_NEUTRAL,
1364         UBIDI_LTR, UBIDI_NEUTRAL, UBIDI_NEUTRAL,
1365         UBIDI_NEUTRAL, UBIDI_LTR, UBIDI_RTL
1366     };
1367 
1368     log_verbose("testGetBaseDirection() with %u test cases ---\n",
1369     UPRV_LENGTHOF(testCases));
1370 /* Run Tests */
1371      for(i=0; i<UPRV_LENGTHOF(testCases); ++i) {
1372         dir = ubidi_getBaseDirection(testCases[i].s, testCases[i].length );
1373         log_verbose("Testing case %d\tReceived dir %d\n", i, dir);
1374         if (dir != expectedDir[i])
1375             log_err("\nFailed getBaseDirection case %d Expected  %d \tReceived %d\n",
1376             i, expectedDir[i], dir);
1377     }
1378 
1379 /* Misc. tests */
1380 /* NULL string */
1381     dir = ubidi_getBaseDirection(NULL, 3);
1382     if (dir != UBIDI_NEUTRAL )
1383         log_err("\nFailed getBaseDirection for NULL string " ,
1384         "\nExpected  %d \nReceived %d", UBIDI_NEUTRAL, dir);
1385 /*All L- English string and length=-3 */
1386     dir = ubidi_getBaseDirection( stringEnglish, -3);
1387     if (dir != UBIDI_NEUTRAL )
1388         log_err("\nFailed getBaseDirection for string w length= -3 ",
1389         "\nExpected  %d \nReceived %d", UBIDI_NEUTRAL, dir);
1390 /*All L- English string and length=-1 */
1391     dir = ubidi_getBaseDirection( stringEnglish, -1);
1392     if (dir != UBIDI_LTR )
1393         log_err("\nFailed getBaseDirection for English string w length= -1 ",
1394         "\nExpected  %d \nReceived %d", UBIDI_LTR, dir);
1395 /*All AL- Persian string and length=-1 */
1396     dir = ubidi_getBaseDirection( stringPersian, -1);
1397     if (dir != UBIDI_RTL )
1398         log_err("\nFailed getBaseDirection for Persian string w length= -1 ",
1399         "\nExpected  %d \nReceived %d", UBIDI_RTL, dir);
1400 /*All R- Hebrew string and length=-1 */
1401     dir = ubidi_getBaseDirection( stringHebrew, -1);
1402     if (dir != UBIDI_RTL )
1403         log_err("\nFailed getBaseDirection for Hebrew string w length= -1 ",
1404         "\nExpected  %d \nReceived %d", UBIDI_RTL, dir);
1405 /*All weak L- English digits string and length=-1 */
1406     dir = ubidi_getBaseDirection(stringAllEnglishDigits, -1);
1407     if (dir != UBIDI_NEUTRAL )
1408         log_err("\nFailed getBaseDirection for English digits string w length= -1 ",
1409         "\nExpected  %d \nReceived %d", UBIDI_NEUTRAL, dir);
1410 /*All weak AL- Arabic digits string and length=-1 */
1411     dir = ubidi_getBaseDirection(stringAllArabicDigits, -1);
1412     if (dir != UBIDI_NEUTRAL )
1413         log_err("\nFailed getBaseDirection for Arabic string w length= -1 ",
1414         "\nExpected  %d \nReceived %d", UBIDI_NEUTRAL, dir);
1415 
1416 }
1417 
1418 
doMisc(void)1419 static void doMisc(void) {
1420 /* Miscellaneous tests to exercize less popular code paths */
1421     UBiDi *bidi, *bidiLine;
1422     UChar src[MAXLEN], dest[MAXLEN];
1423     int32_t srcLen, destLen, runCount, i;
1424     UBiDiLevel level;
1425     UBiDiDirection dir;
1426     int32_t map[MAXLEN];
1427     UErrorCode errorCode=U_ZERO_ERROR;
1428     static const int32_t srcMap[6] = {0,1,-1,5,4};
1429     static const int32_t dstMap[6] = {0,1,-1,-1,4,3};
1430 
1431     bidi = ubidi_openSized(120, 66, &errorCode);
1432     if (bidi == NULL) {
1433         log_err("Error with openSized(120, 66)\n");
1434         return;
1435     }
1436     bidiLine = ubidi_open();
1437     if (bidi == NULL) {
1438         log_err("Error with open()\n");
1439         return;
1440     }
1441 
1442     destLen = ubidi_writeReverse(src, 0, dest, MAXLEN, 0, &errorCode);
1443     if (destLen != 0) {
1444         log_err("\nwriteReverse should return zero length, ",
1445                 "returned %d instead\n", destLen);
1446     }
1447     RETURN_IF_BAD_ERRCODE("#1#");
1448 
1449     ubidi_setPara(bidi, src, 0, UBIDI_LTR, NULL, &errorCode);
1450     destLen = ubidi_writeReordered(bidi, dest, MAXLEN, 0, &errorCode);
1451     if (destLen != 0) {
1452         log_err("\nwriteReordered should return zero length, ",
1453                 "returned %d instead\n", destLen);
1454     }
1455     RETURN_IF_BAD_ERRCODE("#2#");
1456 
1457     srcLen = u_unescape("abc       ", src, MAXLEN);
1458     ubidi_setPara(bidi, src, srcLen, UBIDI_RTL, NULL, &errorCode);
1459     ubidi_setLine(bidi, 0, 6, bidiLine, &errorCode);
1460     for (i = 3; i < 6; i++) {
1461         level = ubidi_getLevelAt(bidiLine, i);
1462         if (level != UBIDI_RTL) {
1463             log_err("\nTrailing space at index %d should get paragraph level"
1464                     "%d, got %d instead\n", i, UBIDI_RTL, level);
1465         }
1466     }
1467     RETURN_IF_BAD_ERRCODE("#3#");
1468 
1469     srcLen = u_unescape("abc       def", src, MAXLEN);
1470     ubidi_setPara(bidi, src, srcLen, UBIDI_RTL, NULL, &errorCode);
1471     ubidi_setLine(bidi, 0, 6, bidiLine, &errorCode);
1472     for (i = 3; i < 6; i++) {
1473         level = ubidi_getLevelAt(bidiLine, i);
1474         if (level != UBIDI_RTL) {
1475             log_err("\nTrailing space at index %d should get paragraph level"
1476                     "%d, got %d instead\n", i, UBIDI_RTL, level);
1477         }
1478     }
1479     RETURN_IF_BAD_ERRCODE("#4#");
1480 
1481     srcLen = u_unescape("abcdefghi    ", src, MAXLEN);
1482     ubidi_setPara(bidi, src, srcLen, UBIDI_RTL, NULL, &errorCode);
1483     ubidi_setLine(bidi, 0, 6, bidiLine, &errorCode);
1484     for (i = 3; i < 6; i++) {
1485         level = ubidi_getLevelAt(bidiLine, i);
1486         if (level != 2) {
1487             log_err("\nTrailing char at index %d should get level 2, "
1488                     "got %d instead\n", i, level);
1489         }
1490     }
1491     RETURN_IF_BAD_ERRCODE("#5#");
1492 
1493     ubidi_setReorderingOptions(bidi, UBIDI_OPTION_REMOVE_CONTROLS);
1494     srcLen = u_unescape("\\u200eabc       def", src, MAXLEN);
1495     ubidi_setPara(bidi, src, srcLen, UBIDI_RTL, NULL, &errorCode);
1496     ubidi_setLine(bidi, 0, 6, bidiLine, &errorCode);
1497     destLen = ubidi_getResultLength(bidiLine);
1498     if (destLen != 5) {
1499         log_err("\nWrong result length, should be 5, got %d\n", destLen);
1500     }
1501     RETURN_IF_BAD_ERRCODE("#6#");
1502 
1503     srcLen = u_unescape("abcdefghi", src, MAXLEN);
1504     ubidi_setPara(bidi, src, srcLen, UBIDI_LTR, NULL, &errorCode);
1505     ubidi_setLine(bidi, 0, 6, bidiLine, &errorCode);
1506     dir = ubidi_getDirection(bidiLine);
1507     if (dir != UBIDI_LTR) {
1508         log_err("\nWrong direction #1, should be %d, got %d\n",
1509                 UBIDI_LTR, dir);
1510     }
1511     RETURN_IF_BAD_ERRCODE("#7#");
1512 
1513     ubidi_setPara(bidi, src, 0, UBIDI_LTR, NULL, &errorCode);
1514     runCount = ubidi_countRuns(bidi, &errorCode);
1515     if (runCount != 0) {
1516         log_err("\nWrong number of runs #1, should be 0, got %d\n", runCount);
1517     }
1518     RETURN_IF_BAD_ERRCODE("#8#");
1519 
1520     srcLen = u_unescape("          ", src, MAXLEN);
1521     ubidi_setPara(bidi, src, srcLen, UBIDI_RTL, NULL, &errorCode);
1522     ubidi_setLine(bidi, 0, 6, bidiLine, &errorCode);
1523     runCount = ubidi_countRuns(bidiLine, &errorCode);
1524     if (runCount != 1) {
1525         log_err("\nWrong number of runs #2, should be 1, got %d\n", runCount);
1526     }
1527     RETURN_IF_BAD_ERRCODE("#9#");
1528 
1529     srcLen = u_unescape("a\\u05d0        bc", src, MAXLEN);
1530     ubidi_setPara(bidi, src, srcLen, UBIDI_RTL, NULL, &errorCode);
1531     ubidi_setLine(bidi, 0, 6, bidiLine, &errorCode);
1532     dir = ubidi_getDirection(bidi);
1533     if (dir != UBIDI_MIXED) {
1534         log_err("\nWrong direction #2, should be %d, got %d\n",
1535                 UBIDI_MIXED, dir);
1536     }
1537     dir = ubidi_getDirection(bidiLine);
1538     if (dir != UBIDI_MIXED) {
1539         log_err("\nWrong direction #3, should be %d, got %d\n",
1540                 UBIDI_MIXED, dir);
1541     }
1542     runCount = ubidi_countRuns(bidiLine, &errorCode);
1543     if (runCount != 2) {
1544         log_err("\nWrong number of runs #3, should be 2, got %d\n", runCount);
1545     }
1546     RETURN_IF_BAD_ERRCODE("#10#");
1547 
1548     ubidi_invertMap(srcMap, map, 5);
1549     if (memcmp(dstMap, map, sizeof(dstMap))) {
1550         log_err("\nUnexpected inverted Map, got ");
1551         for (i = 0; i < 6; i++) {
1552             log_err("%d ", map[i]);
1553         }
1554         log_err("\n");
1555     }
1556 
1557     /* test REMOVE_BIDI_CONTROLS together with DO_MIRRORING */
1558     srcLen = u_unescape("abc\\u200e", src, MAXLEN);
1559     ubidi_setPara(bidi, src, srcLen, UBIDI_LTR, NULL, &errorCode);
1560     destLen = ubidi_writeReordered(bidi, dest, MAXLEN,
1561               UBIDI_REMOVE_BIDI_CONTROLS | UBIDI_DO_MIRRORING, &errorCode);
1562     if (destLen != 3 || memcmp(dest, src, 3 * sizeof(UChar))) {
1563         log_err("\nWrong result #1, should be 'abc', got '%s'\n",
1564                 aescstrdup(dest, destLen));
1565     }
1566     RETURN_IF_BAD_ERRCODE("#11#");
1567 
1568     /* test inverse Bidi with marks and contextual orientation */
1569     ubidi_setReorderingMode(bidi, UBIDI_REORDER_INVERSE_LIKE_DIRECT);
1570     ubidi_setReorderingOptions(bidi, UBIDI_OPTION_INSERT_MARKS);
1571     ubidi_setPara(bidi, src, 0, UBIDI_DEFAULT_RTL, NULL, &errorCode);
1572     destLen = ubidi_writeReordered(bidi, dest, MAXLEN, 0, &errorCode);
1573     if (destLen != 0) {
1574         log_err("\nWrong result #2, length should be 0, got %d\n", destLen);
1575     }
1576     RETURN_IF_BAD_ERRCODE("#12#");
1577     srcLen = u_unescape("   ", src, MAXLEN);
1578     ubidi_setPara(bidi, src, srcLen, UBIDI_DEFAULT_RTL, NULL, &errorCode);
1579     destLen = ubidi_writeReordered(bidi, dest, MAXLEN, 0, &errorCode);
1580     if (destLen != 3 || memcmp(dest, src, destLen * sizeof(UChar))) {
1581         log_err("\nWrong result #3, should be '   ', got '%s'\n",
1582                 aescstrdup(dest, destLen));
1583     }
1584     RETURN_IF_BAD_ERRCODE("#13#");
1585     srcLen = u_unescape("abc", src, MAXLEN);
1586     ubidi_setPara(bidi, src, srcLen, UBIDI_DEFAULT_RTL, NULL, &errorCode);
1587     destLen = ubidi_writeReordered(bidi, dest, MAXLEN, 0, &errorCode);
1588     if (destLen != 3 || memcmp(dest, src, destLen * sizeof(UChar))) {
1589         log_err("\nWrong result #4, should be 'abc', got '%s'\n",
1590                 aescstrdup(dest, destLen));
1591     }
1592     RETURN_IF_BAD_ERRCODE("#14#");
1593     srcLen = u_unescape("\\u05d0\\u05d1", src, MAXLEN);
1594     ubidi_setPara(bidi, src, srcLen, UBIDI_DEFAULT_RTL, NULL, &errorCode);
1595     destLen = ubidi_writeReordered(bidi, dest, MAXLEN, 0, &errorCode);
1596     srcLen = u_unescape("\\u05d1\\u05d0", src, MAXLEN);
1597     if (destLen != 2 || memcmp(dest, src, destLen * sizeof(UChar))) {
1598         log_err("\nWrong result #5, should be '%s', got '%s'\n",
1599                 aescstrdup(src, srcLen), aescstrdup(dest, destLen));
1600     }
1601     RETURN_IF_BAD_ERRCODE("#15#");
1602     srcLen = u_unescape("abc \\u05d0\\u05d1", src, MAXLEN);
1603     ubidi_setPara(bidi, src, srcLen, UBIDI_DEFAULT_RTL, NULL, &errorCode);
1604     destLen = ubidi_writeReordered(bidi, dest, MAXLEN, 0, &errorCode);
1605     srcLen = u_unescape("\\u05d1\\u05d0 abc", src, MAXLEN);
1606     if (destLen != 6 || memcmp(dest, src, destLen * sizeof(UChar))) {
1607         log_err("\nWrong result #6, should be '%s', got '%s'\n",
1608                 aescstrdup(src, srcLen), aescstrdup(dest, destLen));
1609     }
1610     RETURN_IF_BAD_ERRCODE("#16#");
1611     srcLen = u_unescape("\\u05d0\\u05d1 abc", src, MAXLEN);
1612     ubidi_setPara(bidi, src, srcLen, UBIDI_DEFAULT_RTL, NULL, &errorCode);
1613     destLen = ubidi_writeReordered(bidi, dest, MAXLEN, 0, &errorCode);
1614     srcLen = u_unescape("\\u200fabc \\u05d1\\u05d0", src, MAXLEN);
1615     if (destLen != 7 || memcmp(dest, src, destLen * sizeof(UChar))) {
1616         log_err("\nWrong result #7, should be '%s', got '%s'\n",
1617                 aescstrdup(src, srcLen), aescstrdup(dest, destLen));
1618     }
1619     RETURN_IF_BAD_ERRCODE("#17#");
1620     srcLen = u_unescape("\\u05d0\\u05d1 abc .-=", src, MAXLEN);
1621     ubidi_setPara(bidi, src, srcLen, UBIDI_DEFAULT_RTL, NULL, &errorCode);
1622     destLen = ubidi_writeReordered(bidi, dest, MAXLEN, 0, &errorCode);
1623     srcLen = u_unescape("\\u200f=-. abc \\u05d1\\u05d0", src, MAXLEN);
1624     if (destLen != 11 || memcmp(dest, src, destLen * sizeof(UChar))) {
1625         log_err("\nWrong result #8, should be '%s', got '%s'\n",
1626                 aescstrdup(src, srcLen), aescstrdup(dest, destLen));
1627     }
1628     RETURN_IF_BAD_ERRCODE("#18#");
1629     ubidi_orderParagraphsLTR(bidi, TRUE);
1630     srcLen = u_unescape("\n\r   \n\rabc\n\\u05d0\\u05d1\rabc \\u05d2\\u05d3\n\r"
1631                         "\\u05d4\\u05d5 abc\n\\u05d6\\u05d7 abc .-=\r\n"
1632                         "-* \\u05d8\\u05d9 abc .-=", src, MAXLEN);
1633     ubidi_setPara(bidi, src, srcLen, UBIDI_DEFAULT_RTL, NULL, &errorCode);
1634     destLen = ubidi_writeReordered(bidi, dest, MAXLEN, 0, &errorCode);
1635     srcLen = u_unescape("\n\r   \n\rabc\n\\u05d1\\u05d0\r\\u05d3\\u05d2 abc\n\r"
1636                         "\\u200fabc \\u05d5\\u05d4\n\\u200f=-. abc \\u05d7\\u05d6\r\n"
1637                         "\\u200f=-. abc \\u05d9\\u05d8 *-", src, MAXLEN);
1638     if (destLen != 57 || memcmp(dest, src, destLen * sizeof(UChar))) {
1639         log_err("\nWrong result #9, should be '%s', got '%s'\n",
1640                 aescstrdup(src, srcLen), aescstrdup(dest, destLen));
1641     }
1642     RETURN_IF_BAD_ERRCODE("#19#");
1643     srcLen = u_unescape("\\u05d0 \t", src, MAXLEN);
1644     ubidi_setPara(bidi, src, srcLen, UBIDI_LTR, NULL, &errorCode);
1645     destLen = ubidi_writeReordered(bidi, dest, MAXLEN, 0, &errorCode);
1646     srcLen = u_unescape("\\u05D0\\u200e \t", src, MAXLEN);
1647     if (destLen != 4 || memcmp(dest, src, destLen * sizeof(UChar))) {
1648         log_err("\nWrong result #10, should be '%s', got '%s'\n",
1649                 aescstrdup(src, srcLen), aescstrdup(dest, destLen));
1650     }
1651     RETURN_IF_BAD_ERRCODE("#20#");
1652     srcLen = u_unescape("\\u05d0 123 \t\\u05d1 123 \\u05d2", src, MAXLEN);
1653     ubidi_setPara(bidi, src, srcLen, UBIDI_LTR, NULL, &errorCode);
1654     destLen = ubidi_writeReordered(bidi, dest, MAXLEN, 0, &errorCode);
1655     srcLen = u_unescape("\\u05d0 \\u200e123\\u200e \t\\u05d2 123 \\u05d1", src, MAXLEN);
1656     if (destLen != 16 || memcmp(dest, src, destLen * sizeof(UChar))) {
1657         log_err("\nWrong result #11, should be '%s', got '%s'\n",
1658                 aescstrdup(src, srcLen), aescstrdup(dest, destLen));
1659     }
1660     RETURN_IF_BAD_ERRCODE("#21#");
1661     srcLen = u_unescape("\\u05d0 123 \\u0660\\u0661 ab", src, MAXLEN);
1662     ubidi_setPara(bidi, src, srcLen, UBIDI_LTR, NULL, &errorCode);
1663     destLen = ubidi_writeReordered(bidi, dest, MAXLEN, 0, &errorCode);
1664     srcLen = u_unescape("\\u05d0 \\u200e123 \\u200e\\u0660\\u0661 ab", src, MAXLEN);
1665     if (destLen != 13 || memcmp(dest, src, destLen * sizeof(UChar))) {
1666         log_err("\nWrong result #12, should be '%s', got '%s'\n",
1667                 aescstrdup(src, srcLen), aescstrdup(dest, destLen));
1668     }
1669     RETURN_IF_BAD_ERRCODE("#22#");
1670     srcLen = u_unescape("ab \t", src, MAXLEN);
1671     ubidi_setPara(bidi, src, srcLen, UBIDI_RTL, NULL, &errorCode);
1672     destLen = ubidi_writeReordered(bidi, dest, MAXLEN, 0, &errorCode);
1673     srcLen = u_unescape("\\u200f\t ab", src, MAXLEN);
1674     if (destLen != 5 || memcmp(dest, src, destLen * sizeof(UChar))) {
1675         log_err("\nWrong result #13, should be '%s', got '%s'\n",
1676                 aescstrdup(src, srcLen), aescstrdup(dest, destLen));
1677     }
1678     RETURN_IF_BAD_ERRCODE("#23#");
1679 
1680     /* check exceeding para level */
1681     ubidi_close(bidi);
1682     bidi = ubidi_open();
1683     srcLen = u_unescape("A\\u202a\\u05d0\\u202aC\\u202c\\u05d1\\u202cE", src, MAXLEN);
1684     ubidi_setPara(bidi, src, srcLen, UBIDI_MAX_EXPLICIT_LEVEL - 1, NULL, &errorCode);
1685     level = ubidi_getLevelAt(bidi, 2);
1686     if (level != UBIDI_MAX_EXPLICIT_LEVEL) {
1687         log_err("\nWrong level at index 2\n, should be %d, got %d\n", UBIDI_MAX_EXPLICIT_LEVEL, level);
1688     }
1689     RETURN_IF_BAD_ERRCODE("#24#");
1690 
1691     /* check 1-char runs with RUNS_ONLY */
1692     ubidi_setReorderingMode(bidi, UBIDI_REORDER_RUNS_ONLY);
1693     srcLen = u_unescape("a \\u05d0 b \\u05d1 c \\u05d2 d ", src, MAXLEN);
1694     ubidi_setPara(bidi, src, srcLen, UBIDI_LTR, NULL, &errorCode);
1695     runCount = ubidi_countRuns(bidi, &errorCode);
1696     if (runCount != 14) {
1697         log_err("\nWrong number of runs #3, should be 14, got %d\n", runCount);
1698     }
1699     RETURN_IF_BAD_ERRCODE("#25#");
1700 
1701     ubidi_close(bidi);
1702     ubidi_close(bidiLine);
1703 }
1704 
1705 static void
testFailureRecovery(void)1706 testFailureRecovery(void) {
1707     UErrorCode errorCode;
1708     UBiDi *bidi, *bidiLine;
1709     UChar src[MAXLEN];
1710     int32_t srcLen;
1711     UBiDiLevel level;
1712     UBiDiReorderingMode rm;
1713     static UBiDiLevel myLevels[3] = {6,5,4};
1714 
1715     log_verbose("\nEntering TestFailureRecovery\n\n");
1716     errorCode = U_FILE_ACCESS_ERROR;
1717     if (ubidi_writeReordered(NULL, NULL, 0, 0, &errorCode) != 0) {
1718         log_err("ubidi_writeReordered did not return 0 when passed a failing UErrorCode\n");
1719     }
1720     if (ubidi_writeReverse(NULL, 0, NULL, 0, 0, &errorCode) != 0) {
1721         log_err("ubidi_writeReverse did not return 0 when passed a failing UErrorCode\n");
1722     }
1723     errorCode = U_ZERO_ERROR;
1724     if (ubidi_writeReordered(NULL, NULL, 0, 0, &errorCode) != 0 || errorCode != U_ILLEGAL_ARGUMENT_ERROR) {
1725         log_err("ubidi_writeReordered did not fail as expected\n");
1726     }
1727 
1728     bidi = ubidi_open();
1729     srcLen = u_unescape("abc", src, MAXLEN);
1730     errorCode = U_ZERO_ERROR;
1731     ubidi_setPara(bidi, src, srcLen, UBIDI_DEFAULT_LTR - 1, NULL, &errorCode);
1732     if (U_SUCCESS(errorCode)) {
1733         log_err("\nubidi_setPara did not fail when passed too big para level\n");
1734     }
1735     errorCode = U_ZERO_ERROR;
1736     if (ubidi_writeReverse(NULL, 0, NULL, 0, 0, &errorCode) != 0 || errorCode != U_ILLEGAL_ARGUMENT_ERROR) {
1737         log_err("ubidi_writeReverse did not fail as expected\n");
1738     }
1739     bidiLine = ubidi_open();
1740     errorCode = U_ZERO_ERROR;
1741     ubidi_setLine(bidi, 0, 6, bidiLine, &errorCode);
1742     if (U_SUCCESS(errorCode)) {
1743         log_err("\nubidi_setLine did not fail when called before valid setPara()\n");
1744     }
1745     errorCode = U_ZERO_ERROR;
1746     srcLen = u_unescape("abc", src, MAXLEN);
1747     ubidi_setPara(bidi, src, srcLen, UBIDI_LTR + 4, NULL, &errorCode);
1748     level = ubidi_getLevelAt(bidi, 3);
1749     if (level != 0) {
1750         log_err("\nubidi_getLevelAt did not fail when called with bad argument\n");
1751     }
1752     errorCode = U_ZERO_ERROR;
1753     ubidi_close(bidi);
1754     bidi = ubidi_openSized(-1, 0, &errorCode);
1755     if (U_SUCCESS(errorCode)) {
1756         log_err("\nubidi_openSized did not fail when called with bad argument\n");
1757     }
1758     ubidi_close(bidi);
1759     bidi = ubidi_openSized(2, 1, &errorCode);
1760     errorCode = U_ZERO_ERROR;
1761     srcLen = u_unescape("abc", src, MAXLEN);
1762     ubidi_setPara(bidi, src, srcLen, UBIDI_LTR, NULL, &errorCode);
1763     if (U_SUCCESS(errorCode)) {
1764         log_err("\nsetPara did not fail when called with text too long\n");
1765     }
1766     errorCode = U_ZERO_ERROR;
1767     srcLen = u_unescape("=2", src, MAXLEN);
1768     ubidi_setPara(bidi, src, srcLen, UBIDI_RTL, NULL, &errorCode);
1769     ubidi_countRuns(bidi, &errorCode);
1770     if (U_SUCCESS(errorCode)) {
1771         log_err("\nsetPara did not fail when called for too many runs\n");
1772     }
1773     ubidi_close(bidi);
1774     bidi = ubidi_open();
1775     rm = ubidi_getReorderingMode(bidi);
1776     ubidi_setReorderingMode(bidi, UBIDI_REORDER_DEFAULT - 1);
1777     if (rm != ubidi_getReorderingMode(bidi)) {
1778         log_err("\nsetReorderingMode with bad argument #1 should have no effect\n");
1779     }
1780     ubidi_setReorderingMode(bidi, 9999);
1781     if (rm != ubidi_getReorderingMode(bidi)) {
1782         log_err("\nsetReorderingMode with bad argument #2 should have no effect\n");
1783     }
1784 
1785     /* Try a surrogate char */
1786     errorCode = U_ZERO_ERROR;
1787     srcLen = u_unescape("\\uD800\\uDC00", src, MAXLEN);
1788     ubidi_setPara(bidi, src, srcLen, UBIDI_RTL, NULL, &errorCode);
1789     if (ubidi_getDirection(bidi) != UBIDI_MIXED) {
1790         log_err("\ngetDirection for 1st surrogate char should be MIXED\n");
1791     }
1792     errorCode = U_ZERO_ERROR;
1793     srcLen = u_unescape("abc", src, MAXLEN);
1794     ubidi_setPara(bidi, src, srcLen, 5, myLevels, &errorCode);
1795     if (U_SUCCESS(errorCode)) {
1796         log_err("\nsetPara did not fail when called with bad levels\n");
1797     }
1798     ubidi_close(bidi);
1799     ubidi_close(bidiLine);
1800 
1801     log_verbose("\nExiting TestFailureRecovery\n\n");
1802 }
1803 
1804 static void
testMultipleParagraphs(void)1805 testMultipleParagraphs(void) {
1806     static const char* const text = "__ABC\\u001c"          /* Para #0 offset 0 */
1807                                     "__\\u05d0DE\\u001c"    /*       1        6 */
1808                                     "__123\\u001c"          /*       2       12 */
1809                                     "\\u000d\\u000a"        /*       3       18 */
1810                                     "FG\\u000d"             /*       4       20 */
1811                                     "\\u000d"               /*       5       23 */
1812                                     "HI\\u000d\\u000a"      /*       6       24 */
1813                                     "\\u000d\\u000a"        /*       7       28 */
1814                                     "\\u000a"               /*       8       30 */
1815                                     "\\u000a"               /*       9       31 */
1816                                     "JK\\u001c";            /*      10       32 */
1817     static const int32_t paraCount=11;
1818     static const int32_t paraBounds[]={0, 6, 12, 18, 20, 23, 24, 28, 30, 31, 32, 35};
1819     static const UBiDiLevel paraLevels[]={UBIDI_LTR, UBIDI_RTL, UBIDI_DEFAULT_LTR, UBIDI_DEFAULT_RTL, 22, 23};
1820     static const UBiDiLevel multiLevels[6][11] = {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
1821                                                   {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
1822                                                   {0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0},
1823                                                   {0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0},
1824                                                   {22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22},
1825                                                   {23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23}};
1826     static const char* const text2 = "\\u05d0 1-2\\u001c\\u0630 1-2\\u001c1-2";
1827     static const UBiDiLevel levels2[] = {1,1,2,2,2,0, 1,1,2,1,2,0, 2,2,2};
1828     static UBiDiLevel myLevels[10] = {0,0,0,0,0,0,0,0,0,0};
1829     static const UChar multiparaTestString[] = {
1830         0x5de, 0x5e0, 0x5e1, 0x5d4, 0x20,  0x5e1, 0x5e4, 0x5da,
1831         0x20,  0xa,   0xa,   0x41,  0x72,  0x74,  0x69,  0x73,
1832         0x74,  0x3a,  0x20,  0x5de, 0x5e0, 0x5e1, 0x5d4, 0x20,
1833         0x5e1, 0x5e4, 0x5da, 0x20,  0xa,   0xa,   0x41,  0x6c,
1834         0x62,  0x75,  0x6d,  0x3a,  0x20,  0x5de, 0x5e0, 0x5e1,
1835         0x5d4, 0x20,  0x5e1, 0x5e4, 0x5da, 0x20,  0xa,   0xa,
1836         0x54,  0x69,  0x6d,  0x65,  0x3a,  0x20,  0x32,  0x3a,
1837         0x32,  0x37,  0xa,  0xa
1838     };
1839     static const UBiDiLevel multiparaTestLevels[] = {
1840         1, 1, 1, 1, 1, 1, 1, 1,
1841         1, 1, 0, 0, 0, 0, 0, 0,
1842         0, 0, 0, 1, 1, 1, 1, 1,
1843         1, 1, 1, 0, 0, 0, 0, 0,
1844         0, 0, 0, 0, 0, 1, 1, 1,
1845         1, 1, 1, 1, 1, 0, 0, 0,
1846         0, 0, 0, 0, 0, 0, 0, 0,
1847         0, 0, 0, 0
1848     };
1849     UBiDiLevel gotLevel;
1850     const UBiDiLevel* gotLevels;
1851     UBool orderParagraphsLTR;
1852     UChar src[MAXLEN], dest[MAXLEN];
1853     UErrorCode errorCode=U_ZERO_ERROR;
1854     UBiDi* pBidi=ubidi_open();
1855     UBiDi* pLine;
1856     int32_t srcSize, count, paraStart, paraLimit, paraIndex, length;
1857     int32_t srcLen, destLen;
1858     int i, j, k;
1859 
1860     log_verbose("\nEntering TestMultipleParagraphs\n\n");
1861     u_unescape(text, src, MAXLEN);
1862     srcSize=u_strlen(src);
1863     ubidi_setPara(pBidi, src, srcSize, UBIDI_LTR, NULL, &errorCode);
1864     if(U_FAILURE(errorCode)){
1865         log_err("ubidi_setPara failed, paraLevel=%d, errorCode %s\n",
1866                 UBIDI_LTR, u_errorName(errorCode));
1867         ubidi_close(pBidi);
1868         return;
1869     }
1870     /* check paragraph count and boundaries */
1871     if (paraCount!=(count=ubidi_countParagraphs(pBidi))) {
1872         log_err("ubidi_countParagraphs returned %d, should be %d\n",
1873                 count, paraCount);
1874     }
1875     for (i=0; i<paraCount; i++) {
1876         ubidi_getParagraphByIndex(pBidi, i, &paraStart, &paraLimit, NULL, &errorCode);
1877         if ((paraStart!=paraBounds[i]) || (paraLimit!=paraBounds[i+1])) {
1878             log_err("Found boundaries of paragraph %d: %d-%d; expected: %d-%d\n",
1879                     i, paraStart, paraLimit, paraBounds[i], paraBounds[i+1]);
1880         }
1881     }
1882     errorCode=U_ZERO_ERROR;
1883     /* check with last paragraph not terminated by B */
1884     src[srcSize-1]='L';
1885     ubidi_setPara(pBidi, src, srcSize, UBIDI_LTR, NULL, &errorCode);
1886     if(U_FAILURE(errorCode)){
1887         log_err("2nd ubidi_setPara failed, paraLevel=%d, errorCode %s\n",
1888                 UBIDI_LTR, u_errorName(errorCode));
1889         ubidi_close(pBidi);
1890         return;
1891     }
1892     if (paraCount!=(count=ubidi_countParagraphs(pBidi))) {
1893         log_err("2nd ubidi_countParagraphs returned %d, should be %d\n",
1894                 count, paraCount);
1895     }
1896     i=paraCount-1;
1897     ubidi_getParagraphByIndex(pBidi, i, &paraStart, &paraLimit, NULL, &errorCode);
1898     if ((paraStart!=paraBounds[i]) || (paraLimit!=paraBounds[i+1])) {
1899         log_err("2nd Found boundaries of paragraph %d: %d-%d; expected: %d-%d\n",
1900                 i, paraStart, paraLimit, paraBounds[i], paraBounds[i+1]);
1901     }
1902     errorCode=U_ZERO_ERROR;
1903     /* check paraLevel for all paragraphs under various paraLevel specs */
1904     for (k=0; k<6; k++) {
1905         ubidi_setPara(pBidi, src, srcSize, paraLevels[k], NULL, &errorCode);
1906         for (i=0; i<paraCount; i++) {
1907             paraIndex=ubidi_getParagraph(pBidi, paraBounds[i], NULL, NULL, &gotLevel, &errorCode);
1908             if (paraIndex!=i) {
1909                 log_err("For paraLevel=%d paragraph=%d, found paragraph index=%d expected=%d\n",
1910                         paraLevels[k], i, paraIndex, i);
1911             }
1912             if (gotLevel!=multiLevels[k][i]) {
1913                 log_err("For paraLevel=%d paragraph=%d, found level=%d expected %d\n",
1914                         paraLevels[k], i, gotLevel, multiLevels[k][i]);
1915             }
1916         }
1917         gotLevel=ubidi_getParaLevel(pBidi);
1918         if (gotLevel!=multiLevels[k][0]) {
1919             log_err("For paraLevel=%d getParaLevel=%d, expected %d\n",
1920                     paraLevels[k], gotLevel, multiLevels[k][0]);
1921         }
1922     }
1923     errorCode=U_ZERO_ERROR;
1924     /* check that the result of ubidi_getParaLevel changes if the first
1925      * paragraph has a different level
1926      */
1927     src[0]=0x05d2;                      /* Hebrew letter Gimel */
1928     ubidi_setPara(pBidi, src, srcSize, UBIDI_DEFAULT_LTR, NULL, &errorCode);
1929     gotLevel=ubidi_getParaLevel(pBidi);
1930     if (gotLevel!=UBIDI_RTL) {
1931         log_err("For paraLevel=UBIDI_DEFAULT_LTR getParaLevel=%d, expected=%d\n",
1932                         gotLevel, UBIDI_RTL);
1933     }
1934     errorCode=U_ZERO_ERROR;
1935     /* check that line cannot overlap paragraph boundaries */
1936     pLine=ubidi_open();
1937     i=paraBounds[1];
1938     k=paraBounds[2]+1;
1939     ubidi_setLine(pBidi, i, k, pLine, &errorCode);
1940     if (U_SUCCESS(errorCode)) {
1941         log_err("For line limits %d-%d got success %s\n",
1942                 i, k, u_errorName(errorCode));
1943     }
1944     errorCode=U_ZERO_ERROR;
1945     i=paraBounds[1];
1946     k=paraBounds[2];
1947     ubidi_setLine(pBidi, i, k, pLine, &errorCode);
1948     if (U_FAILURE(errorCode)) {
1949         log_err("For line limits %d-%d got error %s\n",
1950                 i, k, u_errorName(errorCode));
1951         errorCode=U_ZERO_ERROR;
1952     }
1953     /* check level of block separator at end of paragraph when orderParagraphsLTR==FALSE */
1954     ubidi_setPara(pBidi, src, srcSize, UBIDI_RTL, NULL, &errorCode);
1955     /* get levels through para Bidi block */
1956     gotLevels=ubidi_getLevels(pBidi, &errorCode);
1957     if (U_FAILURE(errorCode)) {
1958         log_err("Error on Para getLevels %s\n", u_errorName(errorCode));
1959         ubidi_close(pLine);
1960         ubidi_close(pBidi);
1961         return;
1962     }
1963     for (i=26; i<32; i++) {
1964         if (gotLevels[i]!=UBIDI_RTL) {
1965             log_err("For char %d(%04x), level=%d, expected=%d\n",
1966                     i, src[i], gotLevels[i], UBIDI_RTL);
1967         }
1968     }
1969     /* get levels through para Line block */
1970     i=paraBounds[1];
1971     k=paraBounds[2];
1972     ubidi_setLine(pBidi, i, k, pLine, &errorCode);
1973     if (U_FAILURE(errorCode)) {
1974         log_err("For line limits %d-%d got error %s\n",
1975                 i, k, u_errorName(errorCode));
1976         ubidi_close(pLine);
1977         ubidi_close(pBidi);
1978         return;
1979     }
1980     paraIndex=ubidi_getParagraph(pLine, i, &paraStart, &paraLimit, &gotLevel, &errorCode);
1981     gotLevels=ubidi_getLevels(pLine, &errorCode);
1982     if (U_FAILURE(errorCode)) {
1983         log_err("Error on Line getLevels %s\n", u_errorName(errorCode));
1984         ubidi_close(pLine);
1985         ubidi_close(pBidi);
1986         return;
1987     }
1988     length=ubidi_getLength(pLine);
1989     if ((gotLevel!=UBIDI_RTL) || (gotLevels[length-1]!=UBIDI_RTL)) {
1990         log_err("For paragraph %d with limits %d-%d, paraLevel=%d expected=%d, "
1991                 "level of separator=%d expected=%d\n",
1992                 paraIndex, paraStart, paraLimit, gotLevel, UBIDI_RTL, gotLevels[length-1], UBIDI_RTL);
1993     }
1994     orderParagraphsLTR=ubidi_isOrderParagraphsLTR(pBidi);
1995     if (orderParagraphsLTR) {
1996         log_err("Found orderParagraphsLTR=%d expected=%d\n", orderParagraphsLTR, FALSE);
1997     }
1998     ubidi_orderParagraphsLTR(pBidi, TRUE);
1999     orderParagraphsLTR=ubidi_isOrderParagraphsLTR(pBidi);
2000     if (!orderParagraphsLTR) {
2001         log_err("Found orderParagraphsLTR=%d expected=%d\n", orderParagraphsLTR, TRUE);
2002     }
2003     /* check level of block separator at end of paragraph when orderParagraphsLTR==TRUE */
2004     ubidi_setPara(pBidi, src, srcSize, UBIDI_RTL, NULL, &errorCode);
2005     /* get levels through para Bidi block */
2006     gotLevels=ubidi_getLevels(pBidi, &errorCode);
2007     for (i=26; i<32; i++) {
2008         if (gotLevels[i]!=0) {
2009             log_err("For char %d(%04x), level=%d, expected=%d\n",
2010                     i, src[i], gotLevels[i], 0);
2011         }
2012     }
2013     errorCode=U_ZERO_ERROR;
2014     /* get levels through para Line block */
2015     i=paraBounds[1];
2016     k=paraBounds[2];
2017     ubidi_setLine(pBidi, paraStart, paraLimit, pLine, &errorCode);
2018     paraIndex=ubidi_getParagraph(pLine, i, &paraStart, &paraLimit, &gotLevel, &errorCode);
2019     gotLevels=ubidi_getLevels(pLine, &errorCode);
2020     length=ubidi_getLength(pLine);
2021     if ((gotLevel!=UBIDI_RTL) || (gotLevels[length-1]!=0)) {
2022         log_err("For paragraph %d with limits %d-%d, paraLevel=%d expected=%d, "
2023                 "level of separator=%d expected=%d\n",
2024                 paraIndex, paraStart, paraLimit, gotLevel, UBIDI_RTL, gotLevels[length-1], 0);
2025         log_verbose("levels=");
2026         for (count=0; count<length; count++) {
2027             log_verbose(" %d", gotLevels[count]);
2028         }
2029         log_verbose("\n");
2030     }
2031 
2032     /* test that the concatenation of separate invocations of the bidi code
2033      * on each individual paragraph in order matches the levels array that
2034      * results from invoking bidi once over the entire multiparagraph tests
2035      * (with orderParagraphsLTR false, of course)
2036      */
2037     u_unescape(text, src, MAXLEN);      /* restore original content */
2038     srcSize=u_strlen(src);
2039     ubidi_orderParagraphsLTR(pBidi, FALSE);
2040     ubidi_setPara(pBidi, src, srcSize, UBIDI_DEFAULT_RTL, NULL, &errorCode);
2041     gotLevels=ubidi_getLevels(pBidi, &errorCode);
2042     for (i=0; i<paraCount; i++) {
2043         /* use pLine for individual paragraphs */
2044         paraStart = paraBounds[i];
2045         length = paraBounds[i+1] - paraStart;
2046         ubidi_setPara(pLine, src+paraStart, length, UBIDI_DEFAULT_RTL, NULL, &errorCode);
2047         for (j=0; j<length; j++) {
2048             if ((k=ubidi_getLevelAt(pLine, j)) != (gotLevel=gotLevels[paraStart+j])) {
2049                 log_err("Checking paragraph concatenation: for paragraph=%d, "
2050                         "char=%d(%04x), level=%d, expected=%d\n",
2051                         i, j, src[paraStart+j], k, gotLevel);
2052             }
2053         }
2054     }
2055 
2056     /* ensure that leading numerics in a paragraph are not treated as arabic
2057        numerals because of arabic text in a preceding paragraph
2058      */
2059     u_unescape(text2, src, MAXLEN);
2060     srcSize=u_strlen(src);
2061     ubidi_orderParagraphsLTR(pBidi, TRUE);
2062     ubidi_setPara(pBidi, src, srcSize, UBIDI_RTL, NULL, &errorCode);
2063     gotLevels=ubidi_getLevels(pBidi, &errorCode);
2064     if (U_FAILURE(errorCode)) {
2065         log_err("Can't get levels. %s\n", u_errorName(errorCode));
2066         return;
2067     }
2068     for (i=0; i<srcSize; i++) {
2069         if (gotLevels[i]!=levels2[i]) {
2070             log_err("Checking leading numerics: for char %d(%04x), level=%d, expected=%d\n",
2071                     i, src[i], gotLevels[i], levels2[i]);
2072         }
2073     }
2074 
2075     /* check handling of whitespace before end of paragraph separator when
2076      * orderParagraphsLTR==TRUE, when last paragraph has, and lacks, a terminating B
2077      */
2078     u_memset(src, 0x0020, MAXLEN);
2079     srcSize = 5;
2080     ubidi_orderParagraphsLTR(pBidi, TRUE);
2081     for (i=0x001c; i<=0x0020; i+=(0x0020-0x001c)) {
2082         src[4]=(UChar)i;                /* with and without terminating B */
2083         for (j=0x0041; j<=0x05d0; j+=(0x05d0-0x0041)) {
2084             src[0]=(UChar)j;            /* leading 'A' or Alef */
2085             for (gotLevel=4; gotLevel<=5; gotLevel++) {
2086                 /* test even and odd paraLevel */
2087                 ubidi_setPara(pBidi, src, srcSize, gotLevel, NULL, &errorCode);
2088                 gotLevels=ubidi_getLevels(pBidi, &errorCode);
2089                 for (k=1; k<=3; k++) {
2090                     if (gotLevels[k]!=gotLevel) {
2091                         log_err("Checking trailing spaces: for leading_char=%04x, "
2092                                 "last_char=%04x, index=%d, level=%d, expected=%d\n",
2093                                 src[0], src[4], k, gotLevels[k], gotLevel);
2094                     }
2095                 }
2096             }
2097         }
2098     }
2099 
2100     /* check default orientation when inverse bidi and paragraph starts
2101      * with LTR strong char and ends with RTL strong char, with and without
2102      * a terminating B
2103      */
2104     ubidi_setReorderingMode(pBidi, UBIDI_REORDER_INVERSE_LIKE_DIRECT);
2105     srcLen = u_unescape("abc \\u05d2\\u05d1\n", src, MAXLEN);
2106     ubidi_setPara(pBidi, src, srcLen, UBIDI_DEFAULT_LTR, NULL, &errorCode);
2107     destLen = ubidi_writeReordered(pBidi, dest, MAXLEN, 0, &errorCode);
2108     srcLen = u_unescape("\\u05d1\\u05d2 abc\n", src, MAXLEN);
2109     if (memcmp(src, dest, destLen * sizeof(UChar))) {
2110         log_err("\nInvalid output #0, should be '%s', got '%s'\n",
2111                 aescstrdup(src, srcLen), aescstrdup(dest, destLen));
2112     }
2113     srcLen = u_unescape("abc \\u05d2\\u05d1", src, MAXLEN);
2114     ubidi_setPara(pBidi, src, srcLen, UBIDI_DEFAULT_LTR, NULL, &errorCode);
2115     destLen = ubidi_writeReordered(pBidi, dest, MAXLEN, 0, &errorCode);
2116     srcLen = u_unescape("\\u05d1\\u05d2 abc", src, MAXLEN);
2117     if (memcmp(src, dest, destLen * sizeof(UChar))) {
2118         log_err("\nInvalid output #1, should be '%s', got '%s'\n",
2119                 aescstrdup(src, srcLen), aescstrdup(dest, destLen));
2120     }
2121 
2122     /* check multiple paragraphs together with explicit levels
2123      */
2124     ubidi_setReorderingMode(pBidi, UBIDI_REORDER_DEFAULT);
2125     srcLen = u_unescape("ab\\u05d1\\u05d2\n\\u05d3\\u05d4123", src, MAXLEN);
2126     ubidi_setPara(pBidi, src, srcLen, UBIDI_LTR, myLevels, &errorCode);
2127     destLen = ubidi_writeReordered(pBidi, dest, MAXLEN, 0, &errorCode);
2128     srcLen = u_unescape("ab\\u05d2\\u05d1\\n123\\u05d4\\u05d3", src, MAXLEN);
2129     if (memcmp(src, dest, destLen * sizeof(UChar))) {
2130         log_err("\nInvalid output #2, should be '%s', got '%s'\n",
2131                 aescstrdup(src, srcLen), aescstrdup(dest, destLen));
2132     }
2133     count = ubidi_countParagraphs(pBidi);
2134     if (count != 2) {
2135         log_err("\nInvalid number of paras, should be 2, got %d\n", count);
2136     }
2137 
2138     ubidi_close(pLine);
2139     ubidi_close(pBidi);
2140     log_verbose("\nExiting TestMultipleParagraphs\n\n");
2141 
2142     /* check levels in multiple paragraphs with default para level
2143      */
2144     pBidi = ubidi_open();
2145     errorCode = U_ZERO_ERROR;
2146     ubidi_setPara(pBidi, multiparaTestString, UPRV_LENGTHOF(multiparaTestString),
2147                   UBIDI_DEFAULT_LTR, NULL, &errorCode);
2148     if (U_FAILURE(errorCode)) {
2149         log_err("ubidi_setPara failed for multiparaTestString\n");
2150         ubidi_close(pBidi);
2151         return;
2152     }
2153     gotLevels = ubidi_getLevels(pBidi, &errorCode);
2154     if (U_FAILURE(errorCode)) {
2155         log_err("ubidi_getLevels failed for multiparaTestString\n");
2156         ubidi_close(pBidi);
2157         return;
2158     }
2159     for (i = 0; i < UPRV_LENGTHOF(multiparaTestString); i++) {
2160         if (gotLevels[i] != multiparaTestLevels[i]) {
2161             log_err("Error on level for multiparaTestString at index %d, "
2162                     "expected=%d, actual=%d\n",
2163                     i, multiparaTestLevels[i], gotLevels[i]);
2164         }
2165     }
2166     ubidi_close(pBidi);
2167 
2168 }
2169 
2170 
2171 /* inverse BiDi ------------------------------------------------------------- */
2172 
2173 static int countRoundtrips=0, countNonRoundtrips=0;
2174 
2175 #define STRING_TEST_CASE(s) { (s), UPRV_LENGTHOF(s) }
2176 
2177 static void
testInverse(void)2178 testInverse(void) {
2179     static const UChar
2180         string0[]={ 0x6c, 0x61, 0x28, 0x74, 0x69, 0x6e, 0x20, 0x5d0, 0x5d1, 0x29, 0x5d2, 0x5d3 },
2181         string1[]={ 0x6c, 0x61, 0x74, 0x20, 0x5d0, 0x5d1, 0x5d2, 0x20, 0x31, 0x32, 0x33 },
2182         string2[]={ 0x6c, 0x61, 0x74, 0x20, 0x5d0, 0x28, 0x5d1, 0x5d2, 0x20, 0x31, 0x29, 0x32, 0x33 },
2183         string3[]={ 0x31, 0x32, 0x33, 0x20, 0x5d0, 0x5d1, 0x5d2, 0x20, 0x34, 0x35, 0x36 },
2184         string4[]={ 0x61, 0x62, 0x20, 0x61, 0x62, 0x20, 0x661, 0x662 };
2185 
2186     static const struct {
2187         const UChar *s;
2188         int32_t length;
2189     } testCases[]={
2190         STRING_TEST_CASE(string0),
2191         STRING_TEST_CASE(string1),
2192         STRING_TEST_CASE(string2),
2193         STRING_TEST_CASE(string3),
2194         STRING_TEST_CASE(string4)
2195     };
2196 
2197     UBiDi *pBiDi;
2198     UErrorCode errorCode;
2199     int i;
2200 
2201     log_verbose("\nEntering TestInverse\n\n");
2202     pBiDi=ubidi_open();
2203     if(pBiDi==NULL) {
2204         log_err("unable to open a UBiDi object (out of memory)\n");
2205         return;
2206     }
2207 
2208     log_verbose("inverse Bidi: testInverse(L) with %u test cases ---\n", UPRV_LENGTHOF(testCases));
2209      for(i=0; i<UPRV_LENGTHOF(testCases); ++i) {
2210         log_verbose("Testing case %d\n", i);
2211         errorCode=U_ZERO_ERROR;
2212         _testInverseBidi(pBiDi, testCases[i].s, testCases[i].length, 0, &errorCode);
2213     }
2214 
2215     log_verbose("inverse Bidi: testInverse(R) with %u test cases ---\n", UPRV_LENGTHOF(testCases));
2216     for(i=0; i<UPRV_LENGTHOF(testCases); ++i) {
2217         log_verbose("Testing case %d\n", i);
2218         errorCode=U_ZERO_ERROR;
2219         _testInverseBidi(pBiDi, testCases[i].s, testCases[i].length, 1, &errorCode);
2220     }
2221 
2222     _testManyInverseBidi(pBiDi, 0);
2223     _testManyInverseBidi(pBiDi, 1);
2224 
2225     ubidi_close(pBiDi);
2226 
2227     log_verbose("inverse Bidi: roundtrips: %5u\nnon-roundtrips: %5u\n", countRoundtrips, countNonRoundtrips);
2228 
2229     _testWriteReverse();
2230 
2231     _testManyAddedPoints();
2232 
2233     _testMisc();
2234 
2235     log_verbose("\nExiting TestInverse\n\n");
2236 }
2237 
2238 #define COUNT_REPEAT_SEGMENTS 6
2239 
2240 static const UChar repeatSegments[COUNT_REPEAT_SEGMENTS][2]={
2241     { 0x61, 0x62 },     /* L */
2242     { 0x5d0, 0x5d1 },   /* R */
2243     { 0x627, 0x628 },   /* AL */
2244     { 0x31, 0x32 },     /* EN */
2245     { 0x661, 0x662 },   /* AN */
2246     { 0x20, 0x20 }      /* WS (N) */
2247 };
2248 
2249 static void
_testManyInverseBidi(UBiDi * pBiDi,UBiDiLevel direction)2250 _testManyInverseBidi(UBiDi *pBiDi, UBiDiLevel direction) {
2251     UChar text[8]={ 0, 0, 0x20, 0, 0, 0x20, 0, 0 };
2252     int i, j, k;
2253     UErrorCode errorCode;
2254 
2255     log_verbose("inverse Bidi: testManyInverseBidi(%c) - test permutations of text snippets ---\n",
2256                  direction==0 ? 'L' : 'R');
2257     for(i=0; i<COUNT_REPEAT_SEGMENTS; ++i) {
2258         text[0]=repeatSegments[i][0];
2259         text[1]=repeatSegments[i][1];
2260         for(j=0; j<COUNT_REPEAT_SEGMENTS; ++j) {
2261             text[3]=repeatSegments[j][0];
2262             text[4]=repeatSegments[j][1];
2263             for(k=0; k<COUNT_REPEAT_SEGMENTS; ++k) {
2264                 text[6]=repeatSegments[k][0];
2265                 text[7]=repeatSegments[k][1];
2266 
2267                 errorCode=U_ZERO_ERROR;
2268                 log_verbose("inverse Bidi: testManyInverseBidi()[%u %u %u]\n", i, j, k);
2269                 _testInverseBidi(pBiDi, text, 8, direction, &errorCode);
2270             }
2271         }
2272     }
2273 }
2274 
2275 static void
_testInverseBidi(UBiDi * pBiDi,const UChar * src,int32_t srcLength,UBiDiLevel direction,UErrorCode * pErrorCode)2276 _testInverseBidi(UBiDi *pBiDi, const UChar *src, int32_t srcLength,
2277                 UBiDiLevel direction, UErrorCode *pErrorCode) {
2278     UChar visualLTR[MAXLEN], logicalDest[MAXLEN], visualDest[MAXLEN];
2279     int32_t ltrLength, logicalLength, visualLength;
2280 
2281     if(direction==0) {
2282         log_verbose("inverse Bidi: testInverse(L)\n");
2283 
2284         /* convert visual to logical */
2285         ubidi_setInverse(pBiDi, TRUE);
2286         if (!ubidi_isInverse(pBiDi)) {
2287             log_err("Error while doing ubidi_setInverse(TRUE)\n");
2288         }
2289         ubidi_setPara(pBiDi, src, srcLength, 0, NULL, pErrorCode);
2290         if (src != ubidi_getText(pBiDi)) {
2291             log_err("Wrong value returned by ubidi_getText\n");
2292         }
2293         logicalLength=ubidi_writeReordered(pBiDi, logicalDest, UPRV_LENGTHOF(logicalDest),
2294                                            UBIDI_DO_MIRRORING|UBIDI_INSERT_LRM_FOR_NUMERIC, pErrorCode);
2295         log_verbose("  v ");
2296         printUnicode(src, srcLength, ubidi_getLevels(pBiDi, pErrorCode));
2297         log_verbose("\n");
2298 
2299         /* convert back to visual LTR */
2300         ubidi_setInverse(pBiDi, FALSE);
2301         if (ubidi_isInverse(pBiDi)) {
2302             log_err("Error while doing ubidi_setInverse(FALSE)\n");
2303         }
2304         ubidi_setPara(pBiDi, logicalDest, logicalLength, 0, NULL, pErrorCode);
2305         visualLength=ubidi_writeReordered(pBiDi, visualDest, UPRV_LENGTHOF(visualDest),
2306                                           UBIDI_DO_MIRRORING|UBIDI_REMOVE_BIDI_CONTROLS, pErrorCode);
2307     } else {
2308         log_verbose("inverse Bidi: testInverse(R)\n");
2309 
2310         /* reverse visual from RTL to LTR */
2311         ltrLength=ubidi_writeReverse(src, srcLength, visualLTR, UPRV_LENGTHOF(visualLTR), 0, pErrorCode);
2312         log_verbose("  vr");
2313         printUnicode(src, srcLength, NULL);
2314         log_verbose("\n");
2315 
2316         /* convert visual RTL to logical */
2317         ubidi_setInverse(pBiDi, TRUE);
2318         ubidi_setPara(pBiDi, visualLTR, ltrLength, 0, NULL, pErrorCode);
2319         logicalLength=ubidi_writeReordered(pBiDi, logicalDest, UPRV_LENGTHOF(logicalDest),
2320                                            UBIDI_DO_MIRRORING|UBIDI_INSERT_LRM_FOR_NUMERIC, pErrorCode);
2321         log_verbose("  vl");
2322         printUnicode(visualLTR, ltrLength, ubidi_getLevels(pBiDi, pErrorCode));
2323         log_verbose("\n");
2324 
2325         /* convert back to visual RTL */
2326         ubidi_setInverse(pBiDi, FALSE);
2327         ubidi_setPara(pBiDi, logicalDest, logicalLength, 0, NULL, pErrorCode);
2328         visualLength=ubidi_writeReordered(pBiDi, visualDest, UPRV_LENGTHOF(visualDest),
2329                                           UBIDI_DO_MIRRORING|UBIDI_REMOVE_BIDI_CONTROLS|UBIDI_OUTPUT_REVERSE, pErrorCode);
2330     }
2331     log_verbose("  l ");
2332     printUnicode(logicalDest, logicalLength, ubidi_getLevels(pBiDi, pErrorCode));
2333     log_verbose("\n");
2334     log_verbose("  v ");
2335     printUnicode(visualDest, visualLength, NULL);
2336     log_verbose("\n");
2337 
2338     /* check and print results */
2339     if(U_FAILURE(*pErrorCode)) {
2340         log_err("inverse BiDi: *** error %s\n"
2341                 "                 turn on verbose mode to see details\n", u_errorName(*pErrorCode));
2342     } else if(srcLength==visualLength && memcmp(src, visualDest, srcLength*U_SIZEOF_UCHAR)==0) {
2343         ++countRoundtrips;
2344         log_verbose(" + roundtripped\n");
2345     } else {
2346         ++countNonRoundtrips;
2347         log_verbose(" * did not roundtrip\n");
2348         log_err("inverse BiDi: transformation visual->logical->visual did not roundtrip the text;\n"
2349                 "                 turn on verbose mode to see details\n");
2350     }
2351 }
2352 
2353 static void
_testWriteReverse(void)2354 _testWriteReverse(void) {
2355     /* U+064e and U+0650 are combining marks (Mn) */
2356     static const UChar forward[]={
2357         0x200f, 0x627, 0x64e, 0x650, 0x20, 0x28, 0x31, 0x29
2358     }, reverseKeepCombining[]={
2359         0x29, 0x31, 0x28, 0x20, 0x627, 0x64e, 0x650, 0x200f
2360     }, reverseRemoveControlsKeepCombiningDoMirror[]={
2361         0x28, 0x31, 0x29, 0x20, 0x627, 0x64e, 0x650
2362     };
2363     UChar reverse[10];
2364     UErrorCode errorCode;
2365     int32_t length;
2366 
2367     /* test ubidi_writeReverse() with "interesting" options */
2368     errorCode=U_ZERO_ERROR;
2369     length=ubidi_writeReverse(forward, UPRV_LENGTHOF(forward),
2370                               reverse, UPRV_LENGTHOF(reverse),
2371                               UBIDI_KEEP_BASE_COMBINING,
2372                               &errorCode);
2373     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(reverseKeepCombining) || memcmp(reverse, reverseKeepCombining, length*U_SIZEOF_UCHAR)!=0) {
2374         log_err("failure in ubidi_writeReverse(UBIDI_KEEP_BASE_COMBINING): length=%d (should be %d), error code %s\n",
2375                 length, UPRV_LENGTHOF(reverseKeepCombining), u_errorName(errorCode));
2376     }
2377 
2378     memset(reverse, 0xa5, UPRV_LENGTHOF(reverse)*U_SIZEOF_UCHAR);
2379     errorCode=U_ZERO_ERROR;
2380     length=ubidi_writeReverse(forward, UPRV_LENGTHOF(forward),
2381                               reverse, UPRV_LENGTHOF(reverse),
2382                               UBIDI_REMOVE_BIDI_CONTROLS|UBIDI_DO_MIRRORING|UBIDI_KEEP_BASE_COMBINING,
2383                               &errorCode);
2384     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(reverseRemoveControlsKeepCombiningDoMirror) || memcmp(reverse, reverseRemoveControlsKeepCombiningDoMirror, length*U_SIZEOF_UCHAR)!=0) {
2385         log_err("failure in ubidi_writeReverse(UBIDI_REMOVE_BIDI_CONTROLS|UBIDI_DO_MIRRORING|UBIDI_KEEP_BASE_COMBINING):\n"
2386                 "    length=%d (should be %d), error code %s\n",
2387                 length, UPRV_LENGTHOF(reverseRemoveControlsKeepCombiningDoMirror), u_errorName(errorCode));
2388     }
2389 }
2390 
_testManyAddedPoints(void)2391 static void _testManyAddedPoints(void) {
2392     UErrorCode errorCode = U_ZERO_ERROR;
2393     UBiDi *bidi = ubidi_open();
2394     UChar text[90], dest[MAXLEN], expected[120];
2395     int destLen, i;
2396     for (i = 0; i < UPRV_LENGTHOF(text); i+=3) {
2397         text[i] = 0x0061; /* 'a' */
2398         text[i+1] = 0x05d0;
2399         text[i+2] = 0x0033; /* '3' */
2400     }
2401     ubidi_setReorderingMode(bidi, UBIDI_REORDER_INVERSE_LIKE_DIRECT);
2402     ubidi_setReorderingOptions(bidi, UBIDI_OPTION_INSERT_MARKS);
2403     ubidi_setPara(bidi, text, UPRV_LENGTHOF(text), UBIDI_LTR, NULL, &errorCode);
2404     destLen = ubidi_writeReordered(bidi, dest, MAXLEN, 0, &errorCode);
2405     for (i = 0; i < UPRV_LENGTHOF(expected); i+=4) {
2406         expected[i] = 0x0061; /* 'a' */
2407         expected[i+1] = 0x05d0;
2408         expected[i+2] = 0x200e;
2409         expected[i+3] = 0x0033; /* '3' */
2410     }
2411     if (memcmp(dest, expected, destLen * sizeof(UChar))) {
2412         log_err("\nInvalid output with many added points, "
2413                 "expected '%s', got '%s'\n",
2414                 aescstrdup(expected, UPRV_LENGTHOF(expected)),
2415                 aescstrdup(dest, destLen));
2416     }
2417     ubidi_close(bidi);
2418 }
2419 
_testMisc(void)2420 static void _testMisc(void) {
2421     UErrorCode errorCode = U_ZERO_ERROR;
2422     UBiDi *bidi = ubidi_open();
2423     UChar src[3], dest[MAXLEN], expected[5];
2424     int destLen;
2425     ubidi_setInverse(bidi, TRUE);
2426     src[0] = src[1] = src[2] = 0x0020;
2427     ubidi_setPara(bidi, src, UPRV_LENGTHOF(src), UBIDI_RTL, NULL, &errorCode);
2428     destLen = ubidi_writeReordered(bidi, dest, MAXLEN,
2429               UBIDI_OUTPUT_REVERSE | UBIDI_INSERT_LRM_FOR_NUMERIC,
2430               &errorCode);
2431     u_unescape("\\u200f   \\u200f", expected, 5);
2432     if (memcmp(dest, expected, destLen * sizeof(UChar))) {
2433         log_err("\nInvalid output with RLM at both sides, "
2434                 "expected '%s', got '%s'\n",
2435                 aescstrdup(expected, UPRV_LENGTHOF(expected)),
2436                 aescstrdup(dest, destLen));
2437     }
2438     ubidi_close(bidi);
2439 }
2440 
2441 /* arabic shaping ----------------------------------------------------------- */
2442 
2443 static void
doArabicShapingTest(void)2444 doArabicShapingTest(void) {
2445     static const UChar
2446     source[]={
2447         0x31,   /* en:1 */
2448         0x627,  /* arabic:alef */
2449         0x32,   /* en:2 */
2450         0x6f3,  /* an:3 */
2451         0x61,   /* latin:a */
2452         0x34,   /* en:4 */
2453         0
2454     }, en2an[]={
2455         0x661, 0x627, 0x662, 0x6f3, 0x61, 0x664, 0
2456     }, an2en[]={
2457         0x31, 0x627, 0x32, 0x33, 0x61, 0x34, 0
2458     }, logical_alen2an_init_lr[]={
2459         0x31, 0x627, 0x662, 0x6f3, 0x61, 0x34, 0
2460     }, logical_alen2an_init_al[]={
2461         0x6f1, 0x627, 0x6f2, 0x6f3, 0x61, 0x34, 0
2462     }, reverse_alen2an_init_lr[]={
2463         0x661, 0x627, 0x32, 0x6f3, 0x61, 0x34, 0
2464     }, reverse_alen2an_init_al[]={
2465         0x6f1, 0x627, 0x32, 0x6f3, 0x61, 0x6f4, 0
2466     }, lamalef[]={
2467         0xfefb, 0
2468     };
2469     UChar dest[8];
2470     UErrorCode errorCode;
2471     int32_t length;
2472 
2473     /* test number shaping */
2474 
2475     /* european->arabic */
2476     errorCode=U_ZERO_ERROR;
2477     length=u_shapeArabic(source, UPRV_LENGTHOF(source),
2478                          dest, UPRV_LENGTHOF(dest),
2479                          U_SHAPE_DIGITS_EN2AN|U_SHAPE_DIGIT_TYPE_AN,
2480                          &errorCode);
2481     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(source) || memcmp(dest, en2an, length*U_SIZEOF_UCHAR)!=0) {
2482         log_err("failure in u_shapeArabic(en2an)\n");
2483     }
2484 
2485     /* arabic->european */
2486     errorCode=U_ZERO_ERROR;
2487     length=u_shapeArabic(source, -1,
2488                          dest, UPRV_LENGTHOF(dest),
2489                          U_SHAPE_DIGITS_AN2EN|U_SHAPE_DIGIT_TYPE_AN_EXTENDED,
2490                          &errorCode);
2491     if(U_FAILURE(errorCode) || length!=u_strlen(source) || memcmp(dest, an2en, length*U_SIZEOF_UCHAR)!=0) {
2492         log_err("failure in u_shapeArabic(an2en)\n");
2493     }
2494 
2495     /* european->arabic with context, logical order, initial state not AL */
2496     errorCode=U_ZERO_ERROR;
2497     length=u_shapeArabic(source, UPRV_LENGTHOF(source),
2498                          dest, UPRV_LENGTHOF(dest),
2499                          U_SHAPE_DIGITS_ALEN2AN_INIT_LR|U_SHAPE_DIGIT_TYPE_AN,
2500                          &errorCode);
2501     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(source) || memcmp(dest, logical_alen2an_init_lr, length*U_SIZEOF_UCHAR)!=0) {
2502         log_err("failure in u_shapeArabic(logical_alen2an_init_lr)\n");
2503     }
2504 
2505     /* european->arabic with context, logical order, initial state AL */
2506     errorCode=U_ZERO_ERROR;
2507     length=u_shapeArabic(source, UPRV_LENGTHOF(source),
2508                          dest, UPRV_LENGTHOF(dest),
2509                          U_SHAPE_DIGITS_ALEN2AN_INIT_AL|U_SHAPE_DIGIT_TYPE_AN_EXTENDED,
2510                          &errorCode);
2511     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(source) || memcmp(dest, logical_alen2an_init_al, length*U_SIZEOF_UCHAR)!=0) {
2512         log_err("failure in u_shapeArabic(logical_alen2an_init_al)\n");
2513     }
2514 
2515     /* european->arabic with context, reverse order, initial state not AL */
2516     errorCode=U_ZERO_ERROR;
2517     length=u_shapeArabic(source, UPRV_LENGTHOF(source),
2518                          dest, UPRV_LENGTHOF(dest),
2519                          U_SHAPE_DIGITS_ALEN2AN_INIT_LR|U_SHAPE_DIGIT_TYPE_AN|U_SHAPE_TEXT_DIRECTION_VISUAL_LTR,
2520                          &errorCode);
2521     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(source) || memcmp(dest, reverse_alen2an_init_lr, length*U_SIZEOF_UCHAR)!=0) {
2522         log_err("failure in u_shapeArabic(reverse_alen2an_init_lr)\n");
2523     }
2524 
2525     /* european->arabic with context, reverse order, initial state AL */
2526     errorCode=U_ZERO_ERROR;
2527     length=u_shapeArabic(source, UPRV_LENGTHOF(source),
2528                          dest, UPRV_LENGTHOF(dest),
2529                          U_SHAPE_DIGITS_ALEN2AN_INIT_AL|U_SHAPE_DIGIT_TYPE_AN_EXTENDED|U_SHAPE_TEXT_DIRECTION_VISUAL_LTR,
2530                          &errorCode);
2531     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(source) || memcmp(dest, reverse_alen2an_init_al, length*U_SIZEOF_UCHAR)!=0) {
2532         log_err("failure in u_shapeArabic(reverse_alen2an_init_al)\n");
2533     }
2534 
2535     /* test noop */
2536     errorCode=U_ZERO_ERROR;
2537     length=u_shapeArabic(source, UPRV_LENGTHOF(source),
2538                          dest, UPRV_LENGTHOF(dest),
2539                          0,
2540                          &errorCode);
2541     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(source) || memcmp(dest, source, length*U_SIZEOF_UCHAR)!=0) {
2542         log_err("failure in u_shapeArabic(noop)\n");
2543     }
2544 
2545     errorCode=U_ZERO_ERROR;
2546     length=u_shapeArabic(source, 0,
2547                          dest, UPRV_LENGTHOF(dest),
2548                          U_SHAPE_DIGITS_EN2AN|U_SHAPE_DIGIT_TYPE_AN,
2549                          &errorCode);
2550     if(U_FAILURE(errorCode) || length!=0) {
2551         log_err("failure in u_shapeArabic(en2an, sourceLength=0), returned %d/%s\n", u_errorName(errorCode), UPRV_LENGTHOF(source));
2552     }
2553 
2554     /* preflight digit shaping */
2555     errorCode=U_ZERO_ERROR;
2556     length=u_shapeArabic(source, UPRV_LENGTHOF(source),
2557                          NULL, 0,
2558                          U_SHAPE_DIGITS_EN2AN|U_SHAPE_DIGIT_TYPE_AN,
2559                          &errorCode);
2560     if(errorCode!=U_BUFFER_OVERFLOW_ERROR || length!=UPRV_LENGTHOF(source)) {
2561         log_err("failure in u_shapeArabic(en2an preflighting), returned %d/%s instead of %d/U_BUFFER_OVERFLOW_ERROR\n",
2562                 length, u_errorName(errorCode), UPRV_LENGTHOF(source));
2563     }
2564 
2565     /* test illegal arguments */
2566     errorCode=U_ZERO_ERROR;
2567     length=u_shapeArabic(NULL, UPRV_LENGTHOF(source),
2568                          dest, UPRV_LENGTHOF(dest),
2569                          U_SHAPE_DIGITS_EN2AN|U_SHAPE_DIGIT_TYPE_AN,
2570                          &errorCode);
2571     if(errorCode!=U_ILLEGAL_ARGUMENT_ERROR) {
2572         log_err("failure in u_shapeArabic(source=NULL), returned %s instead of U_ILLEGAL_ARGUMENT_ERROR\n", u_errorName(errorCode));
2573     }
2574 
2575     errorCode=U_ZERO_ERROR;
2576     length=u_shapeArabic(source, -2,
2577                          dest, UPRV_LENGTHOF(dest),
2578                          U_SHAPE_DIGITS_EN2AN|U_SHAPE_DIGIT_TYPE_AN,
2579                          &errorCode);
2580     if(errorCode!=U_ILLEGAL_ARGUMENT_ERROR) {
2581         log_err("failure in u_shapeArabic(sourceLength=-2), returned %s instead of U_ILLEGAL_ARGUMENT_ERROR\n", u_errorName(errorCode));
2582     }
2583 
2584     errorCode=U_ZERO_ERROR;
2585     length=u_shapeArabic(source, UPRV_LENGTHOF(source),
2586                          NULL, UPRV_LENGTHOF(dest),
2587                          U_SHAPE_DIGITS_EN2AN|U_SHAPE_DIGIT_TYPE_AN,
2588                          &errorCode);
2589     if(errorCode!=U_ILLEGAL_ARGUMENT_ERROR) {
2590         log_err("failure in u_shapeArabic(dest=NULL), returned %s instead of U_ILLEGAL_ARGUMENT_ERROR\n", u_errorName(errorCode));
2591     }
2592 
2593     errorCode=U_ZERO_ERROR;
2594     length=u_shapeArabic(source, UPRV_LENGTHOF(source),
2595                          dest, -1,
2596                          U_SHAPE_DIGITS_EN2AN|U_SHAPE_DIGIT_TYPE_AN,
2597                          &errorCode);
2598     if(errorCode!=U_ILLEGAL_ARGUMENT_ERROR) {
2599         log_err("failure in u_shapeArabic(destSize=-1), returned %s instead of U_ILLEGAL_ARGUMENT_ERROR\n", u_errorName(errorCode));
2600     }
2601 
2602     errorCode=U_ZERO_ERROR;
2603     length=u_shapeArabic(source, UPRV_LENGTHOF(source),
2604                          dest, UPRV_LENGTHOF(dest),
2605                          U_SHAPE_DIGITS_RESERVED|U_SHAPE_DIGIT_TYPE_AN,
2606                          &errorCode);
2607     if(errorCode!=U_ILLEGAL_ARGUMENT_ERROR) {
2608         log_err("failure in u_shapeArabic(U_SHAPE_DIGITS_RESERVED), returned %s instead of U_ILLEGAL_ARGUMENT_ERROR\n", u_errorName(errorCode));
2609     }
2610 
2611     errorCode=U_ZERO_ERROR;
2612     length=u_shapeArabic(source, UPRV_LENGTHOF(source),
2613                          dest, UPRV_LENGTHOF(dest),
2614                          U_SHAPE_DIGITS_EN2AN|U_SHAPE_DIGIT_TYPE_RESERVED,
2615                          &errorCode);
2616     if(errorCode!=U_ILLEGAL_ARGUMENT_ERROR) {
2617         log_err("failure in u_shapeArabic(U_SHAPE_DIGIT_TYPE_RESERVED), returned %s instead of U_ILLEGAL_ARGUMENT_ERROR\n", u_errorName(errorCode));
2618     }
2619 
2620     errorCode=U_ZERO_ERROR;
2621     length=u_shapeArabic(source, UPRV_LENGTHOF(source),
2622                          (UChar *)(source+2), UPRV_LENGTHOF(dest), /* overlap source and destination */
2623                          U_SHAPE_DIGITS_EN2AN|U_SHAPE_DIGIT_TYPE_AN,
2624                          &errorCode);
2625     if(errorCode!=U_ILLEGAL_ARGUMENT_ERROR) {
2626         log_err("failure in u_shapeArabic(U_SHAPE_DIGIT_TYPE_RESERVED), returned %s instead of U_ILLEGAL_ARGUMENT_ERROR\n", u_errorName(errorCode));
2627     }
2628 
2629     errorCode=U_ZERO_ERROR;
2630     length=u_shapeArabic(lamalef, UPRV_LENGTHOF(lamalef),
2631                          dest, UPRV_LENGTHOF(dest),
2632                          U_SHAPE_LETTERS_UNSHAPE | U_SHAPE_LENGTH_GROW_SHRINK | U_SHAPE_TEXT_DIRECTION_VISUAL_LTR,
2633                          &errorCode);
2634     if(U_FAILURE(errorCode) || length == UPRV_LENGTHOF(lamalef)) {
2635         log_err("failure in u_shapeArabic(U_SHAPE_LETTERS_UNSHAPE | U_SHAPE_LENGTH_GROW_SHRINK | U_SHAPE_TEXT_DIRECTION_VISUAL_LTR)\n");
2636         log_err("returned %s instead of U_ZERO_ERROR or returned length %d instead of 3\n", u_errorName(errorCode), length);
2637     }
2638 }
2639 
2640 static void
doLamAlefSpecialVLTRArabicShapingTest(void)2641 doLamAlefSpecialVLTRArabicShapingTest(void) {
2642     static const UChar
2643     source[]={
2644 /*a*/   0x20 ,0x646,0x622,0x644,0x627,0x20,
2645 /*b*/   0x646,0x623,0x64E,0x644,0x627,0x20,
2646 /*c*/   0x646,0x627,0x670,0x644,0x627,0x20,
2647 /*d*/   0x646,0x622,0x653,0x644,0x627,0x20,
2648 /*e*/   0x646,0x625,0x655,0x644,0x627,0x20,
2649 /*f*/   0x646,0x622,0x654,0x644,0x627,0x20,
2650 /*g*/   0xFEFC,0x639
2651     }, shape_near[]={
2652         0x20,0xfee5,0x20,0xfef5,0xfe8d,0x20,0xfee5,0x20,0xfe76,0xfef7,0xfe8d,0x20,
2653         0xfee5,0x20,0x670,0xfefb,0xfe8d,0x20,0xfee5,0x20,0x653,0xfef5,0xfe8d,0x20,
2654         0xfee5,0x20,0x655,0xfef9,0xfe8d,0x20,0xfee5,0x20,0x654,0xfef5,0xfe8d,0x20,
2655         0xfefc,0xfecb
2656     }, shape_at_end[]={
2657         0x20,0xfee5,0xfef5,0xfe8d,0x20,0xfee5,0xfe76,0xfef7,0xfe8d,0x20,0xfee5,0x670,
2658         0xfefb,0xfe8d,0x20,0xfee5,0x653,0xfef5,0xfe8d,0x20,0xfee5,0x655,0xfef9,0xfe8d,
2659         0x20,0xfee5,0x654,0xfef5,0xfe8d,0x20,0xfefc,0xfecb,0x20,0x20,0x20,0x20,0x20,0x20
2660     }, shape_at_begin[]={
2661         0x20,0x20,0x20,0x20,0x20,0x20,0x20,0xfee5,0xfef5,0xfe8d,0x20,0xfee5,0xfe76,
2662         0xfef7,0xfe8d,0x20,0xfee5,0x670,0xfefb,0xfe8d,0x20,0xfee5,0x653,0xfef5,0xfe8d,
2663         0x20,0xfee5,0x655,0xfef9,0xfe8d,0x20,0xfee5,0x654,0xfef5,0xfe8d,0x20,0xfefc,0xfecb
2664     }, shape_grow_shrink[]={
2665         0x20,0xfee5,0xfef5,0xfe8d,0x20,0xfee5,0xfe76,0xfef7,0xfe8d,0x20,0xfee5,
2666         0x670,0xfefb,0xfe8d,0x20,0xfee5,0x653,0xfef5,0xfe8d,0x20,0xfee5,0x655,0xfef9,
2667         0xfe8d,0x20,0xfee5,0x654,0xfef5,0xfe8d,0x20,0xfefc,0xfecb
2668     }, shape_excepttashkeel_near[]={
2669         0x20,0xfee5,0x20,0xfef5,0xfe8d,0x20,0xfee5,0x20,0xfe76,0xfef7,0xfe8d,0x20,
2670         0xfee5,0x20,0x670,0xfefb,0xfe8d,0x20,0xfee5,0x20,0x653,0xfef5,0xfe8d,0x20,
2671         0xfee5,0x20,0x655,0xfef9,0xfe8d,0x20,0xfee5,0x20,0x654,0xfef5,0xfe8d,0x20,
2672         0xfefc,0xfecb
2673     }, shape_excepttashkeel_at_end[]={
2674         0x20,0xfee5,0xfef5,0xfe8d,0x20,0xfee5,0xfe76,0xfef7,0xfe8d,0x20,0xfee5,
2675         0x670,0xfefb,0xfe8d,0x20,0xfee5,0x653,0xfef5,0xfe8d,0x20,0xfee5,0x655,0xfef9,
2676         0xfe8d,0x20,0xfee5,0x654,0xfef5,0xfe8d,0x20,0xfefc,0xfecb,0x20,0x20,0x20,
2677         0x20,0x20,0x20
2678     }, shape_excepttashkeel_at_begin[]={
2679         0x20,0x20,0x20,0x20,0x20,0x20,0x20,0xfee5,0xfef5,0xfe8d,0x20,0xfee5,0xfe76,
2680         0xfef7,0xfe8d,0x20,0xfee5,0x670,0xfefb,0xfe8d,0x20,0xfee5,0x653,0xfef5,0xfe8d,
2681         0x20,0xfee5,0x655,0xfef9,0xfe8d,0x20,0xfee5,0x654,0xfef5,0xfe8d,0x20,0xfefc,0xfecb
2682     }, shape_excepttashkeel_grow_shrink[]={
2683         0x20,0xfee5,0xfef5,0xfe8d,0x20,0xfee5,0xfe76,0xfef7,0xfe8d,0x20,0xfee5,0x670,
2684         0xfefb,0xfe8d,0x20,0xfee5,0x653,0xfef5,0xfe8d,0x20,0xfee5,0x655,0xfef9,0xfe8d,
2685         0x20,0xfee5,0x654,0xfef5,0xfe8d,0x20,0xfefc,0xfecb
2686     };
2687 
2688     UChar dest[38];
2689     UErrorCode errorCode;
2690     int32_t length;
2691 
2692     errorCode=U_ZERO_ERROR;
2693 
2694     length=u_shapeArabic(source, UPRV_LENGTHOF(source),
2695                          dest, UPRV_LENGTHOF(dest),
2696                          U_SHAPE_LETTERS_SHAPE|U_SHAPE_LENGTH_FIXED_SPACES_NEAR|
2697                          U_SHAPE_TEXT_DIRECTION_VISUAL_LTR,
2698                          &errorCode);
2699 
2700     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(shape_near) || memcmp(dest, shape_near, length*U_SIZEOF_UCHAR)!=0) {
2701         log_err("failure in u_shapeArabic(LAMALEF shape_near)\n");
2702     }
2703 
2704     errorCode=U_ZERO_ERROR;
2705 
2706     length=u_shapeArabic(source, UPRV_LENGTHOF(source),
2707                          dest, UPRV_LENGTHOF(dest),
2708                          U_SHAPE_LETTERS_SHAPE|U_SHAPE_LENGTH_FIXED_SPACES_AT_END|
2709                          U_SHAPE_TEXT_DIRECTION_VISUAL_LTR,
2710                          &errorCode);
2711 
2712     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(shape_at_end) || memcmp(dest, shape_at_end, length*U_SIZEOF_UCHAR)!=0) {
2713         log_err("failure in u_shapeArabic(LAMALEF shape_at_end)\n");
2714     }
2715 
2716     errorCode=U_ZERO_ERROR;
2717 
2718     length=u_shapeArabic(source, UPRV_LENGTHOF(source),
2719                          dest, UPRV_LENGTHOF(dest),
2720                          U_SHAPE_LETTERS_SHAPE|U_SHAPE_LENGTH_FIXED_SPACES_AT_BEGINNING|
2721                          U_SHAPE_TEXT_DIRECTION_VISUAL_LTR,
2722                          &errorCode);
2723 
2724     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(shape_at_begin) || memcmp(dest, shape_at_begin, length*U_SIZEOF_UCHAR)!=0) {
2725         log_err("failure in u_shapeArabic(LAMALEF shape_at_begin)\n");
2726     }
2727 
2728     errorCode=U_ZERO_ERROR;
2729 
2730     length=u_shapeArabic(source, UPRV_LENGTHOF(source),
2731                          dest, UPRV_LENGTHOF(dest),
2732                          U_SHAPE_LETTERS_SHAPE|U_SHAPE_LENGTH_GROW_SHRINK|
2733                          U_SHAPE_TEXT_DIRECTION_VISUAL_LTR,
2734                          &errorCode);
2735 
2736     if(U_FAILURE(errorCode) || memcmp(dest, shape_grow_shrink, length*U_SIZEOF_UCHAR)!=0) {
2737         log_err("failure in u_shapeArabic(LAMALEF shape_grow_shrink)\n");
2738     }
2739 
2740     /* ==================== U_SHAPE_LETTERS_SHAPE_TASHKEEL_ISOLATED ==================== */
2741 
2742     errorCode=U_ZERO_ERROR;
2743 
2744     length=u_shapeArabic(source, UPRV_LENGTHOF(source),
2745                          dest, UPRV_LENGTHOF(dest),
2746                          U_SHAPE_LETTERS_SHAPE_TASHKEEL_ISOLATED|U_SHAPE_LENGTH_FIXED_SPACES_NEAR|
2747                          U_SHAPE_TEXT_DIRECTION_VISUAL_LTR,
2748                          &errorCode);
2749 
2750     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(shape_excepttashkeel_near) || memcmp(dest, shape_excepttashkeel_near, length*U_SIZEOF_UCHAR)!=0) {
2751         log_err("failure in u_shapeArabic(LAMALEF shape_excepttashkeel_near)\n");
2752     }
2753 
2754     errorCode=U_ZERO_ERROR;
2755 
2756     length=u_shapeArabic(source, UPRV_LENGTHOF(source),
2757                          dest, UPRV_LENGTHOF(dest),
2758                          U_SHAPE_LETTERS_SHAPE_TASHKEEL_ISOLATED|U_SHAPE_LENGTH_FIXED_SPACES_AT_END|
2759                          U_SHAPE_TEXT_DIRECTION_VISUAL_LTR,
2760                          &errorCode);
2761 
2762     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(shape_excepttashkeel_at_end) || memcmp(dest,shape_excepttashkeel_at_end , length*U_SIZEOF_UCHAR)!=0) {
2763         log_err("failure in u_shapeArabic(LAMALEF shape_excepttashkeel_at_end)\n");
2764     }
2765 
2766     errorCode=U_ZERO_ERROR;
2767 
2768     length=u_shapeArabic(source, UPRV_LENGTHOF(source),
2769                          dest, UPRV_LENGTHOF(dest),
2770                          U_SHAPE_LETTERS_SHAPE_TASHKEEL_ISOLATED|U_SHAPE_LENGTH_FIXED_SPACES_AT_BEGINNING|
2771                          U_SHAPE_TEXT_DIRECTION_VISUAL_LTR,
2772                          &errorCode);
2773 
2774     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(shape_excepttashkeel_at_begin) || memcmp(dest, shape_excepttashkeel_at_begin, length*U_SIZEOF_UCHAR)!=0) {
2775         log_err("failure in u_shapeArabic(LAMALEF shape_excepttashkeel_at_begin)\n");
2776     }
2777 
2778     errorCode=U_ZERO_ERROR;
2779 
2780     length=u_shapeArabic(source, UPRV_LENGTHOF(source),
2781                          dest, UPRV_LENGTHOF(dest),
2782                          U_SHAPE_LETTERS_SHAPE_TASHKEEL_ISOLATED|U_SHAPE_LENGTH_GROW_SHRINK|
2783                          U_SHAPE_TEXT_DIRECTION_VISUAL_LTR,
2784                          &errorCode);
2785 
2786     if(U_FAILURE(errorCode) || memcmp(dest, shape_excepttashkeel_grow_shrink, length*U_SIZEOF_UCHAR)!=0) {
2787         log_err("failure in u_shapeArabic(LAMALEF shape_excepttashkeel_grow_shrink)\n");
2788     }
2789 }
2790 
2791 static void
doTashkeelSpecialVLTRArabicShapingTest(void)2792 doTashkeelSpecialVLTRArabicShapingTest(void) {
2793     static const UChar
2794     source[]={
2795         0x64A,0x628,0x631,0x639,0x20,
2796         0x64A,0x628,0x651,0x631,0x64E,0x639,0x20,
2797         0x64C,0x64A,0x628,0x631,0x64F,0x639,0x20,
2798         0x628,0x670,0x631,0x670,0x639,0x20,
2799         0x628,0x653,0x631,0x653,0x639,0x20,
2800         0x628,0x654,0x631,0x654,0x639,0x20,
2801         0x628,0x655,0x631,0x655,0x639,0x20,
2802     }, shape_near[]={
2803         0xfef2,0xfe91,0xfeae,0xfecb,0x20,0xfef2,0xfe91,0xfe7c,0xfeae,0xfe77,0xfecb,
2804         0x20,0xfe72,0xfef2,0xfe91,0xfeae,0xfe79,0xfecb,0x20,0xfe8f,0x670,0xfeae,0x670,
2805         0xfecb,0x20,0xfe8f,0x653,0xfeae,0x653,0xfecb,0x20,0xfe8f,0x654,0xfeae,0x654,
2806         0xfecb,0x20,0xfe8f,0x655,0xfeae,0x655,0xfecb,0x20
2807     }, shape_excepttashkeel_near[]={
2808         0xfef2,0xfe91,0xfeae,0xfecb,0x20,0xfef2,0xfe91,0xfe7c,0xfeae,0xfe76,0xfecb,0x20,
2809         0xfe72,0xfef2,0xfe91,0xfeae,0xfe78,0xfecb,0x20,0xfe8f,0x670,0xfeae,0x670,0xfecb,
2810         0x20,0xfe8f,0x653,0xfeae,0x653,0xfecb,0x20,0xfe8f,0x654,0xfeae,0x654,0xfecb,0x20,
2811         0xfe8f,0x655,0xfeae,0x655,0xfecb,0x20
2812     };
2813 
2814     UChar dest[43];
2815     UErrorCode errorCode;
2816     int32_t length;
2817 
2818     errorCode=U_ZERO_ERROR;
2819 
2820     length=u_shapeArabic(source, UPRV_LENGTHOF(source),
2821                          dest, UPRV_LENGTHOF(dest),
2822                          U_SHAPE_LETTERS_SHAPE|U_SHAPE_LENGTH_FIXED_SPACES_NEAR|
2823                          U_SHAPE_TEXT_DIRECTION_VISUAL_LTR,
2824                          &errorCode);
2825 
2826     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(shape_near) || memcmp(dest, shape_near, length*U_SIZEOF_UCHAR)!=0) {
2827         log_err("failure in u_shapeArabic(TASHKEEL shape_near)\n");
2828     }
2829 
2830     errorCode=U_ZERO_ERROR;
2831 
2832     length=u_shapeArabic(source, UPRV_LENGTHOF(source),
2833                          dest, UPRV_LENGTHOF(dest),
2834                          U_SHAPE_LETTERS_SHAPE_TASHKEEL_ISOLATED|U_SHAPE_LENGTH_FIXED_SPACES_NEAR|
2835                          U_SHAPE_TEXT_DIRECTION_VISUAL_LTR,
2836                          &errorCode);
2837 
2838     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(shape_excepttashkeel_near) || memcmp(dest, shape_excepttashkeel_near, length*U_SIZEOF_UCHAR)!=0) {
2839         log_err("failure in u_shapeArabic(TASHKEEL shape_excepttashkeel_near)\n");
2840     }
2841 }
2842 
2843 static void
doLOGICALArabicDeShapingTest(void)2844 doLOGICALArabicDeShapingTest(void) {
2845     static const UChar
2846     source[]={
2847         0x0020,0x0020,0x0020,0xFE8D,0xFEF5,0x0020,0xFEE5,0x0020,0xFE8D,0xFEF7,0x0020,
2848         0xFED7,0xFEFC,0x0020,0xFEE1,0x0020,0xFE8D,0xFEDF,0xFECC,0xFEAE,0xFE91,0xFEF4,
2849         0xFE94,0x0020,0xFE8D,0xFEDF,0xFEA4,0xFEAE,0xFE93,0x0020,0x0020,0x0020,0x0020
2850     }, unshape_near[]={
2851         0x20,0x20,0x20,0x627,0x644,0x622,0x646,0x20,0x627,0x644,0x623,0x642,0x644,0x627,
2852         0x645,0x20,0x627,0x644,0x639,0x631,0x628,0x64a,0x629,0x20,0x627,0x644,0x62d,0x631,
2853         0x629,0x20,0x20,0x20,0x20
2854     }, unshape_at_end[]={
2855         0x20,0x20,0x20,0x627,0x644,0x622,0x20,0x646,0x20,0x627,0x644,0x623,0x20,0x642,
2856         0x644,0x627,0x20,0x645,0x20,0x627,0x644,0x639,0x631,0x628,0x64a,0x629,0x20,0x627,
2857         0x644,0x62d,0x631,0x629,0x20
2858     }, unshape_at_begin[]={
2859         0x627,0x644,0x622,0x20,0x646,0x20,0x627,0x644,0x623,0x20,0x642,0x644,0x627,0x20,
2860         0x645,0x20,0x627,0x644,0x639,0x631,0x628,0x64a,0x629,0x20,0x627,0x644,0x62d,0x631,
2861         0x629,0x20,0x20,0x20,0x20
2862     }, unshape_grow_shrink[]={
2863         0x20,0x20,0x20,0x627,0x644,0x622,0x20,0x646,0x20,0x627,0x644,0x623,0x20,0x642,
2864         0x644,0x627,0x20,0x645,0x20,0x627,0x644,0x639,0x631,0x628,0x64a,0x629,0x20,0x627,
2865         0x644,0x62d,0x631,0x629,0x20,0x20,0x20,0x20
2866     };
2867 
2868     UChar dest[36];
2869     UErrorCode errorCode;
2870     int32_t length;
2871 
2872     errorCode=U_ZERO_ERROR;
2873 
2874     length=u_shapeArabic(source, UPRV_LENGTHOF(source),
2875                          dest, UPRV_LENGTHOF(dest),
2876                          U_SHAPE_LETTERS_UNSHAPE|U_SHAPE_LENGTH_FIXED_SPACES_NEAR|
2877                          U_SHAPE_TEXT_DIRECTION_LOGICAL,
2878                          &errorCode);
2879 
2880     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(unshape_near) || memcmp(dest, unshape_near, length*U_SIZEOF_UCHAR)!=0) {
2881         log_err("failure in u_shapeArabic(unshape_near)\n");
2882     }
2883 
2884     errorCode=U_ZERO_ERROR;
2885 
2886     length=u_shapeArabic(source, UPRV_LENGTHOF(source),
2887                          dest, UPRV_LENGTHOF(dest),
2888                          U_SHAPE_LETTERS_UNSHAPE|U_SHAPE_LENGTH_FIXED_SPACES_AT_END|
2889                          U_SHAPE_TEXT_DIRECTION_LOGICAL,
2890                          &errorCode);
2891 
2892     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(unshape_at_end) || memcmp(dest, unshape_at_end, length*U_SIZEOF_UCHAR)!=0) {
2893         log_err("failure in u_shapeArabic(unshape_at_end)\n");
2894     }
2895 
2896     errorCode=U_ZERO_ERROR;
2897 
2898     length=u_shapeArabic(source, UPRV_LENGTHOF(source),
2899                          dest, UPRV_LENGTHOF(dest),
2900                          U_SHAPE_LETTERS_UNSHAPE|U_SHAPE_LENGTH_FIXED_SPACES_AT_BEGINNING|
2901                          U_SHAPE_TEXT_DIRECTION_LOGICAL,
2902                          &errorCode);
2903 
2904     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(unshape_at_begin) || memcmp(dest, unshape_at_begin, length*U_SIZEOF_UCHAR)!=0) {
2905         log_err("failure in u_shapeArabic(unshape_at_begin)\n");
2906     }
2907 
2908     errorCode=U_ZERO_ERROR;
2909 
2910     length=u_shapeArabic(source, UPRV_LENGTHOF(source),
2911                          dest, UPRV_LENGTHOF(dest),
2912                          U_SHAPE_LETTERS_UNSHAPE|U_SHAPE_LENGTH_GROW_SHRINK|
2913                          U_SHAPE_TEXT_DIRECTION_LOGICAL,
2914                          &errorCode);
2915 
2916     if(U_FAILURE(errorCode) || memcmp(dest, unshape_grow_shrink, length*U_SIZEOF_UCHAR)!=0) {
2917         log_err("failure in u_shapeArabic(unshape_grow_shrink)\n");
2918     }
2919 
2920 }
2921 
2922 static void
doTailTest(void)2923 doTailTest(void) {
2924   static const UChar src[] = { 0x0020, 0x0633, 0 };
2925   static const UChar dst_old[] = { 0xFEB1, 0x200B,0 };
2926   static const UChar dst_new[] = { 0xFEB1, 0xFE73,0 };
2927   UChar dst[3] = { 0x0000, 0x0000,0 };
2928   int32_t length;
2929   UErrorCode status;
2930 
2931   log_verbose("SRC: U+%04X U+%04X\n", src[0],src[1]);
2932 
2933   log_verbose("Trying old tail\n");
2934   status = U_ZERO_ERROR;
2935   length = u_shapeArabic(src, -1, dst, UPRV_LENGTHOF(dst),
2936                          U_SHAPE_LETTERS_SHAPE|U_SHAPE_SEEN_TWOCELL_NEAR, &status);
2937   if(U_FAILURE(status)) {
2938     log_err("Fail: status %s\n", u_errorName(status));
2939   } else if(length!=2) {
2940     log_err("Fail: len %d expected 3\n", length);
2941   } else if(u_strncmp(dst,dst_old,UPRV_LENGTHOF(dst))) {
2942     log_err("Fail: got U+%04X U+%04X expected U+%04X U+%04X\n",
2943             dst[0],dst[1],dst_old[0],dst_old[1]);
2944   } else {
2945     log_verbose("OK:  U+%04X U+%04X len %d err %s\n",
2946             dst[0],dst[1],length,u_errorName(status));
2947   }
2948 
2949 
2950   log_verbose("Trying new tail\n");
2951   status = U_ZERO_ERROR;
2952   length = u_shapeArabic(src, -1, dst, UPRV_LENGTHOF(dst),
2953                          U_SHAPE_LETTERS_SHAPE|U_SHAPE_SEEN_TWOCELL_NEAR|U_SHAPE_TAIL_NEW_UNICODE, &status);
2954   if(U_FAILURE(status)) {
2955     log_err("Fail: status %s\n", u_errorName(status));
2956   } else if(length!=2) {
2957     log_err("Fail: len %d expected 3\n", length);
2958   } else if(u_strncmp(dst,dst_new,UPRV_LENGTHOF(dst))) {
2959     log_err("Fail: got U+%04X U+%04X expected U+%04X U+%04X\n",
2960             dst[0],dst[1],dst_new[0],dst_new[1]);
2961   } else {
2962     log_verbose("OK:  U+%04X U+%04X len %d err %s\n",
2963             dst[0],dst[1],length,u_errorName(status));
2964   }
2965 }
2966 
2967 static void
doArabicShapingTestForBug5421(void)2968 doArabicShapingTestForBug5421(void) {
2969     static const UChar
2970     persian_letters_source[]={
2971         0x0020, 0x0698, 0x067E, 0x0686, 0x06AF, 0x0020
2972     }, persian_letters[]={
2973         0x0020, 0xFB8B, 0xFB59, 0xFB7D, 0xFB94, 0x0020
2974     }, tashkeel_aggregation_source[]={
2975         0x0020, 0x0628, 0x0651, 0x064E, 0x062A, 0x0631, 0x0645, 0x0020,
2976         0x0628, 0x064E, 0x0651, 0x062A, 0x0631, 0x0645, 0x0020
2977     }, tashkeel_aggregation[]={
2978         0x0020, 0xFE90, 0xFC60, 0xFE97, 0xFEAE, 0xFEE3,
2979         0x0020, 0xFE90, 0xFC60, 0xFE97, 0xFEAE, 0xFEE3, 0x0020
2980     }, untouched_presentation_source[]={
2981         0x0020 ,0x0627, 0xfe90,0x0020
2982     }, untouched_presentation[]={
2983         0x0020,0xfe8D, 0xfe90,0x0020
2984     }, untouched_presentation_r_source[]={
2985         0x0020 ,0xfe90, 0x0627, 0x0020
2986     }, untouched_presentation_r[]={
2987         0x0020, 0xfe90,0xfe8D,0x0020
2988     };
2989 
2990     UChar dest[38];
2991     UErrorCode errorCode;
2992     int32_t length;
2993 
2994     errorCode=U_ZERO_ERROR;
2995 
2996     length=u_shapeArabic(persian_letters_source, UPRV_LENGTHOF(persian_letters_source),
2997                          dest, UPRV_LENGTHOF(dest),
2998                          U_SHAPE_LETTERS_SHAPE|U_SHAPE_TEXT_DIRECTION_VISUAL_LTR,
2999                          &errorCode);
3000 
3001     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(persian_letters) || memcmp(dest, persian_letters, length*U_SIZEOF_UCHAR)!=0) {
3002         log_err("failure in u_shapeArabic(persian_letters)\n");
3003     }
3004 
3005     errorCode=U_ZERO_ERROR;
3006 
3007     length=u_shapeArabic(tashkeel_aggregation_source, UPRV_LENGTHOF(tashkeel_aggregation_source),
3008                          dest, UPRV_LENGTHOF(dest),
3009                          U_SHAPE_AGGREGATE_TASHKEEL|U_SHAPE_PRESERVE_PRESENTATION|
3010                          U_SHAPE_LETTERS_SHAPE_TASHKEEL_ISOLATED|U_SHAPE_TEXT_DIRECTION_VISUAL_LTR,
3011                          &errorCode);
3012 
3013     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(tashkeel_aggregation) || memcmp(dest, tashkeel_aggregation, length*U_SIZEOF_UCHAR)!=0) {
3014         log_err("failure in u_shapeArabic(tashkeel_aggregation)\n");
3015     }
3016 
3017     errorCode=U_ZERO_ERROR;
3018 
3019     length=u_shapeArabic(untouched_presentation_source, UPRV_LENGTHOF(untouched_presentation_source),
3020                          dest, UPRV_LENGTHOF(dest),
3021                          U_SHAPE_PRESERVE_PRESENTATION|
3022                          U_SHAPE_LETTERS_SHAPE|U_SHAPE_TEXT_DIRECTION_VISUAL_LTR,
3023                          &errorCode);
3024 
3025     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(untouched_presentation) || memcmp(dest, untouched_presentation, length*U_SIZEOF_UCHAR)!=0) {
3026         log_err("failure in u_shapeArabic(untouched_presentation)\n");
3027     }
3028 
3029     errorCode=U_ZERO_ERROR;
3030 
3031     length=u_shapeArabic(untouched_presentation_r_source, UPRV_LENGTHOF(untouched_presentation_r_source),
3032                          dest, UPRV_LENGTHOF(dest),
3033                          U_SHAPE_PRESERVE_PRESENTATION|
3034                          U_SHAPE_LETTERS_SHAPE|U_SHAPE_TEXT_DIRECTION_LOGICAL,
3035                          &errorCode);
3036 
3037     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(untouched_presentation_r) || memcmp(dest, untouched_presentation_r, length*U_SIZEOF_UCHAR)!=0) {
3038         log_err("failure in u_shapeArabic(untouched_presentation_r)\n");
3039     }
3040 }
3041 
3042 static void
doArabicShapingTestForBug8703(void)3043 doArabicShapingTestForBug8703(void) {
3044     static const UChar
3045     letters_source1[]={
3046         0x0634,0x0651,0x0645,0x0652,0x0633
3047     }, letters_source2[]={
3048         0x0634,0x0651,0x0645,0x0652,0x0633
3049     }, letters_source3[]={
3050        0x0634,0x0651,0x0645,0x0652,0x0633
3051     }, letters_source4[]={
3052         0x0634,0x0651,0x0645,0x0652,0x0633
3053     }, letters_source5[]={
3054         0x0633,0x0652,0x0645,0x0651,0x0634
3055     }, letters_source6[]={
3056         0x0633,0x0652,0x0645,0x0651,0x0634
3057     }, letters_source7[]={
3058         0x0633,0x0652,0x0645,0x0651,0x0634
3059     }, letters_source8[]={
3060         0x0633,0x0652,0x0645,0x0651,0x0634
3061     }, letters_dest1[]={
3062         0x0020,0xFEB7,0xFE7D,0xFEE4,0xFEB2
3063     }, letters_dest2[]={
3064         0xFEB7,0xFE7D,0xFEE4,0xFEB2,0x0020
3065     }, letters_dest3[]={
3066         0xFEB7,0xFE7D,0xFEE4,0xFEB2
3067     }, letters_dest4[]={
3068         0xFEB7,0xFE7D,0xFEE4,0x0640,0xFEB2
3069     }, letters_dest5[]={
3070         0x0020,0xFEB2,0xFEE4,0xFE7D,0xFEB7
3071     }, letters_dest6[]={
3072         0xFEB2,0xFEE4,0xFE7D,0xFEB7,0x0020
3073     }, letters_dest7[]={
3074         0xFEB2,0xFEE4,0xFE7D,0xFEB7
3075     }, letters_dest8[]={
3076         0xFEB2,0x0640,0xFEE4,0xFE7D,0xFEB7
3077     };
3078 
3079     UChar dest[20];
3080     UErrorCode errorCode;
3081     int32_t length;
3082 
3083     errorCode=U_ZERO_ERROR;
3084 
3085     length=u_shapeArabic(letters_source1, UPRV_LENGTHOF(letters_source1),
3086                          dest, UPRV_LENGTHOF(dest),
3087                          U_SHAPE_TEXT_DIRECTION_VISUAL_RTL | U_SHAPE_TASHKEEL_BEGIN | U_SHAPE_LETTERS_SHAPE,
3088                          &errorCode);
3089 
3090     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(letters_dest1) || memcmp(dest, letters_dest1, length*U_SIZEOF_UCHAR)!=0) {
3091         log_err("failure in u_shapeArabic(letters_source1)\n");
3092     }
3093 
3094     errorCode=U_ZERO_ERROR;
3095 
3096     length=u_shapeArabic(letters_source2, UPRV_LENGTHOF(letters_source2),
3097                          dest, UPRV_LENGTHOF(dest),
3098                          U_SHAPE_TEXT_DIRECTION_VISUAL_RTL | U_SHAPE_TASHKEEL_END | U_SHAPE_LETTERS_SHAPE,
3099                          &errorCode);
3100 
3101     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(letters_dest2) || memcmp(dest, letters_dest2, length*U_SIZEOF_UCHAR)!=0) {
3102         log_err("failure in u_shapeArabic(letters_source2)\n");
3103     }
3104 
3105     errorCode=U_ZERO_ERROR;
3106 
3107     length=u_shapeArabic(letters_source3, UPRV_LENGTHOF(letters_source3),
3108                          dest, UPRV_LENGTHOF(dest),
3109                          U_SHAPE_TEXT_DIRECTION_VISUAL_RTL | U_SHAPE_TASHKEEL_RESIZE | U_SHAPE_LETTERS_SHAPE,
3110                          &errorCode);
3111 
3112     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(letters_dest3) || memcmp(dest, letters_dest3, length*U_SIZEOF_UCHAR)!=0) {
3113         log_err("failure in u_shapeArabic(letters_source3)\n");
3114     }
3115 
3116     errorCode=U_ZERO_ERROR;
3117 
3118     length=u_shapeArabic(letters_source4, UPRV_LENGTHOF(letters_source4),
3119                          dest, UPRV_LENGTHOF(dest),
3120                          U_SHAPE_TEXT_DIRECTION_VISUAL_RTL | U_SHAPE_TASHKEEL_REPLACE_BY_TATWEEL | U_SHAPE_LETTERS_SHAPE,
3121                          &errorCode);
3122 
3123     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(letters_dest4) || memcmp(dest, letters_dest4, length*U_SIZEOF_UCHAR)!=0) {
3124         log_err("failure in u_shapeArabic(letters_source4)\n");
3125     }
3126 
3127     errorCode=U_ZERO_ERROR;
3128 
3129     length=u_shapeArabic(letters_source5, UPRV_LENGTHOF(letters_source5),
3130                          dest, UPRV_LENGTHOF(dest),
3131                          U_SHAPE_TEXT_DIRECTION_VISUAL_LTR | U_SHAPE_TASHKEEL_BEGIN | U_SHAPE_LETTERS_SHAPE,
3132                          &errorCode);
3133 
3134     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(letters_dest5) || memcmp(dest, letters_dest5, length*U_SIZEOF_UCHAR)!=0) {
3135         log_err("failure in u_shapeArabic(letters_source5)\n");
3136     }
3137 
3138     errorCode=U_ZERO_ERROR;
3139 
3140     length=u_shapeArabic(letters_source6, UPRV_LENGTHOF(letters_source6),
3141                          dest, UPRV_LENGTHOF(dest),
3142                          U_SHAPE_TEXT_DIRECTION_VISUAL_LTR | U_SHAPE_TASHKEEL_END | U_SHAPE_LETTERS_SHAPE,
3143                          &errorCode);
3144 
3145     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(letters_dest6) || memcmp(dest, letters_dest6, length*U_SIZEOF_UCHAR)!=0) {
3146         log_err("failure in u_shapeArabic(letters_source6)\n");
3147     }
3148 
3149     errorCode=U_ZERO_ERROR;
3150 
3151     length=u_shapeArabic(letters_source7, UPRV_LENGTHOF(letters_source7),
3152                          dest, UPRV_LENGTHOF(dest),
3153                          U_SHAPE_TEXT_DIRECTION_VISUAL_LTR | U_SHAPE_TASHKEEL_RESIZE | U_SHAPE_LETTERS_SHAPE,
3154                          &errorCode);
3155 
3156     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(letters_dest7) || memcmp(dest, letters_dest7, length*U_SIZEOF_UCHAR)!=0) {
3157         log_err("failure in u_shapeArabic(letters_source7)\n");
3158     }
3159 
3160     errorCode=U_ZERO_ERROR;
3161 
3162     length=u_shapeArabic(letters_source8, UPRV_LENGTHOF(letters_source8),
3163                          dest, UPRV_LENGTHOF(dest),
3164                          U_SHAPE_TEXT_DIRECTION_VISUAL_LTR | U_SHAPE_TASHKEEL_REPLACE_BY_TATWEEL | U_SHAPE_LETTERS_SHAPE,
3165                          &errorCode);
3166 
3167     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(letters_dest8) || memcmp(dest, letters_dest8, length*U_SIZEOF_UCHAR)!=0) {
3168         log_err("failure in u_shapeArabic(letters_source8)\n");
3169     }
3170 }
3171 
3172 static void
doArabicShapingTestForBug9024(void)3173 doArabicShapingTestForBug9024(void) {
3174     static const UChar
3175     letters_source1[]={  /* Arabic mathematical Symbols 0x1EE00 - 0x1EE1B */
3176         0xD83B, 0xDE00, 0xD83B, 0xDE01, 0xD83B, 0xDE02, 0xD83B, 0xDE03, 0x20,
3177         0xD83B, 0xDE24, 0xD83B, 0xDE05, 0xD83B, 0xDE06, 0x20,
3178         0xD83B, 0xDE07, 0xD83B, 0xDE08, 0xD83B, 0xDE09, 0x20,
3179         0xD83B, 0xDE0A, 0xD83B, 0xDE0B, 0xD83B, 0xDE0C, 0xD83B, 0xDE0D, 0x20,
3180         0xD83B, 0xDE0E, 0xD83B, 0xDE0F, 0xD83B, 0xDE10, 0xD83B, 0xDE11, 0x20,
3181         0xD83B, 0xDE12, 0xD83B, 0xDE13, 0xD83B, 0xDE14, 0xD83B, 0xDE15, 0x20,
3182         0xD83B, 0xDE16, 0xD83B, 0xDE17, 0xD83B, 0xDE18, 0x20,
3183         0xD83B, 0xDE19, 0xD83B, 0xDE1A, 0xD83B, 0xDE1B
3184     }, letters_source2[]={/* Arabic mathematical Symbols - Looped Symbols, 0x1EE80 - 0x1EE9B */
3185         0xD83B, 0xDE80, 0xD83B, 0xDE81, 0xD83B, 0xDE82, 0xD83B, 0xDE83, 0x20,
3186         0xD83B, 0xDE84, 0xD83B, 0xDE85, 0xD83B, 0xDE86, 0x20,
3187         0xD83B, 0xDE87, 0xD83B, 0xDE88, 0xD83B, 0xDE89, 0x20,
3188         0xD83B, 0xDE8B, 0xD83B, 0xDE8C, 0xD83B, 0xDE8D, 0x20,
3189         0xD83B, 0xDE8E, 0xD83B, 0xDE8F, 0xD83B, 0xDE90, 0xD83B, 0xDE91, 0x20,
3190         0xD83B, 0xDE92, 0xD83B, 0xDE93, 0xD83B, 0xDE94, 0xD83B, 0xDE95, 0x20,
3191         0xD83B, 0xDE96, 0xD83B, 0xDE97, 0xD83B, 0xDE98, 0x20,
3192         0xD83B, 0xDE99, 0xD83B, 0xDE9A, 0xD83B, 0xDE9B
3193     }, letters_source3[]={/* Arabic mathematical Symbols - Double-struck Symbols, 0x1EEA1 - 0x1EEBB */
3194         0xD83B, 0xDEA1, 0xD83B, 0xDEA2, 0xD83B, 0xDEA3, 0x20,
3195         0xD83B, 0xDEA5, 0xD83B, 0xDEA6, 0x20,
3196         0xD83B, 0xDEA7, 0xD83B, 0xDEA8, 0xD83B, 0xDEA9, 0x20,
3197         0xD83B, 0xDEAB, 0xD83B, 0xDEAC, 0xD83B, 0xDEAD, 0x20,
3198         0xD83B, 0xDEAE, 0xD83B, 0xDEAF, 0xD83B, 0xDEB0, 0xD83B, 0xDEB1, 0x20,
3199         0xD83B, 0xDEB2, 0xD83B, 0xDEB3, 0xD83B, 0xDEB4, 0xD83B, 0xDEB5, 0x20,
3200         0xD83B, 0xDEB6, 0xD83B, 0xDEB7, 0xD83B, 0xDEB8, 0x20,
3201         0xD83B, 0xDEB9, 0xD83B, 0xDEBA, 0xD83B, 0xDEBB
3202     }, letters_source4[]={/* Arabic mathematical Symbols - Initial Symbols, 0x1EE21 - 0x1EE3B */
3203         0xD83B, 0xDE21, 0xD83B, 0xDE22, 0x20,
3204         0xD83B, 0xDE27, 0xD83B, 0xDE29, 0x20,
3205         0xD83B, 0xDE2A, 0xD83B, 0xDE2B, 0xD83B, 0xDE2C, 0xD83B, 0xDE2D, 0x20,
3206         0xD83B, 0xDE2E, 0xD83B, 0xDE2F, 0xD83B, 0xDE30, 0xD83B, 0xDE31, 0x20,
3207         0xD83B, 0xDE32, 0xD83B, 0xDE34, 0xD83B, 0xDE35, 0x20,
3208         0xD83B, 0xDE36, 0xD83B, 0xDE37, 0x20,
3209         0xD83B, 0xDE39, 0xD83B, 0xDE3B
3210     }, letters_source5[]={/* Arabic mathematical Symbols - Tailed Symbols */
3211         0xD83B, 0xDE42, 0xD83B, 0xDE47, 0xD83B, 0xDE49, 0xD83B, 0xDE4B, 0x20,
3212         0xD83B, 0xDE4D, 0xD83B, 0xDE4E, 0xD83B, 0xDE4F, 0x20,
3213         0xD83B, 0xDE51, 0xD83B, 0xDE52, 0xD83B, 0xDE54, 0xD83B, 0xDE57, 0x20,
3214         0xD83B, 0xDE59, 0xD83B, 0xDE5B, 0xD83B, 0xDE5D, 0xD83B, 0xDE5F
3215     }, letters_source6[]={/* Arabic mathematical Symbols - Stretched Symbols with 06 range */
3216         0xD83B, 0xDE21, 0x0633, 0xD83B, 0xDE62, 0x0647
3217     }, letters_dest1[]={
3218         0xD83B, 0xDE00, 0xD83B, 0xDE01, 0xD83B, 0xDE02, 0xD83B, 0xDE03, 0x20,
3219         0xD83B, 0xDE24, 0xD83B, 0xDE05, 0xD83B, 0xDE06, 0x20,
3220         0xD83B, 0xDE07, 0xD83B, 0xDE08, 0xD83B, 0xDE09, 0x20,
3221         0xD83B, 0xDE0A, 0xD83B, 0xDE0B, 0xD83B, 0xDE0C, 0xD83B, 0xDE0D, 0x20,
3222         0xD83B, 0xDE0E, 0xD83B, 0xDE0F, 0xD83B, 0xDE10, 0xD83B, 0xDE11, 0x20,
3223         0xD83B, 0xDE12, 0xD83B, 0xDE13, 0xD83B, 0xDE14, 0xD83B, 0xDE15, 0x20,
3224         0xD83B, 0xDE16, 0xD83B, 0xDE17, 0xD83B, 0xDE18, 0x20,
3225         0xD83B, 0xDE19, 0xD83B, 0xDE1A, 0xD83B, 0xDE1B
3226     }, letters_dest2[]={
3227         0xD83B, 0xDE80, 0xD83B, 0xDE81, 0xD83B, 0xDE82, 0xD83B, 0xDE83, 0x20,
3228         0xD83B, 0xDE84, 0xD83B, 0xDE85, 0xD83B, 0xDE86, 0x20,
3229         0xD83B, 0xDE87, 0xD83B, 0xDE88, 0xD83B, 0xDE89, 0x20,
3230         0xD83B, 0xDE8B, 0xD83B, 0xDE8C, 0xD83B, 0xDE8D, 0x20,
3231         0xD83B, 0xDE8E, 0xD83B, 0xDE8F, 0xD83B, 0xDE90, 0xD83B, 0xDE91, 0x20,
3232         0xD83B, 0xDE92, 0xD83B, 0xDE93, 0xD83B, 0xDE94, 0xD83B, 0xDE95, 0x20,
3233         0xD83B, 0xDE96, 0xD83B, 0xDE97, 0xD83B, 0xDE98, 0x20,
3234         0xD83B, 0xDE99, 0xD83B, 0xDE9A, 0xD83B, 0xDE9B
3235     }, letters_dest3[]={
3236         0xD83B, 0xDEA1, 0xD83B, 0xDEA2, 0xD83B, 0xDEA3, 0x20,
3237         0xD83B, 0xDEA5, 0xD83B, 0xDEA6, 0x20,
3238         0xD83B, 0xDEA7, 0xD83B, 0xDEA8, 0xD83B, 0xDEA9, 0x20,
3239         0xD83B, 0xDEAB, 0xD83B, 0xDEAC, 0xD83B, 0xDEAD, 0x20,
3240         0xD83B, 0xDEAE, 0xD83B, 0xDEAF, 0xD83B, 0xDEB0, 0xD83B, 0xDEB1, 0x20,
3241         0xD83B, 0xDEB2, 0xD83B, 0xDEB3, 0xD83B, 0xDEB4, 0xD83B, 0xDEB5, 0x20,
3242         0xD83B, 0xDEB6, 0xD83B, 0xDEB7, 0xD83B, 0xDEB8, 0x20,
3243         0xD83B, 0xDEB9, 0xD83B, 0xDEBA, 0xD83B, 0xDEBB
3244     }, letters_dest4[]={
3245         0xD83B, 0xDE21, 0xD83B, 0xDE22, 0x20,
3246         0xD83B, 0xDE27, 0xD83B, 0xDE29, 0x20,
3247         0xD83B, 0xDE2A, 0xD83B, 0xDE2B, 0xD83B, 0xDE2C, 0xD83B, 0xDE2D, 0x20,
3248         0xD83B, 0xDE2E, 0xD83B, 0xDE2F, 0xD83B, 0xDE30, 0xD83B, 0xDE31, 0x20,
3249         0xD83B, 0xDE32, 0xD83B, 0xDE34, 0xD83B, 0xDE35, 0x20,
3250         0xD83B, 0xDE36, 0xD83B, 0xDE37, 0x20,
3251         0xD83B, 0xDE39, 0xD83B, 0xDE3B
3252     }, letters_dest5[]={
3253         0xD83B, 0xDE42, 0xD83B, 0xDE47, 0xD83B, 0xDE49, 0xD83B, 0xDE4B, 0x20,
3254         0xD83B, 0xDE4D, 0xD83B, 0xDE4E, 0xD83B, 0xDE4F, 0x20,
3255         0xD83B, 0xDE51, 0xD83B, 0xDE52, 0xD83B, 0xDE54, 0xD83B, 0xDE57, 0x20,
3256         0xD83B, 0xDE59, 0xD83B, 0xDE5B, 0xD83B, 0xDE5D, 0xD83B, 0xDE5F
3257     }, letters_dest6[]={
3258         0xD83B, 0xDE21, 0xFEB1, 0xD83B, 0xDE62, 0xFEE9
3259     };
3260 
3261     UChar dest[MAXLEN];
3262     UErrorCode errorCode;
3263     int32_t length;
3264 
3265     errorCode=U_ZERO_ERROR;
3266 
3267     length=u_shapeArabic(letters_source1, UPRV_LENGTHOF(letters_source1),
3268                          dest, UPRV_LENGTHOF(dest),
3269                          U_SHAPE_TEXT_DIRECTION_VISUAL_RTL | U_SHAPE_TASHKEEL_BEGIN | U_SHAPE_LETTERS_SHAPE,
3270                          &errorCode);
3271 
3272     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(letters_dest1) || memcmp(dest, letters_dest1, length*U_SIZEOF_UCHAR)!=0) {
3273         log_err("failure in u_shapeArabic(letters_source1)\n");
3274     }
3275 
3276     errorCode=U_ZERO_ERROR;
3277 
3278     length=u_shapeArabic(letters_source2, UPRV_LENGTHOF(letters_source2),
3279                          dest, UPRV_LENGTHOF(dest),
3280                          U_SHAPE_TEXT_DIRECTION_VISUAL_RTL | U_SHAPE_TASHKEEL_END | U_SHAPE_LETTERS_SHAPE,
3281                          &errorCode);
3282 
3283     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(letters_dest2) || memcmp(dest, letters_dest2, length*U_SIZEOF_UCHAR)!=0) {
3284         log_err("failure in u_shapeArabic(letters_source2)\n");
3285     }
3286 
3287     errorCode=U_ZERO_ERROR;
3288 
3289     length=u_shapeArabic(letters_source3, UPRV_LENGTHOF(letters_source3),
3290                          dest, UPRV_LENGTHOF(dest),
3291                          U_SHAPE_TEXT_DIRECTION_VISUAL_RTL | U_SHAPE_TASHKEEL_RESIZE | U_SHAPE_LETTERS_SHAPE,
3292                          &errorCode);
3293 
3294     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(letters_dest3) || memcmp(dest, letters_dest3, length*U_SIZEOF_UCHAR)!=0) {
3295         log_err("failure in u_shapeArabic(letters_source3)\n");
3296     }
3297 
3298     errorCode=U_ZERO_ERROR;
3299 
3300     length=u_shapeArabic(letters_source4, UPRV_LENGTHOF(letters_source4),
3301                          dest, UPRV_LENGTHOF(dest),
3302                          U_SHAPE_TEXT_DIRECTION_VISUAL_RTL | U_SHAPE_TASHKEEL_REPLACE_BY_TATWEEL | U_SHAPE_LETTERS_SHAPE,
3303                          &errorCode);
3304 
3305     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(letters_dest4) || memcmp(dest, letters_dest4, length*U_SIZEOF_UCHAR)!=0) {
3306         log_err("failure in u_shapeArabic(letters_source4)\n");
3307     }
3308 
3309     errorCode=U_ZERO_ERROR;
3310 
3311     length=u_shapeArabic(letters_source5, UPRV_LENGTHOF(letters_source5),
3312                          dest, UPRV_LENGTHOF(dest),
3313                          U_SHAPE_TEXT_DIRECTION_VISUAL_LTR | U_SHAPE_TASHKEEL_BEGIN | U_SHAPE_LETTERS_SHAPE,
3314                          &errorCode);
3315 
3316     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(letters_dest5) || memcmp(dest, letters_dest5, length*U_SIZEOF_UCHAR)!=0) {
3317         log_err("failure in u_shapeArabic(letters_source5)\n");
3318     }
3319 
3320     errorCode=U_ZERO_ERROR;
3321 
3322     length=u_shapeArabic(letters_source6, UPRV_LENGTHOF(letters_source6),
3323                          dest, UPRV_LENGTHOF(dest),
3324                          U_SHAPE_TEXT_DIRECTION_VISUAL_LTR | U_SHAPE_TASHKEEL_END | U_SHAPE_LETTERS_SHAPE,
3325                          &errorCode);
3326 
3327     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(letters_dest6) || memcmp(dest, letters_dest6, length*U_SIZEOF_UCHAR)!=0) {
3328         log_err("failure in u_shapeArabic(letters_source6)\n");
3329     }
3330 
3331 }
3332 
_testPresentationForms(const UChar * in)3333 static void _testPresentationForms(const UChar* in) {
3334   enum Forms { GENERIC, ISOLATED, FINAL, INITIAL, MEDIAL };
3335   /* This character is used to check whether the in-character is rewritten correctly
3336      and whether the surrounding characters are shaped correctly as well. */
3337   UChar otherChar[] = {0x0628, 0xfe8f, 0xfe90, 0xfe91, 0xfe92};
3338   UChar src[3];
3339   UChar dst[3];
3340   UErrorCode errorCode;
3341   int32_t length;
3342 
3343   /* Testing isolated shaping */
3344   src[0] = in[GENERIC];
3345   errorCode=U_ZERO_ERROR;
3346   length=u_shapeArabic(src, 1,
3347                        dst, 1,
3348                        U_SHAPE_LETTERS_SHAPE,
3349                        &errorCode);
3350   if(U_FAILURE(errorCode) || length!=1 || dst[0] != in[ISOLATED]) {
3351       log_err("failure in u_shapeArabic(_testAllForms: shaping isolated): %x\n", in[GENERIC]);
3352   }
3353   errorCode=U_ZERO_ERROR;
3354   length=u_shapeArabic(dst, 1,
3355                        src, 1,
3356                        U_SHAPE_LETTERS_UNSHAPE,
3357                        &errorCode);
3358   if(U_FAILURE(errorCode) || length!=1 || src[0] != in[GENERIC]) {
3359       log_err("failure in u_shapeArabic(_testAllForms: unshaping isolated): %x\n", in[GENERIC]);
3360   }
3361 
3362   /* Testing final shaping */
3363   src[0] = otherChar[GENERIC];
3364   src[1] = in[GENERIC];
3365   if (in[FINAL] != 0) {
3366     errorCode=U_ZERO_ERROR;
3367     length=u_shapeArabic(src, 2,
3368                          dst, 2,
3369                          U_SHAPE_LETTERS_SHAPE,
3370                          &errorCode);
3371     if(U_FAILURE(errorCode) || length!=2 || dst[0] != otherChar[INITIAL] || dst[1] != in[FINAL]) {
3372       log_err("failure in u_shapeArabic(_testAllForms: shaping final): %x\n", in[GENERIC]);
3373     }
3374     errorCode=U_ZERO_ERROR;
3375     length=u_shapeArabic(dst, 2,
3376                          src, 2,
3377                          U_SHAPE_LETTERS_UNSHAPE,
3378                          &errorCode);
3379     if(U_FAILURE(errorCode) || length!=2 || src[0] != otherChar[GENERIC] || src[1] != in[GENERIC]) {
3380       log_err("failure in u_shapeArabic(_testAllForms: unshaping final): %x\n", in[GENERIC]);
3381     }
3382   } else {
3383     errorCode=U_ZERO_ERROR;
3384     length=u_shapeArabic(src, 2,
3385                          dst, 2,
3386                          U_SHAPE_LETTERS_SHAPE,
3387                          &errorCode);
3388     if(U_FAILURE(errorCode) || length!=2 || dst[0] != otherChar[ISOLATED] || dst[1] != in[ISOLATED]) {
3389       log_err("failure in u_shapeArabic(_testAllForms: shaping final): %x\n", in[GENERIC]);
3390     }
3391     errorCode=U_ZERO_ERROR;
3392     length=u_shapeArabic(dst, 2,
3393                          src, 2,
3394                          U_SHAPE_LETTERS_UNSHAPE,
3395                          &errorCode);
3396     if(U_FAILURE(errorCode) || length!=2 || src[0] != otherChar[GENERIC] || src[1] != in[GENERIC]) {
3397       log_err("failure in u_shapeArabic(_testAllForms: unshaping final): %x\n", in[GENERIC]);
3398     }
3399   }
3400 
3401   /* Testing initial shaping */
3402   src[0] = in[GENERIC];
3403   src[1] = otherChar[GENERIC];
3404   if (in[INITIAL] != 0) {
3405     /* Testing characters that have an initial form */
3406     errorCode=U_ZERO_ERROR;
3407     length=u_shapeArabic(src, 2,
3408                          dst, 2,
3409                          U_SHAPE_LETTERS_SHAPE,
3410                          &errorCode);
3411     if(U_FAILURE(errorCode) || length!=2 || dst[0] != in[INITIAL] || dst[1] != otherChar[FINAL]) {
3412       log_err("failure in u_shapeArabic(_testAllForms: shaping initial): %x\n", in[GENERIC]);
3413     }
3414     errorCode=U_ZERO_ERROR;
3415     length=u_shapeArabic(dst, 2,
3416                          src, 2,
3417                          U_SHAPE_LETTERS_UNSHAPE,
3418                          &errorCode);
3419     if(U_FAILURE(errorCode) || length!=2 || src[0] != in[GENERIC] || src[1] != otherChar[GENERIC]) {
3420       log_err("failure in u_shapeArabic(_testAllForms: unshaping initial): %x\n", in[GENERIC]);
3421     }
3422   } else {
3423     /* Testing characters that do not have an initial form */
3424     errorCode=U_ZERO_ERROR;
3425     length=u_shapeArabic(src, 2,
3426                          dst, 2,
3427                          U_SHAPE_LETTERS_SHAPE,
3428                          &errorCode);
3429     if(U_FAILURE(errorCode) || length!=2 || dst[0] != in[ISOLATED] || dst[1] != otherChar[ISOLATED]) {
3430       log_err("failure in u_shapeArabic(_testTwoForms: shaping initial): %x\n", in[GENERIC]);
3431     }
3432     errorCode=U_ZERO_ERROR;
3433     length=u_shapeArabic(dst, 2,
3434                          src, 2,
3435                          U_SHAPE_LETTERS_UNSHAPE,
3436                          &errorCode);
3437     if(U_FAILURE(errorCode) || length!=2 || src[0] != in[GENERIC] || src[1] != otherChar[GENERIC]) {
3438       log_err("failure in u_shapeArabic(_testTwoForms: unshaping initial): %x\n", in[GENERIC]);
3439     }
3440   }
3441 
3442   /* Testing medial shaping */
3443   src[0] = otherChar[0];
3444   src[1] = in[GENERIC];
3445   src[2] = otherChar[0];
3446   errorCode=U_ZERO_ERROR;
3447   if (in[MEDIAL] != 0) {
3448     /* Testing characters that have an medial form */
3449     length=u_shapeArabic(src, 3,
3450                          dst, 3,
3451                          U_SHAPE_LETTERS_SHAPE,
3452                          &errorCode);
3453     if(U_FAILURE(errorCode) || length!=3 || dst[0] != otherChar[INITIAL] || dst[1] != in[MEDIAL] || dst[2] != otherChar[FINAL]) {
3454       log_err("failure in u_shapeArabic(_testAllForms: shaping medial): %x\n", in[GENERIC]);
3455     }
3456     errorCode=U_ZERO_ERROR;
3457     length=u_shapeArabic(dst, 3,
3458                          src, 3,
3459                          U_SHAPE_LETTERS_UNSHAPE,
3460                          &errorCode);
3461     if(U_FAILURE(errorCode) || length!=3 || src[0] != otherChar[GENERIC] || src[1] != in[GENERIC] || src[2] != otherChar[GENERIC]) {
3462       log_err("failure in u_shapeArabic(_testAllForms: unshaping medial): %x\n", in[GENERIC]);
3463     }
3464   } else {
3465     /* Testing characters that do not have an medial form */
3466     errorCode=U_ZERO_ERROR;
3467     length=u_shapeArabic(src, 3,
3468                          dst, 3,
3469                          U_SHAPE_LETTERS_SHAPE,
3470                          &errorCode);
3471     if(U_FAILURE(errorCode) || length!=3 || dst[0] != otherChar[INITIAL] || dst[1] != in[FINAL] || dst[2] != otherChar[ISOLATED]) {
3472       log_err("failure in u_shapeArabic(_testTwoForms: shaping medial): %x\n", in[GENERIC]);
3473     }
3474     errorCode=U_ZERO_ERROR;
3475     length=u_shapeArabic(dst, 3,
3476                          src, 3,
3477                          U_SHAPE_LETTERS_UNSHAPE,
3478                          &errorCode);
3479     if(U_FAILURE(errorCode) || length!=3 || src[0] != otherChar[GENERIC] || src[1] != in[GENERIC] || src[2] != otherChar[GENERIC]) {
3480       log_err("failure in u_shapeArabic(_testTwoForms: unshaping medial): %x\n", in[GENERIC]);
3481     }
3482   }
3483 }
3484 
3485 static void
doArabicShapingTestForNewCharacters(void)3486 doArabicShapingTestForNewCharacters(void) {
3487   static const UChar letterForms[][5]={
3488     { 0x0679, 0xFB66, 0xFB67, 0xFB68, 0xFB69 },  /* TTEH */
3489     { 0x067A, 0xFB5E, 0xFB5F, 0xFB60, 0xFB61 },  /* TTEHEH */
3490     { 0x067B, 0xFB52, 0xFB53, 0xFB54, 0xFB55 },  /* BEEH */
3491     { 0x0688, 0xFB88, 0xFB89, 0, 0 },            /* DDAL */
3492     { 0x068C, 0xFB84, 0xFB85, 0, 0 },            /* DAHAL */
3493     { 0x068D, 0xFB82, 0xFB83, 0, 0 },            /* DDAHAL */
3494     { 0x068E, 0xFB86, 0xFB87, 0, 0 },            /* DUL */
3495     { 0x0691, 0xFB8C, 0xFB8D, 0, 0 },            /* RREH */
3496     { 0x06BA, 0xFB9E, 0xFB9F, 0, 0 },            /* NOON GHUNNA */
3497     { 0x06BB, 0xFBA0, 0xFBA1, 0xFBA2, 0xFBA3 },  /* RNOON */
3498     { 0x06BE, 0xFBAA, 0xFBAB, 0xFBAC, 0xFBAD },  /* HEH DOACHASHMEE */
3499     { 0x06C0, 0xFBA4, 0xFBA5, 0, 0 },            /* HEH WITH YEH ABOVE */
3500     { 0x06C1, 0xFBA6, 0xFBA7, 0xFBA8, 0xFBA9 },  /* HEH GOAL */
3501     { 0x06C5, 0xFBE0, 0xFBE1, 0, 0 },            /* KIRGIHIZ OE */
3502     { 0x06C6, 0xFBD9, 0xFBDA, 0, 0 },            /* OE */
3503     { 0x06C7, 0xFBD7, 0xFBD8, 0, 0 },            /* U */
3504     { 0x06C8, 0xFBDB, 0xFBDC, 0, 0 },            /* YU */
3505     { 0x06C9, 0xFBE2, 0xFBE3, 0, 0 },            /* KIRGIZ YU */
3506     { 0x06CB, 0xFBDE, 0xFBDF, 0, 0},             /* VE */
3507     { 0x06D0, 0xFBE4, 0xFBE5, 0xFBE6, 0xFBE7 },  /* E */
3508     { 0x06D2, 0xFBAE, 0xFBAF, 0, 0 },            /* YEH BARREE */
3509     { 0x06D3, 0xFBB0, 0xFBB1, 0, 0 },            /* YEH BARREE WITH HAMZA ABOVE */
3510     { 0x0622, 0xFE81, 0xFE82, 0, 0, },           /* ALEF WITH MADDA ABOVE */
3511     { 0x0623, 0xFE83, 0xFE84, 0, 0, },           /* ALEF WITH HAMZA ABOVE */
3512     { 0x0624, 0xFE85, 0xFE86, 0, 0, },           /* WAW WITH HAMZA ABOVE */
3513     { 0x0625, 0xFE87, 0xFE88, 0, 0, },           /* ALEF WITH HAMZA BELOW */
3514     { 0x0626, 0xFE89, 0xFE8A, 0xFE8B, 0xFE8C, }, /* YEH WITH HAMZA ABOVE */
3515     { 0x0627, 0xFE8D, 0xFE8E, 0, 0, },           /* ALEF */
3516     { 0x0628, 0xFE8F, 0xFE90, 0xFE91, 0xFE92, }, /* BEH */
3517     { 0x0629, 0xFE93, 0xFE94, 0, 0, },           /* TEH MARBUTA */
3518     { 0x062A, 0xFE95, 0xFE96, 0xFE97, 0xFE98, }, /* TEH */
3519     { 0x062B, 0xFE99, 0xFE9A, 0xFE9B, 0xFE9C, }, /* THEH */
3520     { 0x062C, 0xFE9D, 0xFE9E, 0xFE9F, 0xFEA0, }, /* JEEM */
3521     { 0x062D, 0xFEA1, 0xFEA2, 0xFEA3, 0xFEA4, }, /* HAH */
3522     { 0x062E, 0xFEA5, 0xFEA6, 0xFEA7, 0xFEA8, }, /* KHAH */
3523     { 0x062F, 0xFEA9, 0xFEAA, 0, 0, },           /* DAL */
3524     { 0x0630, 0xFEAB, 0xFEAC, 0, 0, },           /* THAL */
3525     { 0x0631, 0xFEAD, 0xFEAE, 0, 0, },           /* REH */
3526     { 0x0632, 0xFEAF, 0xFEB0, 0, 0, },           /* ZAIN */
3527     { 0x0633, 0xFEB1, 0xFEB2, 0xFEB3, 0xFEB4, }, /* SEEN */
3528     { 0x0634, 0xFEB5, 0xFEB6, 0xFEB7, 0xFEB8, }, /* SHEEN */
3529     { 0x0635, 0xFEB9, 0xFEBA, 0xFEBB, 0xFEBC, }, /* SAD */
3530     { 0x0636, 0xFEBD, 0xFEBE, 0xFEBF, 0xFEC0, }, /* DAD */
3531     { 0x0637, 0xFEC1, 0xFEC2, 0xFEC3, 0xFEC4, }, /* TAH */
3532     { 0x0638, 0xFEC5, 0xFEC6, 0xFEC7, 0xFEC8, }, /* ZAH */
3533     { 0x0639, 0xFEC9, 0xFECA, 0xFECB, 0xFECC, }, /* AIN */
3534     { 0x063A, 0xFECD, 0xFECE, 0xFECF, 0xFED0, }, /* GHAIN */
3535     { 0x0641, 0xFED1, 0xFED2, 0xFED3, 0xFED4, }, /* FEH */
3536     { 0x0642, 0xFED5, 0xFED6, 0xFED7, 0xFED8, }, /* QAF */
3537     { 0x0643, 0xFED9, 0xFEDA, 0xFEDB, 0xFEDC, }, /* KAF */
3538     { 0x0644, 0xFEDD, 0xFEDE, 0xFEDF, 0xFEE0, }, /* LAM */
3539     { 0x0645, 0xFEE1, 0xFEE2, 0xFEE3, 0xFEE4, }, /* MEEM */
3540     { 0x0646, 0xFEE5, 0xFEE6, 0xFEE7, 0xFEE8, }, /* NOON */
3541     { 0x0647, 0xFEE9, 0xFEEA, 0xFEEB, 0xFEEC, }, /* HEH */
3542     { 0x0648, 0xFEED, 0xFEEE, 0, 0, },           /* WAW */
3543     { 0x0649, 0xFEEF, 0xFEF0, 0, 0, },           /* ALEF MAKSURA */
3544     { 0x064A, 0xFEF1, 0xFEF2, 0xFEF3, 0xFEF4, }, /* YEH */
3545     { 0x064E, 0xFE76, 0, 0, 0xFE77, },           /* FATHA */
3546     { 0x064F, 0xFE78, 0, 0, 0xFE79, },           /* DAMMA */
3547     { 0x0650, 0xFE7A, 0, 0, 0xFE7B, },           /* KASRA */
3548     { 0x0651, 0xFE7C, 0, 0, 0xFE7D, },           /* SHADDA */
3549     { 0x0652, 0xFE7E, 0, 0, 0xFE7F, },           /* SUKUN */
3550     { 0x0679, 0xFB66, 0xFB67, 0xFB68, 0xFB69, }, /* TTEH */
3551     { 0x067E, 0xFB56, 0xFB57, 0xFB58, 0xFB59, }, /* PEH */
3552     { 0x0686, 0xFB7A, 0xFB7B, 0xFB7C, 0xFB7D, }, /* TCHEH */
3553     { 0x0688, 0xFB88, 0xFB89, 0, 0, },           /* DDAL */
3554     { 0x0691, 0xFB8C, 0xFB8D, 0, 0, },           /* RREH */
3555     { 0x0698, 0xFB8A, 0xFB8B, 0, 0, },           /* JEH */
3556     { 0x06A9, 0xFB8E, 0xFB8F, 0xFB90, 0xFB91, }, /* KEHEH */
3557     { 0x06AF, 0xFB92, 0xFB93, 0xFB94, 0xFB95, }, /* GAF */
3558     { 0x06BA, 0xFB9E, 0xFB9F, 0, 0, },           /* NOON GHUNNA */
3559     { 0x06BE, 0xFBAA, 0xFBAB, 0xFBAC, 0xFBAD, }, /* HEH DOACHASHMEE */
3560     { 0x06C0, 0xFBA4, 0xFBA5, 0, 0, },           /* HEH WITH YEH ABOVE */
3561     { 0x06C1, 0xFBA6, 0xFBA7, 0xFBA8, 0xFBA9, }, /* HEH GOAL */
3562     { 0x06CC, 0xFBFC, 0xFBFD, 0xFBFE, 0xFBFF, }, /* FARSI YEH */
3563     { 0x06D2, 0xFBAE, 0xFBAF, 0, 0, },           /* YEH BARREE */
3564     { 0x06D3, 0xFBB0, 0xFBB1, 0, 0, }};          /* YEH BARREE WITH HAMZA ABOVE */
3565   int32_t i;
3566   for (i = 0; i < UPRV_LENGTHOF(letterForms); ++i) {
3567     _testPresentationForms(letterForms[i]);
3568   }
3569 }
3570 
3571 /* helpers ------------------------------------------------------------------ */
3572 
initCharFromDirProps(void)3573 static void initCharFromDirProps(void) {
3574     static const UVersionInfo ucd401={ 4, 0, 1, 0 };
3575     static UVersionInfo ucdVersion={ 0, 0, 0, 0 };
3576 
3577     /* lazy initialization */
3578     if(ucdVersion[0]>0) {
3579         return;
3580     }
3581 
3582     u_getUnicodeVersion(ucdVersion);
3583     if(memcmp(ucdVersion, ucd401, sizeof(UVersionInfo))>=0) {
3584         /* Unicode 4.0.1 changes bidi classes for +-/ */
3585         charFromDirProp[U_EUROPEAN_NUMBER_SEPARATOR]=0x2b; /* change ES character from / to + */
3586     }
3587 }
3588 
3589 /* return a string with characters according to the desired directional properties */
3590 static UChar *
getStringFromDirProps(const uint8_t * dirProps,int32_t length,UChar * buffer)3591 getStringFromDirProps(const uint8_t *dirProps, int32_t length, UChar *buffer) {
3592     int32_t i;
3593 
3594     initCharFromDirProps();
3595 
3596     /* this part would have to be modified for UTF-x */
3597     for(i=0; i<length; ++i) {
3598         buffer[i]=charFromDirProp[dirProps[i]];
3599     }
3600     buffer[length]=0;
3601     return buffer;
3602 }
3603 
printUnicode(const UChar * s,int32_t length,const UBiDiLevel * levels)3604 static void printUnicode(const UChar *s, int32_t length, const UBiDiLevel *levels) {
3605     int32_t i;
3606 
3607     log_verbose("{ ");
3608     for(i=0; i<length; ++i) {
3609         if(levels!=NULL) {
3610             log_verbose("%4x.%u  ", s[i], levels[i]);
3611         } else {
3612             log_verbose("%4x    ", s[i]);
3613         }
3614     }
3615     log_verbose(" }");
3616 }
3617 
3618 /* new BIDI API */
3619 
3620 /* Reordering Mode BiDi --------------------------------------------------------- */
3621 
3622 static const UBiDiLevel paraLevels[] = { UBIDI_LTR, UBIDI_RTL };
3623 
3624 static UBool
assertSuccessful(const char * message,UErrorCode * rc)3625 assertSuccessful(const char* message, UErrorCode* rc) {
3626     if (rc != NULL && U_FAILURE(*rc)) {
3627         log_err("%s() failed with error %s.\n", message, myErrorName(*rc));
3628         return FALSE;
3629     }
3630     return TRUE;
3631 }
3632 
3633 static UBool
assertStringsEqual(const char * expected,const char * actual,const char * src,const char * mode,const char * option,UBiDi * pBiDi)3634 assertStringsEqual(const char* expected, const char* actual, const char* src,
3635                    const char* mode, const char* option, UBiDi* pBiDi) {
3636     if (uprv_strcmp(expected, actual)) {
3637         char formatChars[MAXLEN];
3638         log_err("\nActual and expected output mismatch.\n"
3639             "%20s %s\n%20s %s\n%20s %s\n%20s %s\n%20s %d %s\n%20s %u\n%20s %d %s\n",
3640             "Input:", src,
3641             "Actual output:", actual,
3642             "Expected output:", expected,
3643             "Levels:", formatLevels(pBiDi, formatChars),
3644             "Reordering mode:", ubidi_getReorderingMode(pBiDi), mode,
3645             "Paragraph level:", ubidi_getParaLevel(pBiDi),
3646             "Reordering option:", ubidi_getReorderingOptions(pBiDi), option);
3647         return FALSE;
3648     }
3649     return TRUE;
3650 }
3651 
3652 static UBiDi*
getBiDiObject(void)3653 getBiDiObject(void) {
3654     UBiDi* pBiDi = ubidi_open();
3655     if (pBiDi == NULL) {
3656         log_err("Unable to allocate a UBiDi object. Tests are skipped.\n");
3657     }
3658     return pBiDi;
3659 }
3660 
3661 #define MAKE_ITEMS(val) val, #val
3662 
3663 static const struct {
3664     UBiDiReorderingMode value;
3665     const char* description;
3666 }
3667 modes[] = {
3668     { MAKE_ITEMS(UBIDI_REORDER_GROUP_NUMBERS_WITH_R) },
3669     { MAKE_ITEMS(UBIDI_REORDER_INVERSE_LIKE_DIRECT) },
3670     { MAKE_ITEMS(UBIDI_REORDER_NUMBERS_SPECIAL) },
3671     { MAKE_ITEMS(UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL) },
3672     { MAKE_ITEMS(UBIDI_REORDER_INVERSE_NUMBERS_AS_L) }
3673 };
3674 static const struct {
3675     uint32_t value;
3676     const char* description;
3677 }
3678 options[] = {
3679     { MAKE_ITEMS(UBIDI_OPTION_INSERT_MARKS) },
3680     { MAKE_ITEMS(0) }
3681 };
3682 
3683 #define TC_COUNT                UPRV_LENGTHOF(textIn)
3684 #define MODES_COUNT             UPRV_LENGTHOF(modes)
3685 #define OPTIONS_COUNT           UPRV_LENGTHOF(options)
3686 #define LEVELS_COUNT            UPRV_LENGTHOF(paraLevels)
3687 
3688 static const char* const textIn[] = {
3689 /* (0) 123 */
3690     "123",
3691 /* (1) .123->4.5 */
3692     ".123->4.5",
3693 /* (2) 678 */
3694     "678",
3695 /* (3) .678->8.9 */
3696     ".678->8.9",
3697 /* (4) JIH1.2,3MLK */
3698     "JIH1.2,3MLK",
3699 /* (5) FE.>12-> */
3700     "FE.>12->",
3701 /* (6) JIH.>12->a */
3702     "JIH.>12->a",
3703 /* (7) CBA.>67->89=a */
3704     "CBA.>67->89=a",
3705 /* (8) CBA.123->xyz */
3706     "CBA.123->xyz",
3707 /* (9) .>12->xyz */
3708     ".>12->xyz",
3709 /* (10) a.>67->xyz */
3710     "a.>67->xyz",
3711 /* (11) 123JIH */
3712     "123JIH",
3713 /* (12) 123 JIH */
3714     "123 JIH"
3715 };
3716 
3717 static const char* const textOut[] = {
3718 /* TC 0: 123 */
3719     "123",                                                              /* (0) */
3720 /* TC 1: .123->4.5 */
3721     ".123->4.5",                                                        /* (1) */
3722     "4.5<-123.",                                                        /* (2) */
3723 /* TC 2: 678 */
3724     "678",                                                              /* (3) */
3725 /* TC 3: .678->8.9 */
3726     ".8.9<-678",                                                        /* (4) */
3727     "8.9<-678.",                                                        /* (5) */
3728     ".678->8.9",                                                        /* (6) */
3729 /* TC 4: MLK1.2,3JIH */
3730     "KLM1.2,3HIJ",                                                      /* (7) */
3731 /* TC 5: FE.>12-> */
3732     "12<.EF->",                                                         /* (8) */
3733     "<-12<.EF",                                                         /* (9) */
3734     "EF.>@12->",                                                        /* (10) */
3735 /* TC 6: JIH.>12->a */
3736     "12<.HIJ->a",                                                       /* (11) */
3737     "a<-12<.HIJ",                                                       /* (12) */
3738     "HIJ.>@12->a",                                                      /* (13) */
3739     "a&<-12<.HIJ",                                                      /* (14) */
3740 /* TC 7: CBA.>67->89=a */
3741     "ABC.>@67->89=a",                                                   /* (15) */
3742     "a=89<-67<.ABC",                                                    /* (16) */
3743     "a&=89<-67<.ABC",                                                   /* (17) */
3744     "89<-67<.ABC=a",                                                    /* (18) */
3745 /* TC 8: CBA.123->xyz */
3746     "123.ABC->xyz",                                                     /* (19) */
3747     "xyz<-123.ABC",                                                     /* (20) */
3748     "ABC.@123->xyz",                                                    /* (21) */
3749     "xyz&<-123.ABC",                                                    /* (22) */
3750 /* TC 9: .>12->xyz */
3751     ".>12->xyz",                                                        /* (23) */
3752     "xyz<-12<.",                                                        /* (24) */
3753     "xyz&<-12<.",                                                       /* (25) */
3754 /* TC 10: a.>67->xyz */
3755     "a.>67->xyz",                                                       /* (26) */
3756     "a.>@67@->xyz",                                                     /* (27) */
3757     "xyz<-67<.a",                                                       /* (28) */
3758 /* TC 11: 123JIH */
3759     "123HIJ",                                                           /* (29) */
3760     "HIJ123",                                                           /* (30) */
3761 /* TC 12: 123 JIH */
3762     "123 HIJ",                                                          /* (31) */
3763     "HIJ 123",                                                          /* (32) */
3764 };
3765 
3766 #define NO                  UBIDI_MAP_NOWHERE
3767 #define MAX_MAP_LENGTH      20
3768 
3769 static const int32_t forwardMap[][MAX_MAP_LENGTH] = {
3770 /* TC 0: 123 */
3771     { 0, 1, 2 },                                                        /* (0) */
3772 /* TC 1: .123->4.5 */
3773     { 0, 1, 2, 3, 4, 5, 6, 7, 8 },                                      /* (1) */
3774     { 8, 5, 6, 7, 4, 3, 0, 1, 2 },                                      /* (2) */
3775 /* TC 2: 678 */
3776     { 0, 1, 2 },                                                        /* (3) */
3777 /* TC 3: .678->8.9 */
3778     { 0, 6, 7, 8, 5, 4, 1, 2, 3 },                                      /* (4) */
3779     { 8, 5, 6, 7, 4, 3, 0, 1, 2 },                                      /* (5) */
3780     { 0, 1, 2, 3, 4, 5, 6, 7, 8 },                                      /* (6) */
3781 /* TC 4: MLK1.2,3JIH */
3782     { 10, 9, 8, 3, 4, 5, 6, 7, 2, 1, 0 },                               /* (7) */
3783 /* TC 5: FE.>12-> */
3784     { 5, 4, 3, 2, 0, 1, 6, 7 },                                         /* (8) */
3785     { 7, 6, 5, 4, 2, 3, 1, 0 },                                         /* (9) */
3786     { 1, 0, 2, 3, 5, 6, 7, 8 },                                         /* (10) */
3787 /* TC 6: JIH.>12->a */
3788     { 6, 5, 4, 3, 2, 0, 1, 7, 8, 9 },                                   /* (11) */
3789     { 9, 8, 7, 6, 5, 3, 4, 2, 1, 0 },                                   /* (12) */
3790     { 2, 1, 0, 3, 4, 6, 7, 8, 9, 10 },                                  /* (13) */
3791     { 10, 9, 8, 7, 6, 4, 5, 3, 2, 0 },                                  /* (14) */
3792 /* TC 7: CBA.>67->89=a */
3793     { 2, 1, 0, 3, 4, 6, 7, 8, 9, 10, 11, 12, 13 },                      /* (15) */
3794     { 12, 11, 10, 9, 8, 6, 7, 5, 4, 2, 3, 1, 0 },                       /* (16) */
3795     { 13, 12, 11, 10, 9, 7, 8, 6, 5, 3, 4, 2, 0 },                      /* (17) */
3796     { 10, 9, 8, 7, 6, 4, 5, 3, 2, 0, 1, 11, 12 },                       /* (18) */
3797 /* TC 8: CBA.123->xyz */
3798     { 6, 5, 4, 3, 0, 1, 2, 7, 8, 9, 10, 11 },                           /* (19) */
3799     { 11, 10, 9, 8, 5, 6, 7, 4, 3, 0, 1, 2 },                           /* (20) */
3800     { 2, 1, 0, 3, 5, 6, 7, 8, 9, 10, 11, 12 },                          /* (21) */
3801     { 12, 11, 10, 9, 6, 7, 8, 5, 4, 0, 1, 2 },                          /* (22) */
3802 /* TC 9: .>12->xyz */
3803     { 0, 1, 2, 3, 4, 5, 6, 7, 8 },                                      /* (23) */
3804     { 8, 7, 5, 6, 4, 3, 0, 1, 2 },                                      /* (24) */
3805     { 9, 8, 6, 7, 5, 4, 0, 1, 2 },                                      /* (25) */
3806 /* TC 10: a.>67->xyz */
3807     { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },                                   /* (26) */
3808     { 0, 1, 2, 4, 5, 7, 8, 9, 10, 11 },                                 /* (27) */
3809     { 9, 8, 7, 5, 6, 4, 3, 0, 1, 2 },                                   /* (28) */
3810 /* TC 11: 123JIH */
3811     { 0, 1, 2, 5, 4, 3 },                                               /* (29) */
3812     { 3, 4, 5, 2, 1, 0 },                                               /* (30) */
3813 /* TC 12: 123 JIH */
3814     { 0, 1, 2, 3, 6, 5, 4 },                                            /* (31) */
3815     { 4, 5, 6, 3, 2, 1, 0 },                                            /* (32) */
3816 };
3817 
3818 static const int32_t inverseMap[][MAX_MAP_LENGTH] = {
3819 /* TC 0: 123 */
3820     { 0, 1, 2 },                                                        /* (0) */
3821 /* TC 1: .123->4.5 */
3822     { 0, 1, 2, 3, 4, 5, 6, 7, 8 },                                      /* (1) */
3823     { 6, 7, 8, 5, 4, 1, 2, 3, 0 },                                      /* (2) */
3824 /* TC 2: 678 */
3825     { 0, 1, 2 },                                                        /* (3) */
3826 /* TC 3: .678->8.9 */
3827     { 0, 6, 7, 8, 5, 4, 1, 2, 3 },                                      /* (4) */
3828     { 6, 7, 8, 5, 4, 1, 2, 3, 0 },                                      /* (5) */
3829     { 0, 1, 2, 3, 4, 5, 6, 7, 8 },                                      /* (6) */
3830 /* TC 4: MLK1.2,3JIH */
3831     { 10, 9, 8, 3, 4, 5, 6, 7, 2, 1, 0 },                               /* (7) */
3832 /* TC 5: FE.>12-> */
3833     { 4, 5, 3, 2, 1, 0, 6, 7 },                                         /* (8) */
3834     { 7, 6, 4, 5, 3, 2, 1, 0 },                                         /* (9) */
3835     { 1, 0, 2, 3, NO, 4, 5, 6, 7 },                                     /* (10) */
3836 /* TC 6: JIH.>12->a */
3837     { 5, 6, 4, 3, 2, 1, 0, 7, 8, 9 },                                   /* (11) */
3838     { 9, 8, 7, 5, 6, 4, 3, 2, 1, 0 },                                   /* (12) */
3839     { 2, 1, 0, 3, 4, NO, 5, 6, 7, 8, 9 },                               /* (13) */
3840     { 9, NO, 8, 7, 5, 6, 4, 3, 2, 1, 0 },                               /* (14) */
3841 /* TC 7: CBA.>67->89=a */
3842     { 2, 1, 0, 3, 4, NO, 5, 6, 7, 8, 9, 10, 11, 12 },                   /* (15) */
3843     { 12, 11, 9, 10, 8, 7, 5, 6, 4, 3, 2, 1, 0 },                       /* (16) */
3844     { 12, NO, 11, 9, 10, 8, 7, 5, 6, 4, 3, 2, 1, 0 },                   /* (17) */
3845     { 9, 10, 8, 7, 5, 6, 4, 3, 2, 1, 0, 11, 12 },                       /* (18) */
3846 /* TC 8: CBA.123->xyz */
3847     { 4, 5, 6, 3, 2, 1, 0, 7, 8, 9, 10, 11 },                           /* (19) */
3848     { 9, 10, 11, 8, 7, 4, 5, 6, 3, 2, 1, 0 },                           /* (20) */
3849     { 2, 1, 0, 3, NO, 4, 5, 6, 7, 8, 9, 10, 11 },                       /* (21) */
3850     { 9, 10, 11, NO, 8, 7, 4, 5, 6, 3, 2, 1, 0 },                       /* (22) */
3851 /* TC 9: .>12->xyz */
3852     { 0, 1, 2, 3, 4, 5, 6, 7, 8 },                                      /* (23) */
3853     { 6, 7, 8, 5, 4, 2, 3, 1, 0 },                                      /* (24) */
3854     { 6, 7, 8, NO, 5, 4, 2, 3, 1, 0 },                                  /* (25) */
3855 /* TC 10: a.>67->xyz */
3856     { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },                                   /* (26) */
3857     { 0, 1, 2, NO, 3, 4, NO, 5, 6, 7, 8, 9 },                           /* (27) */
3858     { 7, 8, 9, 6, 5, 3, 4, 2, 1, 0 },                                   /* (28) */
3859 /* TC 11: 123JIH */
3860     { 0, 1, 2, 5, 4, 3 },                                               /* (29) */
3861     { 5, 4, 3, 0, 1, 2 },                                               /* (30) */
3862 /* TC 12: 123 JIH */
3863     { 0, 1, 2, 3, 6, 5, 4 },                                            /* (31) */
3864     { 6, 5, 4, 3, 0, 1, 2 },                                            /* (32) */
3865 };
3866 
3867 static const char outIndices[TC_COUNT][MODES_COUNT - 1][OPTIONS_COUNT]
3868             [LEVELS_COUNT] = {
3869     { /* TC 0: 123 */
3870         {{ 0,  0}, { 0,  0}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
3871         {{ 0,  0}, { 0,  0}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
3872         {{ 0,  0}, { 0,  0}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
3873         {{ 0,  0}, { 0,  0}}  /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
3874     },
3875     { /* TC 1: .123->4.5 */
3876         {{ 1,  2}, { 1,  2}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
3877         {{ 1,  2}, { 1,  2}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
3878         {{ 1,  2}, { 1,  2}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
3879         {{ 1,  2}, { 1,  2}}  /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
3880     },
3881     { /* TC 2: 678 */
3882         {{ 3,  3}, { 3,  3}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
3883         {{ 3,  3}, { 3,  3}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
3884         {{ 3,  3}, { 3,  3}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
3885         {{ 3,  3}, { 3,  3}}  /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
3886     },
3887     { /* TC 3: .678->8.9 */
3888         {{ 6,  5}, { 6,  5}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
3889         {{ 4,  5}, { 4,  5}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
3890         {{ 6,  5}, { 6,  5}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
3891         {{ 6,  5}, { 6,  5}}  /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
3892     },
3893     { /* TC 4: MLK1.2,3JIH */
3894         {{ 7,  7}, { 7,  7}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
3895         {{ 7,  7}, { 7,  7}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
3896         {{ 7,  7}, { 7,  7}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
3897         {{ 7,  7}, { 7,  7}}  /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
3898     },
3899     { /* TC 5: FE.>12-> */
3900         {{ 8,  9}, { 8,  9}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
3901         {{10,  9}, { 8,  9}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
3902         {{ 8,  9}, { 8,  9}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
3903         {{10,  9}, { 8,  9}}  /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
3904     },
3905     { /* TC 6: JIH.>12->a */
3906         {{11, 12}, {11, 12}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
3907         {{13, 14}, {11, 12}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
3908         {{11, 12}, {11, 12}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
3909         {{13, 14}, {11, 12}}  /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
3910     },
3911     { /* TC 7: CBA.>67->89=a */
3912         {{18, 16}, {18, 16}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
3913         {{18, 17}, {18, 16}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
3914         {{18, 16}, {18, 16}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
3915         {{15, 17}, {18, 16}}  /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
3916     },
3917     { /* TC 8: CBA.>124->xyz */
3918         {{19, 20}, {19, 20}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
3919         {{21, 22}, {19, 20}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
3920         {{19, 20}, {19, 20}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
3921         {{21, 22}, {19, 20}}  /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
3922     },
3923     { /* TC 9: .>12->xyz */
3924         {{23, 24}, {23, 24}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
3925         {{23, 25}, {23, 24}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
3926         {{23, 24}, {23, 24}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
3927         {{23, 25}, {23, 24}}  /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
3928     },
3929     { /* TC 10: a.>67->xyz */
3930         {{26, 26}, {26, 26}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
3931         {{26, 27}, {26, 28}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
3932         {{26, 28}, {26, 28}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
3933         {{26, 27}, {26, 28}}  /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
3934     },
3935     { /* TC 11: 124JIH */
3936         {{30, 30}, {30, 30}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
3937         {{29, 30}, {29, 30}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
3938         {{30, 30}, {30, 30}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
3939         {{30, 30}, {30, 30}}  /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
3940     },
3941     { /* TC 12: 124 JIH */
3942         {{32, 32}, {32, 32}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
3943         {{31, 32}, {31, 32}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
3944         {{31, 32}, {31, 32}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
3945         {{31, 32}, {31, 32}}  /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
3946     }
3947 };
3948 
3949 static UBool
assertRoundTrip(UBiDi * pBiDi,int32_t tc,int32_t outIndex,const char * srcChars,const char * destChars,const UChar * dest,int32_t destLen,int mode,int option,UBiDiLevel level)3950 assertRoundTrip(UBiDi *pBiDi, int32_t tc, int32_t outIndex, const char *srcChars,
3951                 const char *destChars, const UChar *dest, int32_t destLen,
3952                 int mode, int option, UBiDiLevel level) {
3953 
3954     static const char roundtrip[TC_COUNT][MODES_COUNT][OPTIONS_COUNT]
3955                 [LEVELS_COUNT] = {
3956         { /* TC 0: 123 */
3957             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
3958             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
3959             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
3960             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
3961             {{ 1,  1}, { 1,  1}}  /* UBIDI_REORDER_INVERSE_NUMBERS_AS_L */
3962         },
3963         { /* TC 1: .123->4.5 */
3964             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
3965             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
3966             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
3967             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
3968             {{ 1,  1}, { 1,  1}}  /* UBIDI_REORDER_INVERSE_NUMBERS_AS_L */
3969         },
3970         { /* TC 2: 678 */
3971             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
3972             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
3973             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
3974             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
3975             {{ 1,  1}, { 1,  1}}  /* UBIDI_REORDER_INVERSE_NUMBERS_AS_L */
3976         },
3977         { /* TC 3: .678->8.9 */
3978             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
3979             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
3980             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
3981             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
3982             {{ 0,  0}, { 1,  1}}  /* UBIDI_REORDER_INVERSE_NUMBERS_AS_L */
3983         },
3984         { /* TC 4: MLK1.2,3JIH */
3985             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
3986             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
3987             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
3988             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
3989             {{ 1,  1}, { 1,  1}}  /* UBIDI_REORDER_INVERSE_NUMBERS_AS_L */
3990         },
3991         { /* TC 5: FE.>12-> */
3992             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
3993             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
3994             {{ 0,  1}, { 1,  1}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
3995             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
3996             {{ 1,  1}, { 1,  1}}  /* UBIDI_REORDER_INVERSE_NUMBERS_AS_L */
3997         },
3998         { /* TC 6: JIH.>12->a */
3999             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
4000             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
4001             {{ 0,  0}, { 1,  1}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
4002             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
4003             {{ 1,  1}, { 1,  1}}  /* UBIDI_REORDER_INVERSE_NUMBERS_AS_L */
4004         },
4005         { /* TC 7: CBA.>67->89=a */
4006             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
4007             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
4008             {{ 0,  1}, { 1,  1}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
4009             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
4010             {{ 0,  0}, { 1,  1}}  /* UBIDI_REORDER_INVERSE_NUMBERS_AS_L */
4011         },
4012         { /* TC 8: CBA.>123->xyz */
4013             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
4014             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
4015             {{ 0,  0}, { 1,  1}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
4016             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
4017             {{ 1,  1}, { 1,  1}}  /* UBIDI_REORDER_INVERSE_NUMBERS_AS_L */
4018         },
4019         { /* TC 9: .>12->xyz */
4020             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
4021             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
4022             {{ 1,  0}, { 1,  1}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
4023             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
4024             {{ 1,  1}, { 1,  1}}  /* UBIDI_REORDER_INVERSE_NUMBERS_AS_L */
4025         },
4026         { /* TC 10: a.>67->xyz */
4027             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
4028             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
4029             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
4030             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
4031             {{ 1,  0}, { 1,  1}}  /* UBIDI_REORDER_INVERSE_NUMBERS_AS_L */
4032         },
4033         { /* TC 11: 123JIH */
4034             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
4035             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
4036             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
4037             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
4038             {{ 1,  1}, { 1,  1}}  /* UBIDI_REORDER_INVERSE_NUMBERS_AS_L */
4039         },
4040         { /* TC 12: 123 JIH */
4041             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
4042             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
4043             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
4044             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
4045             {{ 1,  1}, { 1,  1}}  /* UBIDI_REORDER_INVERSE_NUMBERS_AS_L */
4046         }
4047     };
4048 
4049     #define SET_ROUND_TRIP_MODE(mode) \
4050         ubidi_setReorderingMode(pBiDi, mode); \
4051         desc = #mode; \
4052         break;
4053 
4054     UErrorCode rc = U_ZERO_ERROR;
4055     UChar dest2[MAXLEN];
4056     int32_t destLen2;
4057     const char* desc;
4058     char destChars2[MAXLEN];
4059     char destChars3[MAXLEN];
4060 
4061     switch (modes[mode].value) {
4062         case UBIDI_REORDER_NUMBERS_SPECIAL:
4063             SET_ROUND_TRIP_MODE(UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL)
4064         case UBIDI_REORDER_GROUP_NUMBERS_WITH_R:
4065             SET_ROUND_TRIP_MODE(UBIDI_REORDER_GROUP_NUMBERS_WITH_R)
4066         case UBIDI_REORDER_RUNS_ONLY:
4067             SET_ROUND_TRIP_MODE(UBIDI_REORDER_RUNS_ONLY)
4068         case UBIDI_REORDER_INVERSE_NUMBERS_AS_L:
4069             SET_ROUND_TRIP_MODE(UBIDI_REORDER_DEFAULT)
4070         case UBIDI_REORDER_INVERSE_LIKE_DIRECT:
4071             SET_ROUND_TRIP_MODE(UBIDI_REORDER_DEFAULT)
4072         case UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL:
4073             SET_ROUND_TRIP_MODE(UBIDI_REORDER_NUMBERS_SPECIAL)
4074         default:
4075             SET_ROUND_TRIP_MODE(UBIDI_REORDER_INVERSE_LIKE_DIRECT)
4076     }
4077     ubidi_setReorderingOptions(pBiDi, UBIDI_OPTION_REMOVE_CONTROLS);
4078 
4079     ubidi_setPara(pBiDi, dest, destLen, level, NULL, &rc);
4080     assertSuccessful("ubidi_setPara", &rc);
4081     *dest2 = 0;
4082     destLen2 = ubidi_writeReordered(pBiDi, dest2, MAXLEN, UBIDI_DO_MIRRORING,
4083                                     &rc);
4084     assertSuccessful("ubidi_writeReordered", &rc);
4085 
4086     u16ToPseudo(destLen, dest, destChars3);
4087     u16ToPseudo(destLen2, dest2, destChars2);
4088     checkWhatYouCan(pBiDi, destChars3, destChars2);
4089     if (strcmp(srcChars, destChars2)) {
4090         if (roundtrip[tc][mode][option][level]) {
4091             log_err("\nRound trip failed for case=%d mode=%d option=%d.\n"
4092                     "%20s %s\n%20s %s\n%20s %s\n%20s %s\n%20s %s"
4093                     "\n%20s %u\n", tc, mode, option,
4094                     "Original text:", srcChars,
4095                     "Round-tripped text:", destChars2,
4096                     "Intermediate  text:", destChars3,
4097                     "Reordering mode:", modes[mode].description,
4098                     "Reordering option:", options[option].description,
4099                     "Paragraph level:", level);
4100         }
4101         else {
4102             log_verbose("\nExpected round trip failure for case=%d mode=%d option=%d.\n"
4103                     "%20s %s\n%20s %s\n%20s %s\n%20s %s\n%20s %s"
4104                     "\n%20s %u\n", tc, mode, option,
4105                     "Original text:", srcChars,
4106                     "Round-tripped text:", destChars2,
4107                     "Intermediate  text:", destChars3,
4108                     "Reordering mode:", modes[mode].description,
4109                     "Reordering option:", options[option].description,
4110                     "Paragraph level:", level);
4111         }
4112         return FALSE;
4113     }
4114     if (!checkResultLength(pBiDi, destChars, destChars2, destLen2,
4115                            desc, "UBIDI_OPTION_REMOVE_CONTROLS", level)) {
4116         return FALSE;
4117     }
4118     if (outIndex > -1 && !checkMaps(pBiDi, outIndex, srcChars, destChars,
4119                                     desc, "UBIDI_OPTION_REMOVE_CONTROLS",
4120                                     level, FALSE)) {
4121         return FALSE;
4122     }
4123     return TRUE;
4124 }
4125 
4126 static UBool
checkResultLength(UBiDi * pBiDi,const char * srcChars,const char * destChars,int32_t destLen,const char * mode,const char * option,UBiDiLevel level)4127 checkResultLength(UBiDi *pBiDi, const char *srcChars, const char *destChars,
4128                   int32_t destLen, const char* mode,
4129                   const char* option, UBiDiLevel level) {
4130     int32_t actualLen;
4131     if (strcmp(mode, "UBIDI_REORDER_INVERSE_NUMBERS_AS_L") == 0)
4132         actualLen = (int32_t)strlen(destChars);
4133     else
4134         actualLen = ubidi_getResultLength(pBiDi);
4135     if (actualLen != destLen) {
4136         log_err("\nubidi_getResultLength failed.\n%20s %7d\n%20s %7d\n"
4137                 "%20s %s\n%20s %s\n%20s %s\n%20s %s\n%20s %u\n",
4138                 "Expected:", destLen, "Actual:", actualLen,
4139                 "Input:", srcChars, "Output:", destChars,
4140                 "Reordering mode:", mode, "Reordering option:", option,
4141                 "Paragraph level:", level);
4142         return FALSE;
4143     }
4144     return TRUE;
4145 }
4146 
4147 static void
testReorderRunsOnly(void)4148 testReorderRunsOnly(void) {
4149     static const struct {
4150         const char* textIn;
4151         const char* textOut[2][2];
4152         const char noroundtrip[2];
4153     } testCases[] = {
4154         {"ab 234 896 de", {{"de 896 ab 234", "de 896 ab 234"},                   /*0*/
4155                            {"ab 234 @896@ de", "de 896 ab 234"}}, {0, 0}},
4156         {"abcGHI", {{"GHIabc", "GHIabc"}, {"GHIabc", "GHIabc"}}, {0, 0}},        /*1*/
4157         {"a.>67->", {{"<-67<.a", "<-67<.a"}, {"<-67<.a", "<-67<.a"}}, {0, 0}},   /*2*/
4158         {"-=%$123/ *", {{"* /%$123=-", "* /%$123=-"},                            /*3*/
4159                         {"* /%$123=-", "* /%$123=-"}}, {0, 0}},
4160         {"abc->12..>JKL", {{"JKL<..12<-abc", "JKL<..abc->12"},                   /*4*/
4161                            {"JKL<..12<-abc", "JKL<..abc->12"}}, {0, 0}},
4162         {"JKL->12..>abc", {{"abc<..JKL->12", "abc<..12<-JKL"},                   /*5*/
4163                            {"abc<..JKL->12", "abc<..12<-JKL"}}, {0, 0}},
4164         {"123->abc", {{"abc<-123", "abc<-123"},                                  /*6*/
4165                       {"abc&<-123", "abc<-123"}}, {1, 0}},
4166         {"123->JKL", {{"JKL<-123", "123->JKL"},                                  /*7*/
4167                       {"JKL<-123", "JKL<-@123"}}, {0, 1}},
4168         {"*>12.>34->JKL", {{"JKL<-34<.12<*", "12.>34->JKL<*"},                   /*8*/
4169                            {"JKL<-34<.12<*", "JKL<-@34<.12<*"}}, {0, 1}},
4170         {"*>67.>89->JKL", {{"67.>89->JKL<*", "67.>89->JKL<*"},                   /*9*/
4171                            {"67.>89->JKL<*", "67.>89->JKL<*"}}, {0, 0}},
4172         {"* /abc-=$%123", {{"$%123=-abc/ *", "abc-=$%123/ *"},                   /*10*/
4173                            {"$%123=-abc/ *", "abc-=$%123/ *"}}, {0, 0}},
4174         {"* /$%def-=123", {{"123=-def%$/ *", "def-=123%$/ *"},                   /*11*/
4175                            {"123=-def%$/ *", "def-=123%$/ *"}}, {0, 0}},
4176         {"-=GHI* /123%$", {{"GHI* /123%$=-", "123%$/ *GHI=-"},                   /*12*/
4177                            {"GHI* /123%$=-", "123%$/ *GHI=-"}}, {0, 0}},
4178         {"-=%$JKL* /123", {{"JKL* /%$123=-", "123/ *JKL$%=-"},                   /*13*/
4179                            {"JKL* /%$123=-", "123/ *JKL$%=-"}}, {0, 0}},
4180         {"ab =#CD *?450", {{"CD *?450#= ab", "450?* CD#= ab"},                   /*14*/
4181                            {"CD *?450#= ab", "450?* CD#= ab"}}, {0, 0}},
4182         {"ab 234 896 de", {{"de 896 ab 234", "de 896 ab 234"},                   /*15*/
4183                            {"ab 234 @896@ de", "de 896 ab 234"}}, {0, 0}},
4184         {"abc-=%$LMN* /123", {{"LMN* /%$123=-abc", "123/ *LMN$%=-abc"},          /*16*/
4185                               {"LMN* /%$123=-abc", "123/ *LMN$%=-abc"}}, {0, 0}},
4186         {"123->JKL&MN&P", {{"JKLMNP<-123", "123->JKLMNP"},                       /*17*/
4187                            {"JKLMNP<-123", "JKLMNP<-@123"}}, {0, 1}},
4188         {"123", {{"123", "123"},                /* just one run */               /*18*/
4189                  {"123", "123"}}, {0, 0}}
4190     };
4191     UBiDi *pBiDi = getBiDiObject();
4192     UBiDi *pL2VBiDi = getBiDiObject();
4193     UChar src[MAXLEN], dest[MAXLEN], visual1[MAXLEN], visual2[MAXLEN];
4194     char destChars[MAXLEN], vis1Chars[MAXLEN], vis2Chars[MAXLEN];
4195     int32_t srcLen, destLen, vis1Len, vis2Len, option, i, j, nCases, paras;
4196     UErrorCode rc = U_ZERO_ERROR;
4197     UBiDiLevel level;
4198 
4199     log_verbose("\nEntering TestReorderRunsOnly\n\n");
4200 
4201     if(!pL2VBiDi) {
4202         ubidi_close(pBiDi);             /* in case this one was allocated */
4203         return;
4204     }
4205     ubidi_setReorderingMode(pBiDi, UBIDI_REORDER_RUNS_ONLY);
4206     ubidi_setReorderingOptions(pL2VBiDi, UBIDI_OPTION_REMOVE_CONTROLS);
4207 
4208     for (option = 0; option < 2; option++) {
4209         ubidi_setReorderingOptions(pBiDi, option==0 ? UBIDI_OPTION_REMOVE_CONTROLS
4210                                                     : UBIDI_OPTION_INSERT_MARKS);
4211         for (i = 0, nCases = UPRV_LENGTHOF(testCases); i < nCases; i++) {
4212             srcLen = (int32_t)strlen(testCases[i].textIn);
4213             pseudoToU16(srcLen, testCases[i].textIn, src);
4214             for(j = 0; j < 2; j++) {
4215                 log_verbose("Now doing test for option %d, case %d, level %d\n",
4216                             i, option, j);
4217                 level = paraLevels[j];
4218                 ubidi_setPara(pBiDi, src, srcLen, level, NULL, &rc);
4219                 assertSuccessful("ubidi_setPara", &rc);
4220                 *dest = 0;
4221                 destLen = ubidi_writeReordered(pBiDi, dest, MAXLEN, UBIDI_DO_MIRRORING, &rc);
4222                 assertSuccessful("ubidi_writeReordered", &rc);
4223                 u16ToPseudo(destLen, dest, destChars);
4224                 checkWhatYouCan(pBiDi, testCases[i].textIn, destChars);
4225                 assertStringsEqual(testCases[i].textOut[option][level], destChars,
4226                         testCases[i].textIn, "UBIDI_REORDER_RUNS_ONLY",
4227                         option==0 ? "0" : "UBIDI_OPTION_INSERT_MARKS",
4228                         pBiDi);
4229 
4230                 if((option==0) && testCases[i].noroundtrip[level]) {
4231                     continue;
4232                 }
4233                 ubidi_setPara(pL2VBiDi, src, srcLen, level, NULL, &rc);
4234                 assertSuccessful("ubidi_setPara1", &rc);
4235                 *visual1 = 0;
4236                 vis1Len = ubidi_writeReordered(pL2VBiDi, visual1, MAXLEN, UBIDI_DO_MIRRORING, &rc);
4237                 assertSuccessful("ubidi_writeReordered1", &rc);
4238                 u16ToPseudo(vis1Len, visual1, vis1Chars);
4239                 checkWhatYouCan(pL2VBiDi, testCases[i].textIn, vis1Chars);
4240                 ubidi_setPara(pL2VBiDi, dest, destLen, level^1, NULL, &rc);
4241                 assertSuccessful("ubidi_setPara2", &rc);
4242                 *visual2 = 0;
4243                 vis2Len = ubidi_writeReordered(pL2VBiDi, visual2, MAXLEN, UBIDI_DO_MIRRORING, &rc);
4244                 assertSuccessful("ubidi_writeReordered2", &rc);
4245                 u16ToPseudo(vis2Len, visual2, vis2Chars);
4246                 checkWhatYouCan(pL2VBiDi, destChars, vis2Chars);
4247                 assertStringsEqual(vis1Chars, vis2Chars,
4248                         testCases[i].textIn, "UBIDI_REORDER_RUNS_ONLY (2)",
4249                         option==0 ? "0" : "UBIDI_OPTION_INSERT_MARKS",
4250                         pBiDi);
4251             }
4252         }
4253     }
4254 
4255     /* test with null or empty text */
4256     ubidi_setPara(pBiDi, src, 0, UBIDI_LTR, NULL, &rc);
4257     assertSuccessful("ubidi_setPara3", &rc);
4258     paras = ubidi_countParagraphs(pBiDi);
4259     if (paras != 0) {
4260         log_err("\nInvalid number of paras (should be 0): %d\n", paras);
4261     }
4262 
4263     ubidi_close(pBiDi);
4264     ubidi_close(pL2VBiDi);
4265 
4266     log_verbose("\nExiting TestReorderRunsOnly\n\n");
4267 }
4268 
4269 static void
testReorderingMode(void)4270 testReorderingMode(void) {
4271 
4272     UChar src[MAXLEN], dest[MAXLEN];
4273     char destChars[MAXLEN];
4274     UBiDi *pBiDi = NULL, *pBiDi2 = NULL, *pBiDi3 = NULL;
4275     UErrorCode rc;
4276     int tc, mode, option, level;
4277     uint32_t optionValue, optionBack;
4278     UBiDiReorderingMode modeValue, modeBack;
4279     int32_t srcLen, destLen, idx;
4280     const char *expectedChars;
4281     UBool testOK = TRUE;
4282 
4283     log_verbose("\nEntering TestReorderingMode\n\n");
4284 
4285     pBiDi = getBiDiObject();
4286     pBiDi2 = getBiDiObject();
4287     pBiDi3 = getBiDiObject();
4288     if(!pBiDi3) {
4289         ubidi_close(pBiDi);             /* in case this one was allocated */
4290         ubidi_close(pBiDi2);            /* in case this one was allocated */
4291         return;
4292     }
4293 
4294     ubidi_setInverse(pBiDi2, TRUE);
4295 
4296     for (tc = 0; tc < TC_COUNT; tc++) {
4297         const char *srcChars = textIn[tc];
4298         srcLen = (int32_t)strlen(srcChars);
4299         pseudoToU16(srcLen, srcChars, src);
4300 
4301         for (mode = 0; mode < MODES_COUNT; mode++) {
4302             modeValue = modes[mode].value;
4303             ubidi_setReorderingMode(pBiDi, modeValue);
4304             modeBack = ubidi_getReorderingMode(pBiDi);
4305             if (modeValue != modeBack) {
4306                 log_err("Error while setting reordering mode to %d, returned %d\n",
4307                         modeValue, modeBack);
4308             }
4309 
4310             for (option = 0; option < OPTIONS_COUNT; option++) {
4311                 optionValue = options[option].value;
4312                 ubidi_setReorderingOptions(pBiDi, optionValue);
4313                 optionBack = ubidi_getReorderingOptions(pBiDi);
4314                 if (optionValue != optionBack) {
4315                     log_err("Error while setting reordering option to %d, returned %d\n",
4316                             optionValue, optionBack);
4317                 }
4318 
4319                 for (level = 0; level < LEVELS_COUNT; level++) {
4320                     log_verbose("starting test %d mode=%d option=%d level=%d\n",
4321                                 tc, modes[mode].value, options[option].value, level);
4322                     rc = U_ZERO_ERROR;
4323                     ubidi_setPara(pBiDi, src, srcLen, paraLevels[level], NULL, &rc);
4324                     assertSuccessful("ubidi_setPara", &rc);
4325 
4326                     *dest = 0;
4327                     destLen = ubidi_writeReordered(pBiDi, dest, MAXLEN,
4328                                                    UBIDI_DO_MIRRORING, &rc);
4329                     assertSuccessful("ubidi_writeReordered", &rc);
4330                     u16ToPseudo(destLen, dest, destChars);
4331                     if (!((modes[mode].value == UBIDI_REORDER_INVERSE_NUMBERS_AS_L) &&
4332                           (options[option].value == UBIDI_OPTION_INSERT_MARKS))) {
4333                         checkWhatYouCan(pBiDi, srcChars, destChars);
4334                     }
4335 
4336                     if (modes[mode].value == UBIDI_REORDER_INVERSE_NUMBERS_AS_L) {
4337                         idx = -1;
4338                         expectedChars = inverseBasic(pBiDi2, srcChars, srcLen,
4339                                 options[option].value, paraLevels[level], destChars);
4340                     }
4341                     else {
4342                         idx = outIndices[tc][mode][option][level];
4343                         expectedChars = textOut[idx];
4344                     }
4345                     if (!assertStringsEqual(expectedChars, destChars, srcChars,
4346                                 modes[mode].description,
4347                                 options[option].description,
4348                                 pBiDi)) {
4349                         testOK = FALSE;
4350                     }
4351                     if (options[option].value == UBIDI_OPTION_INSERT_MARKS &&
4352                              !assertRoundTrip(pBiDi3, tc, idx, srcChars,
4353                                               destChars, dest, destLen,
4354                                               mode, option, paraLevels[level])) {
4355                         testOK = FALSE;
4356                     }
4357                     else if (!checkResultLength(pBiDi, srcChars, destChars,
4358                                 destLen, modes[mode].description,
4359                                 options[option].description,
4360                                 paraLevels[level])) {
4361                         testOK = FALSE;
4362                     }
4363                     else if (idx > -1 && !checkMaps(pBiDi, idx, srcChars,
4364                             destChars, modes[mode].description,
4365                             options[option].description, paraLevels[level],
4366                             TRUE)) {
4367                         testOK = FALSE;
4368                     }
4369                 }
4370             }
4371         }
4372     }
4373     if (testOK == TRUE) {
4374         log_verbose("\nReordering mode test OK\n");
4375     }
4376     ubidi_close(pBiDi3);
4377     ubidi_close(pBiDi2);
4378     ubidi_close(pBiDi);
4379 
4380     log_verbose("\nExiting TestReorderingMode\n\n");
4381 }
4382 
inverseBasic(UBiDi * pBiDi,const char * srcChars,int32_t srcLen,uint32_t option,UBiDiLevel level,char * result)4383 static const char* inverseBasic(UBiDi *pBiDi, const char *srcChars, int32_t srcLen,
4384                                 uint32_t option, UBiDiLevel level, char *result) {
4385     UErrorCode rc = U_ZERO_ERROR;
4386     int32_t destLen;
4387     UChar src[MAXLEN], dest2[MAXLEN];
4388 
4389     if (pBiDi == NULL || srcChars == NULL) {
4390         return NULL;
4391     }
4392     ubidi_setReorderingOptions(pBiDi, option);
4393     pseudoToU16(srcLen, srcChars, src);
4394     ubidi_setPara(pBiDi, src, srcLen, level, NULL, &rc);
4395     assertSuccessful("ubidi_setPara", &rc);
4396 
4397     *dest2 = 0;
4398     destLen = ubidi_writeReordered(pBiDi, dest2, MAXLEN,
4399                                    UBIDI_DO_MIRRORING, &rc);
4400     assertSuccessful("ubidi_writeReordered", &rc);
4401     u16ToPseudo(destLen, dest2, result);
4402     if (!(option == UBIDI_OPTION_INSERT_MARKS)) {
4403         checkWhatYouCan(pBiDi, srcChars, result);
4404     }
4405     return result;
4406 }
4407 
4408 #define NULL_CHAR '\0'
4409 
4410 static void
testStreaming(void)4411 testStreaming(void) {
4412 #define MAXPORTIONS 10
4413 
4414     static const struct {
4415         const char* textIn;
4416         short int chunk;
4417         short int nPortions[2];
4418         char  portionLens[2][MAXPORTIONS];
4419         const char* message[2];
4420     } testData[] = {
4421         {   "123\\u000A"
4422             "abc45\\u000D"
4423             "67890\\u000A"
4424             "\\u000D"
4425             "02468\\u000D"
4426             "ghi",
4427             6, { 6, 6 }, {{ 4, 6, 6, 1, 6, 3}, { 4, 6, 6, 1, 6, 3 }},
4428             {"4, 6, 6, 1, 6, 3", "4, 6, 6, 1, 6, 3"}
4429         },
4430         {   "abcd\\u000Afgh\\u000D12345\\u000A456",
4431             6, { 4, 4 }, {{ 5, 4, 6, 3 }, { 5, 4, 6, 3 }},
4432             {"5, 4, 6, 3", "5, 4, 6, 3"}
4433         },
4434         {   "abcd\\u000Afgh\\u000D12345\\u000A45\\u000D",
4435             6, { 4, 4 }, {{ 5, 4, 6, 3 }, { 5, 4, 6, 3 }},
4436             {"5, 4, 6, 3", "5, 4, 6, 3"}
4437         },
4438         {   "abcde\\u000Afghi",
4439             10, { 2, 2 }, {{ 6, 4 }, { 6, 4 }},
4440             {"6, 4", "6, 4"}
4441         }
4442     };
4443     UChar src[MAXLEN];
4444     UBiDi *pBiDi = NULL;
4445     UChar *pSrc;
4446     UErrorCode rc = U_ZERO_ERROR;
4447     int32_t srcLen, processedLen, chunk, len, nPortions;
4448     int i, j, levelIndex;
4449     UBiDiLevel level;
4450     int nTests = UPRV_LENGTHOF(testData), nLevels = UPRV_LENGTHOF(paraLevels);
4451     UBool mismatch, testOK = TRUE;
4452    char processedLenStr[MAXPORTIONS * 5];
4453 
4454     log_verbose("\nEntering TestStreaming\n\n");
4455 
4456     pBiDi = getBiDiObject();
4457 
4458     ubidi_orderParagraphsLTR(pBiDi, TRUE);
4459 
4460     for (levelIndex = 0; levelIndex < nLevels; levelIndex++) {
4461         for (i = 0; i < nTests; i++) {
4462             srcLen = u_unescape(testData[i].textIn, src, MAXLEN);
4463             chunk = testData[i].chunk;
4464             nPortions = testData[i].nPortions[levelIndex];
4465             level = paraLevels[levelIndex];
4466             processedLenStr[0] = NULL_CHAR;
4467             log_verbose("Testing level %d, case %d\n", level, i);
4468 
4469             mismatch = FALSE;
4470 
4471             ubidi_setReorderingOptions(pBiDi, UBIDI_OPTION_STREAMING);
4472             for (j = 0, pSrc = src; j < MAXPORTIONS && srcLen > 0; j++) {
4473 
4474                 len = chunk < srcLen ? chunk : srcLen;
4475                 ubidi_setPara(pBiDi, pSrc, len, level, NULL, &rc);
4476                 if (!assertSuccessful("ubidi_setPara", &rc)) {
4477                     break;
4478                 }
4479 
4480                 processedLen = ubidi_getProcessedLength(pBiDi);
4481                 if (processedLen == 0) {
4482                     ubidi_setReorderingOptions(pBiDi, UBIDI_OPTION_DEFAULT);
4483                     j--;
4484                     continue;
4485                 }
4486                 ubidi_setReorderingOptions(pBiDi, UBIDI_OPTION_STREAMING);
4487 
4488                 mismatch |= (UBool)(j >= nPortions ||
4489                            processedLen != testData[i].portionLens[levelIndex][j]);
4490 
4491                 sprintf(processedLenStr + j * 4, "%4d", processedLen);
4492                 srcLen -= processedLen, pSrc += processedLen;
4493             }
4494 
4495             if (mismatch || j != nPortions) {
4496                 testOK = FALSE;
4497                 log_err("\nProcessed lengths mismatch.\n"
4498                     "\tParagraph level: %u\n"
4499                     "\tInput string: %s\n"
4500                     "\tActually processed portion lengths: { %s }\n"
4501                     "\tExpected portion lengths          : { %s }\n",
4502                     paraLevels[levelIndex], testData[i].textIn,
4503                     processedLenStr, testData[i].message[levelIndex]);
4504             }
4505         }
4506     }
4507     ubidi_close(pBiDi);
4508     if (testOK == TRUE) {
4509         log_verbose("\nBiDi streaming test OK\n");
4510     }
4511     log_verbose("\nExiting TestStreaming\n\n");
4512 }
4513 
4514 U_CDECL_BEGIN
4515 
4516 static UCharDirection U_CALLCONV
overrideBidiClass(const void * context,UChar32 c)4517 overrideBidiClass(const void *context, UChar32 c) {
4518 
4519 #define DEF U_BIDI_CLASS_DEFAULT
4520 
4521     static const UCharDirection customClasses[] = {
4522        /* 0/8    1/9    2/A    3/B    4/C    5/D    6/E    7/F  */
4523           DEF,   DEF,   DEF,   DEF,   DEF,   DEF,   DEF,   DEF, /* 00-07 */
4524           DEF,   DEF,   DEF,   DEF,   DEF,   DEF,   DEF,   DEF, /* 08-0F */
4525           DEF,   DEF,   DEF,   DEF,   DEF,   DEF,   DEF,   DEF, /* 10-17 */
4526           DEF,   DEF,   DEF,   DEF,   DEF,   DEF,   DEF,   DEF, /* 18-1F */
4527           DEF,   DEF,   DEF,   DEF,   DEF,   DEF,     R,   DEF, /* 20-27 */
4528           DEF,   DEF,   DEF,   DEF,   DEF,   DEF,   DEF,   DEF, /* 28-2F */
4529            EN,    EN,    EN,    EN,    EN,    EN,    AN,    AN, /* 30-37 */
4530            AN,    AN,   DEF,   DEF,   DEF,   DEF,   DEF,   DEF, /* 38-3F */
4531             L,    AL,    AL,    AL,    AL,    AL,    AL,     R, /* 40-47 */
4532             R,     R,     R,     R,     R,     R,     R,     R, /* 48-4F */
4533             R,     R,     R,     R,     R,     R,     R,     R, /* 50-57 */
4534             R,     R,     R,   LRE,   DEF,   RLE,   PDF,     S, /* 58-5F */
4535           NSM,   DEF,   DEF,   DEF,   DEF,   DEF,   DEF,   DEF, /* 60-67 */
4536           DEF,   DEF,   DEF,   DEF,   DEF,   DEF,   DEF,   DEF, /* 68-6F */
4537           DEF,   DEF,   DEF,   DEF,   DEF,   DEF,   DEF,   DEF, /* 70-77 */
4538           DEF,   DEF,   DEF,   LRO,     B,   RLO,    BN,   DEF  /* 78-7F */
4539     };
4540     static const int nEntries = UPRV_LENGTHOF(customClasses);
4541     const char *dummy = context;        /* just to avoid a compiler warning */
4542     dummy++;
4543 
4544     return c >= nEntries ? U_BIDI_CLASS_DEFAULT : customClasses[c];
4545 }
4546 
4547 U_CDECL_END
4548 
verifyCallbackParams(UBiDiClassCallback * fn,const void * context,UBiDiClassCallback * expectedFn,const void * expectedContext,int32_t sizeOfContext)4549 static void verifyCallbackParams(UBiDiClassCallback* fn, const void* context,
4550                                  UBiDiClassCallback* expectedFn,
4551                                  const void* expectedContext,
4552                                  int32_t sizeOfContext) {
4553     if (fn != expectedFn) {
4554         log_err("Class callback pointer is not set properly.\n");
4555     }
4556     if (context != expectedContext) {
4557         log_err("Class callback context is not set properly.\n");
4558     }
4559     else if (context != NULL &&
4560             memcmp(context, expectedContext, sizeOfContext)) {
4561         log_err("Callback context content doesn't match the expected one.\n");
4562     }
4563 }
4564 
4565 static void
testClassOverride(void)4566 testClassOverride(void) {
4567     static const char* const textSrc  = "JIH.>12->a \\u05D0\\u05D1 6 ABC78";
4568     static const char* const textResult = "12<.HIJ->a 78CBA 6 \\u05D1\\u05D0";
4569 
4570     UChar src[MAXLEN], dest[MAXLEN];
4571     UErrorCode rc = U_ZERO_ERROR;
4572     UBiDi *pBiDi = NULL;
4573     UBiDiClassCallback* oldFn = NULL;
4574     UBiDiClassCallback* newFn = overrideBidiClass;
4575     const void* oldContext = NULL;
4576     int32_t srcLen, destLen, textSrcSize = (int32_t)uprv_strlen(textSrc);
4577     char* destChars = NULL;
4578 
4579     log_verbose("\nEntering TestClassOverride\n\n");
4580 
4581     pBiDi = getBiDiObject();
4582     if(!pBiDi) {
4583         return;
4584     }
4585 
4586     ubidi_getClassCallback(pBiDi, &oldFn, &oldContext);
4587     verifyCallbackParams(oldFn, oldContext, NULL, NULL, 0);
4588 
4589     ubidi_setClassCallback(pBiDi, newFn, textSrc, &oldFn, &oldContext, &rc);
4590     if (!assertSuccessful("ubidi_setClassCallback", &rc)) {
4591         ubidi_close(pBiDi);
4592         return;
4593     }
4594     verifyCallbackParams(oldFn, oldContext, NULL, NULL, 0);
4595 
4596     ubidi_getClassCallback(pBiDi, &oldFn, &oldContext);
4597     verifyCallbackParams(oldFn, oldContext, newFn, textSrc, textSrcSize);
4598 
4599     ubidi_setClassCallback(pBiDi, newFn, textSrc, &oldFn, &oldContext, &rc);
4600     if (!assertSuccessful("ubidi_setClassCallback", &rc)) {
4601         ubidi_close(pBiDi);
4602         return;
4603     }
4604     verifyCallbackParams(oldFn, oldContext, newFn, textSrc, textSrcSize);
4605 
4606     srcLen = u_unescape(textSrc, src, MAXLEN);
4607     ubidi_setPara(pBiDi, src, srcLen, UBIDI_LTR, NULL, &rc);
4608     assertSuccessful("ubidi_setPara", &rc);
4609 
4610     destLen = ubidi_writeReordered(pBiDi, dest, MAXLEN,
4611                                    UBIDI_DO_MIRRORING, &rc);
4612     assertSuccessful("ubidi_writeReordered", &rc);
4613 
4614     destChars = aescstrdup(dest, destLen);
4615     if (uprv_strcmp(textResult, destChars)) {
4616         log_err("\nActual and expected output mismatch.\n"
4617             "%20s %s\n%20s %s\n%20s %s\n",
4618             "Input:", textSrc, "Actual output:", destChars,
4619             "Expected output:", textResult);
4620     }
4621     else {
4622         log_verbose("\nClass override test OK\n");
4623     }
4624     ubidi_close(pBiDi);
4625     log_verbose("\nExiting TestClassOverride\n\n");
4626 }
4627 
formatMap(const int32_t * map,int len,char * buffer)4628 static char * formatMap(const int32_t * map, int len, char * buffer)
4629 {
4630     int32_t i, k;
4631     char c;
4632     for (i = 0; i < len; i++) {
4633         k = map[i];
4634         if (k < 0)
4635             c = '-';
4636         else if (k >= (int32_t)sizeof(columns))
4637             c = '+';
4638         else
4639             c = columns[k];
4640         buffer[i] = c;
4641     }
4642     buffer[len] = '\0';
4643     return buffer;
4644 }
4645 
4646 static UBool
checkMaps(UBiDi * pBiDi,int32_t stringIndex,const char * src,const char * dest,const char * mode,const char * option,UBiDiLevel level,UBool forward)4647 checkMaps(UBiDi *pBiDi, int32_t stringIndex, const char *src, const char *dest,
4648           const char *mode, const char* option, UBiDiLevel level, UBool forward)
4649 {
4650     int32_t actualLogicalMap[MAX_MAP_LENGTH];
4651     int32_t actualVisualMap[MAX_MAP_LENGTH];
4652     int32_t getIndexMap[MAX_MAP_LENGTH];
4653     int32_t i, srcLen, resLen, idx;
4654     const int32_t *expectedLogicalMap, *expectedVisualMap;
4655     UErrorCode rc = U_ZERO_ERROR;
4656     UBool testOK = TRUE;
4657 
4658     if (forward) {
4659         expectedLogicalMap = forwardMap[stringIndex];
4660         expectedVisualMap  = inverseMap[stringIndex];
4661     }
4662     else {
4663         expectedLogicalMap = inverseMap[stringIndex];
4664         expectedVisualMap  = forwardMap[stringIndex];
4665     }
4666     ubidi_getLogicalMap(pBiDi, actualLogicalMap, &rc);
4667     if (!assertSuccessful("ubidi_getLogicalMap", &rc)) {
4668         testOK = FALSE;
4669     }
4670     srcLen = ubidi_getProcessedLength(pBiDi);
4671     if (memcmp(expectedLogicalMap, actualLogicalMap, srcLen * sizeof(int32_t))) {
4672         char expChars[MAX_MAP_LENGTH];
4673         char actChars[MAX_MAP_LENGTH];
4674         log_err("\nubidi_getLogicalMap() returns unexpected map for output string "
4675                 "index %d\n"
4676                 "source: %s\n"
4677                 "dest  : %s\n"
4678                 "Scale : %s\n"
4679                 "ExpMap: %s\n"
4680                 "Actual: %s\n"
4681                 "Paragraph level  : %d == %d\n"
4682                 "Reordering mode  : %s == %d\n"
4683                 "Reordering option: %s == %d\n"
4684                 "Forward flag     : %d\n",
4685                 stringIndex, src, dest, columns,
4686                 formatMap(expectedLogicalMap, srcLen, expChars),
4687                 formatMap(actualLogicalMap, srcLen, actChars),
4688                 level, ubidi_getParaLevel(pBiDi),
4689                 mode, ubidi_getReorderingMode(pBiDi),
4690                 option, ubidi_getReorderingOptions(pBiDi),
4691                 forward
4692                 );
4693         testOK = FALSE;
4694     }
4695     resLen = ubidi_getResultLength(pBiDi);
4696     ubidi_getVisualMap(pBiDi, actualVisualMap, &rc);
4697     assertSuccessful("ubidi_getVisualMap", &rc);
4698     if (memcmp(expectedVisualMap, actualVisualMap, resLen * sizeof(int32_t))) {
4699         char expChars[MAX_MAP_LENGTH];
4700         char actChars[MAX_MAP_LENGTH];
4701         log_err("\nubidi_getVisualMap() returns unexpected map for output string "
4702                 "index %d\n"
4703                 "source: %s\n"
4704                 "dest  : %s\n"
4705                 "Scale : %s\n"
4706                 "ExpMap: %s\n"
4707                 "Actual: %s\n"
4708                 "Paragraph level  : %d == %d\n"
4709                 "Reordering mode  : %s == %d\n"
4710                 "Reordering option: %s == %d\n"
4711                 "Forward flag     : %d\n",
4712                 stringIndex, src, dest, columns,
4713                 formatMap(expectedVisualMap, resLen, expChars),
4714                 formatMap(actualVisualMap, resLen, actChars),
4715                 level, ubidi_getParaLevel(pBiDi),
4716                 mode, ubidi_getReorderingMode(pBiDi),
4717                 option, ubidi_getReorderingOptions(pBiDi),
4718                 forward
4719                 );
4720         testOK = FALSE;
4721     }
4722     for (i = 0; i < srcLen; i++) {
4723         idx = ubidi_getVisualIndex(pBiDi, i, &rc);
4724         assertSuccessful("ubidi_getVisualIndex", &rc);
4725         getIndexMap[i] = idx;
4726     }
4727     if (memcmp(actualLogicalMap, getIndexMap, srcLen * sizeof(int32_t))) {
4728         char actChars[MAX_MAP_LENGTH];
4729         char gotChars[MAX_MAP_LENGTH];
4730         log_err("\nMismatch between ubidi_getLogicalMap and ubidi_getVisualIndex for output string "
4731                 "index %d\n"
4732                 "source: %s\n"
4733                 "dest  : %s\n"
4734                 "Scale : %s\n"
4735                 "ActMap: %s\n"
4736                 "IdxMap: %s\n"
4737                 "Paragraph level  : %d == %d\n"
4738                 "Reordering mode  : %s == %d\n"
4739                 "Reordering option: %s == %d\n"
4740                 "Forward flag     : %d\n",
4741                 stringIndex, src, dest, columns,
4742                 formatMap(actualLogicalMap, srcLen, actChars),
4743                 formatMap(getIndexMap, srcLen, gotChars),
4744                 level, ubidi_getParaLevel(pBiDi),
4745                 mode, ubidi_getReorderingMode(pBiDi),
4746                 option, ubidi_getReorderingOptions(pBiDi),
4747                 forward
4748                 );
4749         testOK = FALSE;
4750     }
4751     for (i = 0; i < resLen; i++) {
4752         idx = ubidi_getLogicalIndex(pBiDi, i, &rc);
4753         assertSuccessful("ubidi_getLogicalIndex", &rc);
4754         getIndexMap[i] = idx;
4755     }
4756     if (memcmp(actualVisualMap, getIndexMap, resLen * sizeof(int32_t))) {
4757         char actChars[MAX_MAP_LENGTH];
4758         char gotChars[MAX_MAP_LENGTH];
4759         log_err("\nMismatch between ubidi_getVisualMap and ubidi_getLogicalIndex for output string "
4760                 "index %d\n"
4761                 "source: %s\n"
4762                 "dest  : %s\n"
4763                 "Scale : %s\n"
4764                 "ActMap: %s\n"
4765                 "IdxMap: %s\n"
4766                 "Paragraph level  : %d == %d\n"
4767                 "Reordering mode  : %s == %d\n"
4768                 "Reordering option: %s == %d\n"
4769                 "Forward flag     : %d\n",
4770                 stringIndex, src, dest, columns,
4771                 formatMap(actualVisualMap, resLen, actChars),
4772                 formatMap(getIndexMap, resLen, gotChars),
4773                 level, ubidi_getParaLevel(pBiDi),
4774                 mode, ubidi_getReorderingMode(pBiDi),
4775                 option, ubidi_getReorderingOptions(pBiDi),
4776                 forward
4777                 );
4778         testOK = FALSE;
4779     }
4780     return testOK;
4781 }
4782 
4783 static UBool
assertIllegalArgument(const char * message,UErrorCode * rc)4784 assertIllegalArgument(const char* message, UErrorCode* rc) {
4785     if (*rc != U_ILLEGAL_ARGUMENT_ERROR) {
4786         log_err("%s() failed with error %s.\n", message, myErrorName(*rc));
4787         return FALSE;
4788     }
4789     return TRUE;
4790 }
4791 
4792 typedef struct {
4793     const char* prologue;
4794     const char* source;
4795     const char* epilogue;
4796     const char* expected;
4797     UBiDiLevel paraLevel;
4798 } contextCase;
4799 
4800 static const contextCase contextData[] = {
4801     /*00*/  {"", "", "", "", UBIDI_LTR},
4802     /*01*/  {"", ".-=JKL-+*", "", ".-=LKJ-+*", UBIDI_LTR},
4803     /*02*/  {" ", ".-=JKL-+*", " ", ".-=LKJ-+*", UBIDI_LTR},
4804     /*03*/  {"a", ".-=JKL-+*", "b", ".-=LKJ-+*", UBIDI_LTR},
4805     /*04*/  {"D", ".-=JKL-+*", "", "LKJ=-.-+*", UBIDI_LTR},
4806     /*05*/  {"", ".-=JKL-+*", " D", ".-=*+-LKJ", UBIDI_LTR},
4807     /*06*/  {"", ".-=JKL-+*", " 2", ".-=*+-LKJ", UBIDI_LTR},
4808     /*07*/  {"", ".-=JKL-+*", " 7", ".-=*+-LKJ", UBIDI_LTR},
4809     /*08*/  {" G 1", ".-=JKL-+*", " H", "*+-LKJ=-.", UBIDI_LTR},
4810     /*09*/  {"7", ".-=JKL-+*", " H", ".-=*+-LKJ", UBIDI_LTR},
4811     /*10*/  {"", ".-=abc-+*", "", "*+-abc=-.", UBIDI_RTL},
4812     /*11*/  {" ", ".-=abc-+*", " ", "*+-abc=-.", UBIDI_RTL},
4813     /*12*/  {"D", ".-=abc-+*", "G", "*+-abc=-.", UBIDI_RTL},
4814     /*13*/  {"x", ".-=abc-+*", "", "*+-.-=abc", UBIDI_RTL},
4815     /*14*/  {"", ".-=abc-+*", " y", "abc-+*=-.", UBIDI_RTL},
4816     /*15*/  {"", ".-=abc-+*", " 2", "abc-+*=-.", UBIDI_RTL},
4817     /*16*/  {" x 1", ".-=abc-+*", " 2", ".-=abc-+*", UBIDI_RTL},
4818     /*17*/  {" x 7", ".-=abc-+*", " 8", "*+-.-=abc", UBIDI_RTL},
4819     /*18*/  {"x|", ".-=abc-+*", " 8", "*+-abc=-.", UBIDI_RTL},
4820     /*19*/  {"G|y", ".-=abc-+*", " 8", "*+-.-=abc", UBIDI_RTL},
4821     /*20*/  {"", ".-=", "", ".-=", UBIDI_DEFAULT_LTR},
4822     /*21*/  {"D", ".-=", "", "=-.", UBIDI_DEFAULT_LTR},
4823     /*22*/  {"G", ".-=", "", "=-.", UBIDI_DEFAULT_LTR},
4824     /*23*/  {"xG", ".-=", "", ".-=", UBIDI_DEFAULT_LTR},
4825     /*24*/  {"x|G", ".-=", "", "=-.", UBIDI_DEFAULT_LTR},
4826     /*25*/  {"x|G", ".-=|-+*", "", "=-.|-+*", UBIDI_DEFAULT_LTR},
4827 };
4828 #define CONTEXT_COUNT       UPRV_LENGTHOF(contextData)
4829 
4830 static void
testContext(void)4831 testContext(void) {
4832 
4833     UChar prologue[MAXLEN], epilogue[MAXLEN], src[MAXLEN], dest[MAXLEN];
4834     char destChars[MAXLEN];
4835     UBiDi *pBiDi = NULL;
4836     UErrorCode rc;
4837     int32_t proLength, epiLength, srcLen, destLen, tc;
4838     contextCase cc;
4839     UBool testOK = TRUE;
4840 
4841     log_verbose("\nEntering TestContext \n\n");
4842 
4843     /* test null BiDi object */
4844     rc = U_ZERO_ERROR;
4845     ubidi_setContext(pBiDi, NULL, 0, NULL, 0, &rc);
4846     testOK &= assertIllegalArgument("Error when BiDi object is null", &rc);
4847 
4848     pBiDi = getBiDiObject();
4849     ubidi_orderParagraphsLTR(pBiDi, TRUE);
4850 
4851     /* test proLength < -1 */
4852     rc = U_ZERO_ERROR;
4853     ubidi_setContext(pBiDi, NULL, -2, NULL, 0, &rc);
4854     testOK &= assertIllegalArgument("Error when proLength < -1", &rc);
4855     /* test epiLength < -1 */
4856     rc = U_ZERO_ERROR;
4857     ubidi_setContext(pBiDi, NULL, 0, NULL, -2, &rc);
4858     testOK &= assertIllegalArgument("Error when epiLength < -1", &rc);
4859     /* test prologue == NULL */
4860     rc = U_ZERO_ERROR;
4861     ubidi_setContext(pBiDi, NULL, 3, NULL, 0, &rc);
4862     testOK &= assertIllegalArgument("Prologue is NULL", &rc);
4863     /* test epilogue == NULL */
4864     rc = U_ZERO_ERROR;
4865     ubidi_setContext(pBiDi, NULL, 0, NULL, 4, &rc);
4866     testOK &= assertIllegalArgument("Epilogue is NULL", &rc);
4867 
4868     for (tc = 0; tc < CONTEXT_COUNT; tc++) {
4869         cc = contextData[tc];
4870         proLength = (int32_t)strlen(cc.prologue);
4871         pseudoToU16(proLength, cc.prologue, prologue);
4872         epiLength = (int32_t)strlen(cc.epilogue);
4873         pseudoToU16(epiLength, cc.epilogue, epilogue);
4874         /* in the call below, prologue and epilogue are swapped to show
4875            that the next call will override this call */
4876         rc = U_ZERO_ERROR;
4877         ubidi_setContext(pBiDi, epilogue, epiLength, prologue, proLength, &rc);
4878         testOK &= assertSuccessful("swapped ubidi_setContext", &rc);
4879         ubidi_setContext(pBiDi, prologue, -1, epilogue, -1, &rc);
4880         testOK &= assertSuccessful("regular ubidi_setContext", &rc);
4881         srcLen = (int32_t)strlen(cc.source);
4882         pseudoToU16(srcLen, cc.source, src);
4883         ubidi_setPara(pBiDi, src, srcLen, cc.paraLevel, NULL, &rc);
4884         testOK &= assertSuccessful("ubidi_setPara", &rc);
4885         destLen = ubidi_writeReordered(pBiDi, dest, MAXLEN, UBIDI_DO_MIRRORING, &rc);
4886         assertSuccessful("ubidi_writeReordered", &rc);
4887         u16ToPseudo(destLen, dest, destChars);
4888         if (uprv_strcmp(cc.expected, destChars)) {
4889             char formatChars[MAXLEN];
4890             log_err("\nActual and expected output mismatch on case %d.\n"
4891                 "%20s %s\n%20s %s\n%20s %s\n%20s %s\n%20s %s\n%20s %s\n%20s %d\n%20s %u\n%20s %d\n",
4892                 tc,
4893                 "Prologue:", cc.prologue,
4894                 "Input:", cc.source,
4895                 "Epilogue:", cc.epilogue,
4896                 "Expected output:", cc.expected,
4897                 "Actual output:", destChars,
4898                 "Levels:", formatLevels(pBiDi, formatChars),
4899                 "Reordering mode:", ubidi_getReorderingMode(pBiDi),
4900                 "Paragraph level:", ubidi_getParaLevel(pBiDi),
4901                 "Reordering option:", ubidi_getReorderingOptions(pBiDi));
4902             testOK = FALSE;
4903         }
4904     }
4905     if (testOK == TRUE) {
4906         log_verbose("\nContext test OK\n");
4907     }
4908     ubidi_close(pBiDi);
4909 
4910     log_verbose("\nExiting TestContext \n\n");
4911 }
4912 
4913 /* Ticket#11054 ubidi_setPara crash with heavily nested brackets */
4914 static void
testBracketOverflow(void)4915 testBracketOverflow(void) {
4916     static const char* TEXT = "(((((((((((((((((((((((((((((((((((((((((a)(A)))))))))))))))))))))))))))))))))))))))))";
4917     UErrorCode status = U_ZERO_ERROR;
4918     UBiDi* bidi;
4919     UChar src[100];
4920     int32_t len;
4921 
4922     bidi = ubidi_open();
4923     len = (int32_t)uprv_strlen(TEXT);
4924     pseudoToU16(len, TEXT, src);
4925     ubidi_setPara(bidi, src, len, UBIDI_DEFAULT_LTR , NULL, &status);
4926     if (U_FAILURE(status)) {
4927         log_err("setPara failed with heavily nested brackets - %s", u_errorName(status));
4928     }
4929 
4930     ubidi_close(bidi);
4931 }
4932 
TestExplicitLevel0(void)4933 static void TestExplicitLevel0(void) {
4934     // The following used to fail with an error, see ICU ticket #12922.
4935     static const UChar text[2] = { 0x202d, 0x05d0 };
4936     static UBiDiLevel embeddings[2] = { 0, 0 };
4937     UErrorCode errorCode = U_ZERO_ERROR;
4938     UBiDi *bidi = ubidi_open();
4939     ubidi_setPara(bidi, text, 2, UBIDI_DEFAULT_LTR , embeddings, &errorCode);
4940     if (U_FAILURE(errorCode)) {
4941         log_err("ubidi_setPara() - %s", u_errorName(errorCode));
4942     } else {
4943         UBiDiLevel level0 = ubidi_getLevelAt(bidi, 0);
4944         UBiDiLevel level1 = ubidi_getLevelAt(bidi, 1);
4945         if (level0 != 1 || level1 != 1) {
4946             log_err("resolved levels != 1: { %d, %d }\n", level0, level1);
4947         }
4948         if (embeddings[0] != 1 || embeddings[1] != 1) {
4949             log_err("modified embeddings[] levels != 1: { %d, %d }\n", embeddings[0], embeddings[1]);
4950         }
4951     }
4952     ubidi_close(bidi);
4953 }
4954