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