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