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