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