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