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