• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(void);
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     int32_t len = ubidi_getLength(bidi);
402     char c;
403     int32_t 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 >= (int32_t)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 = (int)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) UPRV_BLOCK_MACRO_BEGIN { \
1291     if (U_FAILURE(errorCode)) {      \
1292         log_err("\nbad errorCode %d at %s\n", errorCode, (x));  \
1293         return;     \
1294     }               \
1295 } UPRV_BLOCK_MACRO_END
1296 
1297 #define STRING_TEST_CASE(s) { (s), UPRV_LENGTHOF(s) }
1298 
testGetBaseDirection(void)1299 static void testGetBaseDirection(void) {
1300     UBiDiDirection dir;
1301     int i;
1302 
1303 /* Test Data */
1304     static const UChar
1305 /*Mixed Start with L*/
1306     stringMixedEnglishFirst[]={ 0x61, 0x627, 0x32, 0x6f3, 0x61, 0x34, 0 },
1307 /*Mixed Start with AL*/
1308     stringMixedArabicFirst[]={ 0x661, 0x627, 0x662, 0x6f3, 0x61, 0x664, 0 },
1309 /*Mixed Start with R*/
1310     stringMixedHebrewFirst[]={ 0x05EA, 0x627, 0x662, 0x6f3, 0x61, 0x664, 0 },
1311 /*All AL (Arabic. Persian)*/
1312     stringPersian[]={0x0698, 0x067E, 0x0686, 0x06AF, 0},
1313 /*All R (Hebrew etc.)*/
1314     stringHebrew[]={0x0590, 0x05D5, 0x05EA, 0x05F1, 0},
1315 /*All L (English)*/
1316     stringEnglish[]={0x71, 0x61, 0x66, 0},
1317 /*Mixed Start with weak AL an then L*/
1318     stringStartWeakAL[]={ 0x0663, 0x71, 0x61, 0x66, 0},
1319 /*Mixed Start with weak L and then AL*/
1320     stringStartWeakL[]={0x31, 0x0698, 0x067E, 0x0686, 0x06AF, 0},
1321 /*Empty*/
1322     stringEmpty[]={0},
1323 /*Surrogate Char.*/
1324     stringSurrogateChar[]={0xD800, 0xDC00, 0},
1325 /*Invalid UChar*/
1326     stringInvalidUchar[]={-1},
1327 /*All weak L (English Digits)*/
1328     stringAllEnglishDigits[]={0x31, 0x32, 0x33, 0},
1329 /*All weak AL (Arabic Digits)*/
1330     stringAllArabicDigits[]={0x0663, 0x0664, 0x0665, 0},
1331 /*First L (English) others are R (Hebrew etc.) */
1332     stringFirstL[] = {0x71, 0x0590, 0x05D5, 0x05EA, 0x05F1, 0},
1333 /*Last R (Hebrew etc.) others are weak L (English Digits)*/
1334     stringLastR[] = {0x31, 0x32, 0x33, 0x05F1, 0};
1335 
1336     static const struct {
1337         const UChar *s;
1338         int32_t length;
1339     } testCases[]={
1340         STRING_TEST_CASE(stringMixedEnglishFirst),
1341         STRING_TEST_CASE(stringMixedArabicFirst),
1342         STRING_TEST_CASE(stringMixedHebrewFirst),
1343         STRING_TEST_CASE(stringPersian),
1344         STRING_TEST_CASE(stringHebrew),
1345         STRING_TEST_CASE(stringEnglish),
1346         STRING_TEST_CASE(stringStartWeakAL),
1347         STRING_TEST_CASE(stringStartWeakL),
1348         STRING_TEST_CASE(stringEmpty),
1349         STRING_TEST_CASE(stringSurrogateChar),
1350         STRING_TEST_CASE(stringInvalidUchar),
1351         STRING_TEST_CASE(stringAllEnglishDigits),
1352         STRING_TEST_CASE(stringAllArabicDigits),
1353         STRING_TEST_CASE(stringFirstL),
1354         STRING_TEST_CASE(stringLastR),
1355     };
1356 
1357 /* Expected results */
1358     static const UBiDiDirection expectedDir[] ={
1359         UBIDI_LTR, UBIDI_RTL, UBIDI_RTL,
1360         UBIDI_RTL, UBIDI_RTL, UBIDI_LTR,
1361         UBIDI_LTR, UBIDI_RTL, UBIDI_NEUTRAL,
1362         UBIDI_LTR, UBIDI_NEUTRAL, UBIDI_NEUTRAL,
1363         UBIDI_NEUTRAL, UBIDI_LTR, UBIDI_RTL
1364     };
1365 
1366     log_verbose("testGetBaseDirection() with %u test cases ---\n",
1367     UPRV_LENGTHOF(testCases));
1368 /* Run Tests */
1369      for(i=0; i<UPRV_LENGTHOF(testCases); ++i) {
1370         dir = ubidi_getBaseDirection(testCases[i].s, testCases[i].length );
1371         log_verbose("Testing case %d\tReceived dir %d\n", i, dir);
1372         if (dir != expectedDir[i])
1373             log_err("\nFailed getBaseDirection case %d Expected  %d \tReceived %d\n",
1374             i, expectedDir[i], dir);
1375     }
1376 
1377 /* Misc. tests */
1378 /* NULL string */
1379     dir = ubidi_getBaseDirection(NULL, 3);
1380     if (dir != UBIDI_NEUTRAL )
1381         log_err("\nFailed getBaseDirection for NULL string " ,
1382         "\nExpected  %d \nReceived %d", UBIDI_NEUTRAL, dir);
1383 /*All L- English string and length=-3 */
1384     dir = ubidi_getBaseDirection( stringEnglish, -3);
1385     if (dir != UBIDI_NEUTRAL )
1386         log_err("\nFailed getBaseDirection for string w length= -3 ",
1387         "\nExpected  %d \nReceived %d", UBIDI_NEUTRAL, dir);
1388 /*All L- English string and length=-1 */
1389     dir = ubidi_getBaseDirection( stringEnglish, -1);
1390     if (dir != UBIDI_LTR )
1391         log_err("\nFailed getBaseDirection for English string w length= -1 ",
1392         "\nExpected  %d \nReceived %d", UBIDI_LTR, dir);
1393 /*All AL- Persian string and length=-1 */
1394     dir = ubidi_getBaseDirection( stringPersian, -1);
1395     if (dir != UBIDI_RTL )
1396         log_err("\nFailed getBaseDirection for Persian string w length= -1 ",
1397         "\nExpected  %d \nReceived %d", UBIDI_RTL, dir);
1398 /*All R- Hebrew string and length=-1 */
1399     dir = ubidi_getBaseDirection( stringHebrew, -1);
1400     if (dir != UBIDI_RTL )
1401         log_err("\nFailed getBaseDirection for Hebrew string w length= -1 ",
1402         "\nExpected  %d \nReceived %d", UBIDI_RTL, dir);
1403 /*All weak L- English digits string and length=-1 */
1404     dir = ubidi_getBaseDirection(stringAllEnglishDigits, -1);
1405     if (dir != UBIDI_NEUTRAL )
1406         log_err("\nFailed getBaseDirection for English digits string w length= -1 ",
1407         "\nExpected  %d \nReceived %d", UBIDI_NEUTRAL, dir);
1408 /*All weak AL- Arabic digits string and length=-1 */
1409     dir = ubidi_getBaseDirection(stringAllArabicDigits, -1);
1410     if (dir != UBIDI_NEUTRAL )
1411         log_err("\nFailed getBaseDirection for Arabic string w length= -1 ",
1412         "\nExpected  %d \nReceived %d", UBIDI_NEUTRAL, dir);
1413 
1414 }
1415 
1416 
doMisc(void)1417 static void doMisc(void) {
1418 /* Miscellaneous tests to exercize less popular code paths */
1419     UBiDi *bidi, *bidiLine;
1420     UChar src[MAXLEN], dest[MAXLEN];
1421     int32_t srcLen, destLen, runCount, i;
1422     UBiDiLevel level;
1423     UBiDiDirection dir;
1424     int32_t map[MAXLEN];
1425     UErrorCode errorCode=U_ZERO_ERROR;
1426     static const int32_t srcMap[6] = {0,1,-1,5,4};
1427     static const int32_t dstMap[6] = {0,1,-1,-1,4,3};
1428 
1429     bidi = ubidi_openSized(120, 66, &errorCode);
1430     if (bidi == NULL) {
1431         log_err("Error with openSized(120, 66)\n");
1432         return;
1433     }
1434     bidiLine = ubidi_open();
1435     if (bidi == NULL) {
1436         log_err("Error with open()\n");
1437         return;
1438     }
1439 
1440     destLen = ubidi_writeReverse(src, 0, dest, MAXLEN, 0, &errorCode);
1441     if (destLen != 0) {
1442         log_err("\nwriteReverse should return zero length, ",
1443                 "returned %d instead\n", destLen);
1444     }
1445     RETURN_IF_BAD_ERRCODE("#1#");
1446 
1447     ubidi_setPara(bidi, src, 0, UBIDI_LTR, NULL, &errorCode);
1448     destLen = ubidi_writeReordered(bidi, dest, MAXLEN, 0, &errorCode);
1449     if (destLen != 0) {
1450         log_err("\nwriteReordered should return zero length, ",
1451                 "returned %d instead\n", destLen);
1452     }
1453     RETURN_IF_BAD_ERRCODE("#2#");
1454 
1455     srcLen = u_unescape("abc       ", src, MAXLEN);
1456     ubidi_setPara(bidi, src, srcLen, UBIDI_RTL, NULL, &errorCode);
1457     ubidi_setLine(bidi, 0, 6, bidiLine, &errorCode);
1458     for (i = 3; i < 6; i++) {
1459         level = ubidi_getLevelAt(bidiLine, i);
1460         if (level != UBIDI_RTL) {
1461             log_err("\nTrailing space at index %d should get paragraph level"
1462                     "%d, got %d instead\n", i, UBIDI_RTL, level);
1463         }
1464     }
1465     RETURN_IF_BAD_ERRCODE("#3#");
1466 
1467     srcLen = u_unescape("abc       def", src, MAXLEN);
1468     ubidi_setPara(bidi, src, srcLen, UBIDI_RTL, NULL, &errorCode);
1469     ubidi_setLine(bidi, 0, 6, bidiLine, &errorCode);
1470     for (i = 3; i < 6; i++) {
1471         level = ubidi_getLevelAt(bidiLine, i);
1472         if (level != UBIDI_RTL) {
1473             log_err("\nTrailing space at index %d should get paragraph level"
1474                     "%d, got %d instead\n", i, UBIDI_RTL, level);
1475         }
1476     }
1477     RETURN_IF_BAD_ERRCODE("#4#");
1478 
1479     srcLen = u_unescape("abcdefghi    ", src, MAXLEN);
1480     ubidi_setPara(bidi, src, srcLen, UBIDI_RTL, NULL, &errorCode);
1481     ubidi_setLine(bidi, 0, 6, bidiLine, &errorCode);
1482     for (i = 3; i < 6; i++) {
1483         level = ubidi_getLevelAt(bidiLine, i);
1484         if (level != 2) {
1485             log_err("\nTrailing char at index %d should get level 2, "
1486                     "got %d instead\n", i, level);
1487         }
1488     }
1489     RETURN_IF_BAD_ERRCODE("#5#");
1490 
1491     ubidi_setReorderingOptions(bidi, UBIDI_OPTION_REMOVE_CONTROLS);
1492     srcLen = u_unescape("\\u200eabc       def", src, MAXLEN);
1493     ubidi_setPara(bidi, src, srcLen, UBIDI_RTL, NULL, &errorCode);
1494     ubidi_setLine(bidi, 0, 6, bidiLine, &errorCode);
1495     destLen = ubidi_getResultLength(bidiLine);
1496     if (destLen != 5) {
1497         log_err("\nWrong result length, should be 5, got %d\n", destLen);
1498     }
1499     RETURN_IF_BAD_ERRCODE("#6#");
1500 
1501     srcLen = u_unescape("abcdefghi", src, MAXLEN);
1502     ubidi_setPara(bidi, src, srcLen, UBIDI_LTR, NULL, &errorCode);
1503     ubidi_setLine(bidi, 0, 6, bidiLine, &errorCode);
1504     dir = ubidi_getDirection(bidiLine);
1505     if (dir != UBIDI_LTR) {
1506         log_err("\nWrong direction #1, should be %d, got %d\n",
1507                 UBIDI_LTR, dir);
1508     }
1509     RETURN_IF_BAD_ERRCODE("#7#");
1510 
1511     ubidi_setPara(bidi, src, 0, UBIDI_LTR, NULL, &errorCode);
1512     runCount = ubidi_countRuns(bidi, &errorCode);
1513     if (runCount != 0) {
1514         log_err("\nWrong number of runs #1, should be 0, got %d\n", runCount);
1515     }
1516     RETURN_IF_BAD_ERRCODE("#8#");
1517 
1518     srcLen = u_unescape("          ", src, MAXLEN);
1519     ubidi_setPara(bidi, src, srcLen, UBIDI_RTL, NULL, &errorCode);
1520     ubidi_setLine(bidi, 0, 6, bidiLine, &errorCode);
1521     runCount = ubidi_countRuns(bidiLine, &errorCode);
1522     if (runCount != 1) {
1523         log_err("\nWrong number of runs #2, should be 1, got %d\n", runCount);
1524     }
1525     RETURN_IF_BAD_ERRCODE("#9#");
1526 
1527     srcLen = u_unescape("a\\u05d0        bc", src, MAXLEN);
1528     ubidi_setPara(bidi, src, srcLen, UBIDI_RTL, NULL, &errorCode);
1529     ubidi_setLine(bidi, 0, 6, bidiLine, &errorCode);
1530     dir = ubidi_getDirection(bidi);
1531     if (dir != UBIDI_MIXED) {
1532         log_err("\nWrong direction #2, should be %d, got %d\n",
1533                 UBIDI_MIXED, dir);
1534     }
1535     dir = ubidi_getDirection(bidiLine);
1536     if (dir != UBIDI_MIXED) {
1537         log_err("\nWrong direction #3, should be %d, got %d\n",
1538                 UBIDI_MIXED, dir);
1539     }
1540     runCount = ubidi_countRuns(bidiLine, &errorCode);
1541     if (runCount != 2) {
1542         log_err("\nWrong number of runs #3, should be 2, got %d\n", runCount);
1543     }
1544     RETURN_IF_BAD_ERRCODE("#10#");
1545 
1546     ubidi_invertMap(srcMap, map, 5);
1547     if (memcmp(dstMap, map, sizeof(dstMap))) {
1548         log_err("\nUnexpected inverted Map, got ");
1549         for (i = 0; i < 6; i++) {
1550             log_err("%d ", map[i]);
1551         }
1552         log_err("\n");
1553     }
1554 
1555     /* test REMOVE_BIDI_CONTROLS together with DO_MIRRORING */
1556     srcLen = u_unescape("abc\\u200e", src, MAXLEN);
1557     ubidi_setPara(bidi, src, srcLen, UBIDI_LTR, NULL, &errorCode);
1558     destLen = ubidi_writeReordered(bidi, dest, MAXLEN,
1559               UBIDI_REMOVE_BIDI_CONTROLS | UBIDI_DO_MIRRORING, &errorCode);
1560     if (destLen != 3 || memcmp(dest, src, 3 * sizeof(UChar))) {
1561         log_err("\nWrong result #1, should be 'abc', got '%s'\n",
1562                 aescstrdup(dest, destLen));
1563     }
1564     RETURN_IF_BAD_ERRCODE("#11#");
1565 
1566     /* test inverse Bidi with marks and contextual orientation */
1567     ubidi_setReorderingMode(bidi, UBIDI_REORDER_INVERSE_LIKE_DIRECT);
1568     ubidi_setReorderingOptions(bidi, UBIDI_OPTION_INSERT_MARKS);
1569     ubidi_setPara(bidi, src, 0, UBIDI_DEFAULT_RTL, NULL, &errorCode);
1570     destLen = ubidi_writeReordered(bidi, dest, MAXLEN, 0, &errorCode);
1571     if (destLen != 0) {
1572         log_err("\nWrong result #2, length should be 0, got %d\n", destLen);
1573     }
1574     RETURN_IF_BAD_ERRCODE("#12#");
1575     srcLen = u_unescape("   ", src, MAXLEN);
1576     ubidi_setPara(bidi, src, srcLen, UBIDI_DEFAULT_RTL, NULL, &errorCode);
1577     destLen = ubidi_writeReordered(bidi, dest, MAXLEN, 0, &errorCode);
1578     if (destLen != 3 || memcmp(dest, src, destLen * sizeof(UChar))) {
1579         log_err("\nWrong result #3, should be '   ', got '%s'\n",
1580                 aescstrdup(dest, destLen));
1581     }
1582     RETURN_IF_BAD_ERRCODE("#13#");
1583     srcLen = u_unescape("abc", src, MAXLEN);
1584     ubidi_setPara(bidi, src, srcLen, UBIDI_DEFAULT_RTL, NULL, &errorCode);
1585     destLen = ubidi_writeReordered(bidi, dest, MAXLEN, 0, &errorCode);
1586     if (destLen != 3 || memcmp(dest, src, destLen * sizeof(UChar))) {
1587         log_err("\nWrong result #4, should be 'abc', got '%s'\n",
1588                 aescstrdup(dest, destLen));
1589     }
1590     RETURN_IF_BAD_ERRCODE("#14#");
1591     srcLen = u_unescape("\\u05d0\\u05d1", src, MAXLEN);
1592     ubidi_setPara(bidi, src, srcLen, UBIDI_DEFAULT_RTL, NULL, &errorCode);
1593     destLen = ubidi_writeReordered(bidi, dest, MAXLEN, 0, &errorCode);
1594     srcLen = u_unescape("\\u05d1\\u05d0", src, MAXLEN);
1595     if (destLen != 2 || memcmp(dest, src, destLen * sizeof(UChar))) {
1596         log_err("\nWrong result #5, should be '%s', got '%s'\n",
1597                 aescstrdup(src, srcLen), aescstrdup(dest, destLen));
1598     }
1599     RETURN_IF_BAD_ERRCODE("#15#");
1600     srcLen = u_unescape("abc \\u05d0\\u05d1", src, MAXLEN);
1601     ubidi_setPara(bidi, src, srcLen, UBIDI_DEFAULT_RTL, NULL, &errorCode);
1602     destLen = ubidi_writeReordered(bidi, dest, MAXLEN, 0, &errorCode);
1603     srcLen = u_unescape("\\u05d1\\u05d0 abc", src, MAXLEN);
1604     if (destLen != 6 || memcmp(dest, src, destLen * sizeof(UChar))) {
1605         log_err("\nWrong result #6, should be '%s', got '%s'\n",
1606                 aescstrdup(src, srcLen), aescstrdup(dest, destLen));
1607     }
1608     RETURN_IF_BAD_ERRCODE("#16#");
1609     srcLen = u_unescape("\\u05d0\\u05d1 abc", src, MAXLEN);
1610     ubidi_setPara(bidi, src, srcLen, UBIDI_DEFAULT_RTL, NULL, &errorCode);
1611     destLen = ubidi_writeReordered(bidi, dest, MAXLEN, 0, &errorCode);
1612     srcLen = u_unescape("\\u200fabc \\u05d1\\u05d0", src, MAXLEN);
1613     if (destLen != 7 || memcmp(dest, src, destLen * sizeof(UChar))) {
1614         log_err("\nWrong result #7, should be '%s', got '%s'\n",
1615                 aescstrdup(src, srcLen), aescstrdup(dest, destLen));
1616     }
1617     RETURN_IF_BAD_ERRCODE("#17#");
1618     srcLen = u_unescape("\\u05d0\\u05d1 abc .-=", src, MAXLEN);
1619     ubidi_setPara(bidi, src, srcLen, UBIDI_DEFAULT_RTL, NULL, &errorCode);
1620     destLen = ubidi_writeReordered(bidi, dest, MAXLEN, 0, &errorCode);
1621     srcLen = u_unescape("\\u200f=-. abc \\u05d1\\u05d0", src, MAXLEN);
1622     if (destLen != 11 || memcmp(dest, src, destLen * sizeof(UChar))) {
1623         log_err("\nWrong result #8, should be '%s', got '%s'\n",
1624                 aescstrdup(src, srcLen), aescstrdup(dest, destLen));
1625     }
1626     RETURN_IF_BAD_ERRCODE("#18#");
1627     ubidi_orderParagraphsLTR(bidi, TRUE);
1628     srcLen = u_unescape("\n\r   \n\rabc\n\\u05d0\\u05d1\rabc \\u05d2\\u05d3\n\r"
1629                         "\\u05d4\\u05d5 abc\n\\u05d6\\u05d7 abc .-=\r\n"
1630                         "-* \\u05d8\\u05d9 abc .-=", src, MAXLEN);
1631     ubidi_setPara(bidi, src, srcLen, UBIDI_DEFAULT_RTL, NULL, &errorCode);
1632     destLen = ubidi_writeReordered(bidi, dest, MAXLEN, 0, &errorCode);
1633     srcLen = u_unescape("\n\r   \n\rabc\n\\u05d1\\u05d0\r\\u05d3\\u05d2 abc\n\r"
1634                         "\\u200fabc \\u05d5\\u05d4\n\\u200f=-. abc \\u05d7\\u05d6\r\n"
1635                         "\\u200f=-. abc \\u05d9\\u05d8 *-", src, MAXLEN);
1636     if (destLen != 57 || memcmp(dest, src, destLen * sizeof(UChar))) {
1637         log_err("\nWrong result #9, should be '%s', got '%s'\n",
1638                 aescstrdup(src, srcLen), aescstrdup(dest, destLen));
1639     }
1640     RETURN_IF_BAD_ERRCODE("#19#");
1641     srcLen = u_unescape("\\u05d0 \t", src, MAXLEN);
1642     ubidi_setPara(bidi, src, srcLen, UBIDI_LTR, NULL, &errorCode);
1643     destLen = ubidi_writeReordered(bidi, dest, MAXLEN, 0, &errorCode);
1644     srcLen = u_unescape("\\u05D0\\u200e \t", src, MAXLEN);
1645     if (destLen != 4 || memcmp(dest, src, destLen * sizeof(UChar))) {
1646         log_err("\nWrong result #10, should be '%s', got '%s'\n",
1647                 aescstrdup(src, srcLen), aescstrdup(dest, destLen));
1648     }
1649     RETURN_IF_BAD_ERRCODE("#20#");
1650     srcLen = u_unescape("\\u05d0 123 \t\\u05d1 123 \\u05d2", src, MAXLEN);
1651     ubidi_setPara(bidi, src, srcLen, UBIDI_LTR, NULL, &errorCode);
1652     destLen = ubidi_writeReordered(bidi, dest, MAXLEN, 0, &errorCode);
1653     srcLen = u_unescape("\\u05d0 \\u200e123\\u200e \t\\u05d2 123 \\u05d1", src, MAXLEN);
1654     if (destLen != 16 || memcmp(dest, src, destLen * sizeof(UChar))) {
1655         log_err("\nWrong result #11, should be '%s', got '%s'\n",
1656                 aescstrdup(src, srcLen), aescstrdup(dest, destLen));
1657     }
1658     RETURN_IF_BAD_ERRCODE("#21#");
1659     srcLen = u_unescape("\\u05d0 123 \\u0660\\u0661 ab", src, MAXLEN);
1660     ubidi_setPara(bidi, src, srcLen, UBIDI_LTR, NULL, &errorCode);
1661     destLen = ubidi_writeReordered(bidi, dest, MAXLEN, 0, &errorCode);
1662     srcLen = u_unescape("\\u05d0 \\u200e123 \\u200e\\u0660\\u0661 ab", src, MAXLEN);
1663     if (destLen != 13 || memcmp(dest, src, destLen * sizeof(UChar))) {
1664         log_err("\nWrong result #12, should be '%s', got '%s'\n",
1665                 aescstrdup(src, srcLen), aescstrdup(dest, destLen));
1666     }
1667     RETURN_IF_BAD_ERRCODE("#22#");
1668     srcLen = u_unescape("ab \t", src, MAXLEN);
1669     ubidi_setPara(bidi, src, srcLen, UBIDI_RTL, NULL, &errorCode);
1670     destLen = ubidi_writeReordered(bidi, dest, MAXLEN, 0, &errorCode);
1671     srcLen = u_unescape("\\u200f\t ab", src, MAXLEN);
1672     if (destLen != 5 || memcmp(dest, src, destLen * sizeof(UChar))) {
1673         log_err("\nWrong result #13, should be '%s', got '%s'\n",
1674                 aescstrdup(src, srcLen), aescstrdup(dest, destLen));
1675     }
1676     RETURN_IF_BAD_ERRCODE("#23#");
1677 
1678     /* check exceeding para level */
1679     ubidi_close(bidi);
1680     bidi = ubidi_open();
1681     srcLen = u_unescape("A\\u202a\\u05d0\\u202aC\\u202c\\u05d1\\u202cE", src, MAXLEN);
1682     ubidi_setPara(bidi, src, srcLen, UBIDI_MAX_EXPLICIT_LEVEL - 1, NULL, &errorCode);
1683     level = ubidi_getLevelAt(bidi, 2);
1684     if (level != UBIDI_MAX_EXPLICIT_LEVEL) {
1685         log_err("\nWrong level at index 2\n, should be %d, got %d\n", UBIDI_MAX_EXPLICIT_LEVEL, level);
1686     }
1687     RETURN_IF_BAD_ERRCODE("#24#");
1688 
1689     /* check 1-char runs with RUNS_ONLY */
1690     ubidi_setReorderingMode(bidi, UBIDI_REORDER_RUNS_ONLY);
1691     srcLen = u_unescape("a \\u05d0 b \\u05d1 c \\u05d2 d ", src, MAXLEN);
1692     ubidi_setPara(bidi, src, srcLen, UBIDI_LTR, NULL, &errorCode);
1693     runCount = ubidi_countRuns(bidi, &errorCode);
1694     if (runCount != 14) {
1695         log_err("\nWrong number of runs #3, should be 14, got %d\n", runCount);
1696     }
1697     RETURN_IF_BAD_ERRCODE("#25#");
1698 
1699     ubidi_close(bidi);
1700     ubidi_close(bidiLine);
1701 }
1702 
1703 static void
testFailureRecovery(void)1704 testFailureRecovery(void) {
1705     UErrorCode errorCode;
1706     UBiDi *bidi, *bidiLine;
1707     UChar src[MAXLEN];
1708     int32_t srcLen;
1709     UBiDiLevel level;
1710     UBiDiReorderingMode rm;
1711     static UBiDiLevel myLevels[3] = {6,5,4};
1712 
1713     log_verbose("\nEntering TestFailureRecovery\n\n");
1714     errorCode = U_FILE_ACCESS_ERROR;
1715     if (ubidi_writeReordered(NULL, NULL, 0, 0, &errorCode) != 0) {
1716         log_err("ubidi_writeReordered did not return 0 when passed a failing UErrorCode\n");
1717     }
1718     if (ubidi_writeReverse(NULL, 0, NULL, 0, 0, &errorCode) != 0) {
1719         log_err("ubidi_writeReverse did not return 0 when passed a failing UErrorCode\n");
1720     }
1721     errorCode = U_ZERO_ERROR;
1722     if (ubidi_writeReordered(NULL, NULL, 0, 0, &errorCode) != 0 || errorCode != U_ILLEGAL_ARGUMENT_ERROR) {
1723         log_err("ubidi_writeReordered did not fail as expected\n");
1724     }
1725 
1726     bidi = ubidi_open();
1727     srcLen = u_unescape("abc", src, MAXLEN);
1728     errorCode = U_ZERO_ERROR;
1729     ubidi_setPara(bidi, src, srcLen, UBIDI_DEFAULT_LTR - 1, NULL, &errorCode);
1730     if (U_SUCCESS(errorCode)) {
1731         log_err("\nubidi_setPara did not fail when passed too big para level\n");
1732     }
1733     errorCode = U_ZERO_ERROR;
1734     if (ubidi_writeReverse(NULL, 0, NULL, 0, 0, &errorCode) != 0 || errorCode != U_ILLEGAL_ARGUMENT_ERROR) {
1735         log_err("ubidi_writeReverse did not fail as expected\n");
1736     }
1737     bidiLine = ubidi_open();
1738     errorCode = U_ZERO_ERROR;
1739     ubidi_setLine(bidi, 0, 6, bidiLine, &errorCode);
1740     if (U_SUCCESS(errorCode)) {
1741         log_err("\nubidi_setLine did not fail when called before valid setPara()\n");
1742     }
1743     errorCode = U_ZERO_ERROR;
1744     srcLen = u_unescape("abc", src, MAXLEN);
1745     ubidi_setPara(bidi, src, srcLen, UBIDI_LTR + 4, NULL, &errorCode);
1746     level = ubidi_getLevelAt(bidi, 3);
1747     if (level != 0) {
1748         log_err("\nubidi_getLevelAt did not fail when called with bad argument\n");
1749     }
1750     errorCode = U_ZERO_ERROR;
1751     ubidi_close(bidi);
1752     bidi = ubidi_openSized(-1, 0, &errorCode);
1753     if (U_SUCCESS(errorCode)) {
1754         log_err("\nubidi_openSized did not fail when called with bad argument\n");
1755     }
1756     ubidi_close(bidi);
1757     bidi = ubidi_openSized(2, 1, &errorCode);
1758     errorCode = U_ZERO_ERROR;
1759     srcLen = u_unescape("abc", src, MAXLEN);
1760     ubidi_setPara(bidi, src, srcLen, UBIDI_LTR, NULL, &errorCode);
1761     if (U_SUCCESS(errorCode)) {
1762         log_err("\nsetPara did not fail when called with text too long\n");
1763     }
1764     errorCode = U_ZERO_ERROR;
1765     srcLen = u_unescape("=2", src, MAXLEN);
1766     ubidi_setPara(bidi, src, srcLen, UBIDI_RTL, NULL, &errorCode);
1767     ubidi_countRuns(bidi, &errorCode);
1768     if (U_SUCCESS(errorCode)) {
1769         log_err("\nsetPara did not fail when called for too many runs\n");
1770     }
1771     ubidi_close(bidi);
1772     bidi = ubidi_open();
1773     rm = ubidi_getReorderingMode(bidi);
1774     ubidi_setReorderingMode(bidi, UBIDI_REORDER_DEFAULT - 1);
1775     if (rm != ubidi_getReorderingMode(bidi)) {
1776         log_err("\nsetReorderingMode with bad argument #1 should have no effect\n");
1777     }
1778     ubidi_setReorderingMode(bidi, 9999);
1779     if (rm != ubidi_getReorderingMode(bidi)) {
1780         log_err("\nsetReorderingMode with bad argument #2 should have no effect\n");
1781     }
1782 
1783     /* Try a surrogate char */
1784     errorCode = U_ZERO_ERROR;
1785     srcLen = u_unescape("\\uD800\\uDC00", src, MAXLEN);
1786     ubidi_setPara(bidi, src, srcLen, UBIDI_RTL, NULL, &errorCode);
1787     if (ubidi_getDirection(bidi) != UBIDI_MIXED) {
1788         log_err("\ngetDirection for 1st surrogate char should be MIXED\n");
1789     }
1790     errorCode = U_ZERO_ERROR;
1791     srcLen = u_unescape("abc", src, MAXLEN);
1792     ubidi_setPara(bidi, src, srcLen, 5, myLevels, &errorCode);
1793     if (U_SUCCESS(errorCode)) {
1794         log_err("\nsetPara did not fail when called with bad levels\n");
1795     }
1796     ubidi_close(bidi);
1797     ubidi_close(bidiLine);
1798 
1799     log_verbose("\nExiting TestFailureRecovery\n\n");
1800 }
1801 
1802 static void
testMultipleParagraphs(void)1803 testMultipleParagraphs(void) {
1804     static const char* const text = "__ABC\\u001c"          /* Para #0 offset 0 */
1805                                     "__\\u05d0DE\\u001c"    /*       1        6 */
1806                                     "__123\\u001c"          /*       2       12 */
1807                                     "\\u000d\\u000a"        /*       3       18 */
1808                                     "FG\\u000d"             /*       4       20 */
1809                                     "\\u000d"               /*       5       23 */
1810                                     "HI\\u000d\\u000a"      /*       6       24 */
1811                                     "\\u000d\\u000a"        /*       7       28 */
1812                                     "\\u000a"               /*       8       30 */
1813                                     "\\u000a"               /*       9       31 */
1814                                     "JK\\u001c";            /*      10       32 */
1815     static const int32_t paraCount=11;
1816     static const int32_t paraBounds[]={0, 6, 12, 18, 20, 23, 24, 28, 30, 31, 32, 35};
1817     static const UBiDiLevel paraLevels[]={UBIDI_LTR, UBIDI_RTL, UBIDI_DEFAULT_LTR, UBIDI_DEFAULT_RTL, 22, 23};
1818     static const UBiDiLevel multiLevels[6][11] = {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
1819                                                   {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
1820                                                   {0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0},
1821                                                   {0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0},
1822                                                   {22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22},
1823                                                   {23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23}};
1824     static const char* const text2 = "\\u05d0 1-2\\u001c\\u0630 1-2\\u001c1-2";
1825     static const UBiDiLevel levels2[] = {1,1,2,2,2,0, 1,1,2,1,2,0, 2,2,2};
1826     static UBiDiLevel myLevels[10] = {0,0,0,0,0,0,0,0,0,0};
1827     static const UChar multiparaTestString[] = {
1828         0x5de, 0x5e0, 0x5e1, 0x5d4, 0x20,  0x5e1, 0x5e4, 0x5da,
1829         0x20,  0xa,   0xa,   0x41,  0x72,  0x74,  0x69,  0x73,
1830         0x74,  0x3a,  0x20,  0x5de, 0x5e0, 0x5e1, 0x5d4, 0x20,
1831         0x5e1, 0x5e4, 0x5da, 0x20,  0xa,   0xa,   0x41,  0x6c,
1832         0x62,  0x75,  0x6d,  0x3a,  0x20,  0x5de, 0x5e0, 0x5e1,
1833         0x5d4, 0x20,  0x5e1, 0x5e4, 0x5da, 0x20,  0xa,   0xa,
1834         0x54,  0x69,  0x6d,  0x65,  0x3a,  0x20,  0x32,  0x3a,
1835         0x32,  0x37,  0xa,  0xa
1836     };
1837     static const UBiDiLevel multiparaTestLevels[] = {
1838         1, 1, 1, 1, 1, 1, 1, 1,
1839         1, 1, 0, 0, 0, 0, 0, 0,
1840         0, 0, 0, 1, 1, 1, 1, 1,
1841         1, 1, 1, 0, 0, 0, 0, 0,
1842         0, 0, 0, 0, 0, 1, 1, 1,
1843         1, 1, 1, 1, 1, 0, 0, 0,
1844         0, 0, 0, 0, 0, 0, 0, 0,
1845         0, 0, 0, 0
1846     };
1847     UBiDiLevel gotLevel;
1848     const UBiDiLevel* gotLevels;
1849     UBool orderParagraphsLTR;
1850     UChar src[MAXLEN], dest[MAXLEN];
1851     UErrorCode errorCode=U_ZERO_ERROR;
1852     UBiDi* pBidi=ubidi_open();
1853     UBiDi* pLine;
1854     int32_t srcSize, count, paraStart, paraLimit, paraIndex, length;
1855     int32_t srcLen, destLen;
1856     int i, j, k;
1857 
1858     log_verbose("\nEntering TestMultipleParagraphs\n\n");
1859     u_unescape(text, src, MAXLEN);
1860     srcSize=u_strlen(src);
1861     ubidi_setPara(pBidi, src, srcSize, UBIDI_LTR, NULL, &errorCode);
1862     if(U_FAILURE(errorCode)){
1863         log_err("ubidi_setPara failed, paraLevel=%d, errorCode %s\n",
1864                 UBIDI_LTR, u_errorName(errorCode));
1865         ubidi_close(pBidi);
1866         return;
1867     }
1868     /* check paragraph count and boundaries */
1869     if (paraCount!=(count=ubidi_countParagraphs(pBidi))) {
1870         log_err("ubidi_countParagraphs returned %d, should be %d\n",
1871                 count, paraCount);
1872     }
1873     for (i=0; i<paraCount; i++) {
1874         ubidi_getParagraphByIndex(pBidi, i, &paraStart, &paraLimit, NULL, &errorCode);
1875         if ((paraStart!=paraBounds[i]) || (paraLimit!=paraBounds[i+1])) {
1876             log_err("Found boundaries of paragraph %d: %d-%d; expected: %d-%d\n",
1877                     i, paraStart, paraLimit, paraBounds[i], paraBounds[i+1]);
1878         }
1879     }
1880     errorCode=U_ZERO_ERROR;
1881     /* check with last paragraph not terminated by B */
1882     src[srcSize-1]='L';
1883     ubidi_setPara(pBidi, src, srcSize, UBIDI_LTR, NULL, &errorCode);
1884     if(U_FAILURE(errorCode)){
1885         log_err("2nd ubidi_setPara failed, paraLevel=%d, errorCode %s\n",
1886                 UBIDI_LTR, u_errorName(errorCode));
1887         ubidi_close(pBidi);
1888         return;
1889     }
1890     if (paraCount!=(count=ubidi_countParagraphs(pBidi))) {
1891         log_err("2nd ubidi_countParagraphs returned %d, should be %d\n",
1892                 count, paraCount);
1893     }
1894     i=paraCount-1;
1895     ubidi_getParagraphByIndex(pBidi, i, &paraStart, &paraLimit, NULL, &errorCode);
1896     if ((paraStart!=paraBounds[i]) || (paraLimit!=paraBounds[i+1])) {
1897         log_err("2nd Found boundaries of paragraph %d: %d-%d; expected: %d-%d\n",
1898                 i, paraStart, paraLimit, paraBounds[i], paraBounds[i+1]);
1899     }
1900     errorCode=U_ZERO_ERROR;
1901     /* check paraLevel for all paragraphs under various paraLevel specs */
1902     for (k=0; k<6; k++) {
1903         ubidi_setPara(pBidi, src, srcSize, paraLevels[k], NULL, &errorCode);
1904         for (i=0; i<paraCount; i++) {
1905             paraIndex=ubidi_getParagraph(pBidi, paraBounds[i], NULL, NULL, &gotLevel, &errorCode);
1906             if (paraIndex!=i) {
1907                 log_err("For paraLevel=%d paragraph=%d, found paragraph index=%d expected=%d\n",
1908                         paraLevels[k], i, paraIndex, i);
1909             }
1910             if (gotLevel!=multiLevels[k][i]) {
1911                 log_err("For paraLevel=%d paragraph=%d, found level=%d expected %d\n",
1912                         paraLevels[k], i, gotLevel, multiLevels[k][i]);
1913             }
1914         }
1915         gotLevel=ubidi_getParaLevel(pBidi);
1916         if (gotLevel!=multiLevels[k][0]) {
1917             log_err("For paraLevel=%d getParaLevel=%d, expected %d\n",
1918                     paraLevels[k], gotLevel, multiLevels[k][0]);
1919         }
1920     }
1921     errorCode=U_ZERO_ERROR;
1922     /* check that the result of ubidi_getParaLevel changes if the first
1923      * paragraph has a different level
1924      */
1925     src[0]=0x05d2;                      /* Hebrew letter Gimel */
1926     ubidi_setPara(pBidi, src, srcSize, UBIDI_DEFAULT_LTR, NULL, &errorCode);
1927     gotLevel=ubidi_getParaLevel(pBidi);
1928     if (gotLevel!=UBIDI_RTL) {
1929         log_err("For paraLevel=UBIDI_DEFAULT_LTR getParaLevel=%d, expected=%d\n",
1930                         gotLevel, UBIDI_RTL);
1931     }
1932     errorCode=U_ZERO_ERROR;
1933     /* check that line cannot overlap paragraph boundaries */
1934     pLine=ubidi_open();
1935     i=paraBounds[1];
1936     k=paraBounds[2]+1;
1937     ubidi_setLine(pBidi, i, k, pLine, &errorCode);
1938     if (U_SUCCESS(errorCode)) {
1939         log_err("For line limits %d-%d got success %s\n",
1940                 i, k, u_errorName(errorCode));
1941     }
1942     errorCode=U_ZERO_ERROR;
1943     i=paraBounds[1];
1944     k=paraBounds[2];
1945     ubidi_setLine(pBidi, i, k, pLine, &errorCode);
1946     if (U_FAILURE(errorCode)) {
1947         log_err("For line limits %d-%d got error %s\n",
1948                 i, k, u_errorName(errorCode));
1949         errorCode=U_ZERO_ERROR;
1950     }
1951     /* check level of block separator at end of paragraph when orderParagraphsLTR==FALSE */
1952     ubidi_setPara(pBidi, src, srcSize, UBIDI_RTL, NULL, &errorCode);
1953     /* get levels through para Bidi block */
1954     gotLevels=ubidi_getLevels(pBidi, &errorCode);
1955     if (U_FAILURE(errorCode)) {
1956         log_err("Error on Para getLevels %s\n", u_errorName(errorCode));
1957         ubidi_close(pLine);
1958         ubidi_close(pBidi);
1959         return;
1960     }
1961     for (i=26; i<32; i++) {
1962         if (gotLevels[i]!=UBIDI_RTL) {
1963             log_err("For char %d(%04x), level=%d, expected=%d\n",
1964                     i, src[i], gotLevels[i], UBIDI_RTL);
1965         }
1966     }
1967     /* get levels through para Line block */
1968     i=paraBounds[1];
1969     k=paraBounds[2];
1970     ubidi_setLine(pBidi, i, k, pLine, &errorCode);
1971     if (U_FAILURE(errorCode)) {
1972         log_err("For line limits %d-%d got error %s\n",
1973                 i, k, u_errorName(errorCode));
1974         ubidi_close(pLine);
1975         ubidi_close(pBidi);
1976         return;
1977     }
1978     paraIndex=ubidi_getParagraph(pLine, i, &paraStart, &paraLimit, &gotLevel, &errorCode);
1979     gotLevels=ubidi_getLevels(pLine, &errorCode);
1980     if (U_FAILURE(errorCode)) {
1981         log_err("Error on Line getLevels %s\n", u_errorName(errorCode));
1982         ubidi_close(pLine);
1983         ubidi_close(pBidi);
1984         return;
1985     }
1986     length=ubidi_getLength(pLine);
1987     if ((gotLevel!=UBIDI_RTL) || (gotLevels[length-1]!=UBIDI_RTL)) {
1988         log_err("For paragraph %d with limits %d-%d, paraLevel=%d expected=%d, "
1989                 "level of separator=%d expected=%d\n",
1990                 paraIndex, paraStart, paraLimit, gotLevel, UBIDI_RTL, gotLevels[length-1], UBIDI_RTL);
1991     }
1992     orderParagraphsLTR=ubidi_isOrderParagraphsLTR(pBidi);
1993     if (orderParagraphsLTR) {
1994         log_err("Found orderParagraphsLTR=%d expected=%d\n", orderParagraphsLTR, FALSE);
1995     }
1996     ubidi_orderParagraphsLTR(pBidi, TRUE);
1997     orderParagraphsLTR=ubidi_isOrderParagraphsLTR(pBidi);
1998     if (!orderParagraphsLTR) {
1999         log_err("Found orderParagraphsLTR=%d expected=%d\n", orderParagraphsLTR, TRUE);
2000     }
2001     /* check level of block separator at end of paragraph when orderParagraphsLTR==TRUE */
2002     ubidi_setPara(pBidi, src, srcSize, UBIDI_RTL, NULL, &errorCode);
2003     /* get levels through para Bidi block */
2004     gotLevels=ubidi_getLevels(pBidi, &errorCode);
2005     for (i=26; i<32; i++) {
2006         if (gotLevels[i]!=0) {
2007             log_err("For char %d(%04x), level=%d, expected=%d\n",
2008                     i, src[i], gotLevels[i], 0);
2009         }
2010     }
2011     errorCode=U_ZERO_ERROR;
2012     /* get levels through para Line block */
2013     i=paraBounds[1];
2014     k=paraBounds[2];
2015     ubidi_setLine(pBidi, paraStart, paraLimit, pLine, &errorCode);
2016     paraIndex=ubidi_getParagraph(pLine, i, &paraStart, &paraLimit, &gotLevel, &errorCode);
2017     gotLevels=ubidi_getLevels(pLine, &errorCode);
2018     length=ubidi_getLength(pLine);
2019     if ((gotLevel!=UBIDI_RTL) || (gotLevels[length-1]!=0)) {
2020         log_err("For paragraph %d with limits %d-%d, paraLevel=%d expected=%d, "
2021                 "level of separator=%d expected=%d\n",
2022                 paraIndex, paraStart, paraLimit, gotLevel, UBIDI_RTL, gotLevels[length-1], 0);
2023         log_verbose("levels=");
2024         for (count=0; count<length; count++) {
2025             log_verbose(" %d", gotLevels[count]);
2026         }
2027         log_verbose("\n");
2028     }
2029 
2030     /* test that the concatenation of separate invocations of the bidi code
2031      * on each individual paragraph in order matches the levels array that
2032      * results from invoking bidi once over the entire multiparagraph tests
2033      * (with orderParagraphsLTR false, of course)
2034      */
2035     u_unescape(text, src, MAXLEN);      /* restore original content */
2036     srcSize=u_strlen(src);
2037     ubidi_orderParagraphsLTR(pBidi, FALSE);
2038     ubidi_setPara(pBidi, src, srcSize, UBIDI_DEFAULT_RTL, NULL, &errorCode);
2039     gotLevels=ubidi_getLevels(pBidi, &errorCode);
2040     for (i=0; i<paraCount; i++) {
2041         /* use pLine for individual paragraphs */
2042         paraStart = paraBounds[i];
2043         length = paraBounds[i+1] - paraStart;
2044         ubidi_setPara(pLine, src+paraStart, length, UBIDI_DEFAULT_RTL, NULL, &errorCode);
2045         for (j=0; j<length; j++) {
2046             if ((k=ubidi_getLevelAt(pLine, j)) != (gotLevel=gotLevels[paraStart+j])) {
2047                 log_err("Checking paragraph concatenation: for paragraph=%d, "
2048                         "char=%d(%04x), level=%d, expected=%d\n",
2049                         i, j, src[paraStart+j], k, gotLevel);
2050             }
2051         }
2052     }
2053 
2054     /* ensure that leading numerics in a paragraph are not treated as arabic
2055        numerals because of arabic text in a preceding paragraph
2056      */
2057     u_unescape(text2, src, MAXLEN);
2058     srcSize=u_strlen(src);
2059     ubidi_orderParagraphsLTR(pBidi, TRUE);
2060     ubidi_setPara(pBidi, src, srcSize, UBIDI_RTL, NULL, &errorCode);
2061     gotLevels=ubidi_getLevels(pBidi, &errorCode);
2062     if (U_FAILURE(errorCode)) {
2063         log_err("Can't get levels. %s\n", u_errorName(errorCode));
2064         return;
2065     }
2066     for (i=0; i<srcSize; i++) {
2067         if (gotLevels[i]!=levels2[i]) {
2068             log_err("Checking leading numerics: for char %d(%04x), level=%d, expected=%d\n",
2069                     i, src[i], gotLevels[i], levels2[i]);
2070         }
2071     }
2072 
2073     /* check handling of whitespace before end of paragraph separator when
2074      * orderParagraphsLTR==TRUE, when last paragraph has, and lacks, a terminating B
2075      */
2076     u_memset(src, 0x0020, MAXLEN);
2077     srcSize = 5;
2078     ubidi_orderParagraphsLTR(pBidi, TRUE);
2079     for (i=0x001c; i<=0x0020; i+=(0x0020-0x001c)) {
2080         src[4]=(UChar)i;                /* with and without terminating B */
2081         for (j=0x0041; j<=0x05d0; j+=(0x05d0-0x0041)) {
2082             src[0]=(UChar)j;            /* leading 'A' or Alef */
2083             for (gotLevel=4; gotLevel<=5; gotLevel++) {
2084                 /* test even and odd paraLevel */
2085                 ubidi_setPara(pBidi, src, srcSize, gotLevel, NULL, &errorCode);
2086                 gotLevels=ubidi_getLevels(pBidi, &errorCode);
2087                 for (k=1; k<=3; k++) {
2088                     if (gotLevels[k]!=gotLevel) {
2089                         log_err("Checking trailing spaces: for leading_char=%04x, "
2090                                 "last_char=%04x, index=%d, level=%d, expected=%d\n",
2091                                 src[0], src[4], k, gotLevels[k], gotLevel);
2092                     }
2093                 }
2094             }
2095         }
2096     }
2097 
2098     /* check default orientation when inverse bidi and paragraph starts
2099      * with LTR strong char and ends with RTL strong char, with and without
2100      * a terminating B
2101      */
2102     ubidi_setReorderingMode(pBidi, UBIDI_REORDER_INVERSE_LIKE_DIRECT);
2103     srcLen = u_unescape("abc \\u05d2\\u05d1\n", src, MAXLEN);
2104     ubidi_setPara(pBidi, src, srcLen, UBIDI_DEFAULT_LTR, NULL, &errorCode);
2105     destLen = ubidi_writeReordered(pBidi, dest, MAXLEN, 0, &errorCode);
2106     srcLen = u_unescape("\\u05d1\\u05d2 abc\n", src, MAXLEN);
2107     if (memcmp(src, dest, destLen * sizeof(UChar))) {
2108         log_err("\nInvalid output #0, should be '%s', got '%s'\n",
2109                 aescstrdup(src, srcLen), aescstrdup(dest, destLen));
2110     }
2111     srcLen = u_unescape("abc \\u05d2\\u05d1", src, MAXLEN);
2112     ubidi_setPara(pBidi, src, srcLen, UBIDI_DEFAULT_LTR, NULL, &errorCode);
2113     destLen = ubidi_writeReordered(pBidi, dest, MAXLEN, 0, &errorCode);
2114     srcLen = u_unescape("\\u05d1\\u05d2 abc", src, MAXLEN);
2115     if (memcmp(src, dest, destLen * sizeof(UChar))) {
2116         log_err("\nInvalid output #1, should be '%s', got '%s'\n",
2117                 aescstrdup(src, srcLen), aescstrdup(dest, destLen));
2118     }
2119 
2120     /* check multiple paragraphs together with explicit levels
2121      */
2122     ubidi_setReorderingMode(pBidi, UBIDI_REORDER_DEFAULT);
2123     srcLen = u_unescape("ab\\u05d1\\u05d2\n\\u05d3\\u05d4123", src, MAXLEN);
2124     ubidi_setPara(pBidi, src, srcLen, UBIDI_LTR, myLevels, &errorCode);
2125     destLen = ubidi_writeReordered(pBidi, dest, MAXLEN, 0, &errorCode);
2126     srcLen = u_unescape("ab\\u05d2\\u05d1\\n123\\u05d4\\u05d3", src, MAXLEN);
2127     if (memcmp(src, dest, destLen * sizeof(UChar))) {
2128         log_err("\nInvalid output #2, should be '%s', got '%s'\n",
2129                 aescstrdup(src, srcLen), aescstrdup(dest, destLen));
2130     }
2131     count = ubidi_countParagraphs(pBidi);
2132     if (count != 2) {
2133         log_err("\nInvalid number of paras, should be 2, got %d\n", count);
2134     }
2135 
2136     ubidi_close(pLine);
2137     ubidi_close(pBidi);
2138     log_verbose("\nExiting TestMultipleParagraphs\n\n");
2139 
2140     /* check levels in multiple paragraphs with default para level
2141      */
2142     pBidi = ubidi_open();
2143     errorCode = U_ZERO_ERROR;
2144     ubidi_setPara(pBidi, multiparaTestString, UPRV_LENGTHOF(multiparaTestString),
2145                   UBIDI_DEFAULT_LTR, NULL, &errorCode);
2146     if (U_FAILURE(errorCode)) {
2147         log_err("ubidi_setPara failed for multiparaTestString\n");
2148         ubidi_close(pBidi);
2149         return;
2150     }
2151     gotLevels = ubidi_getLevels(pBidi, &errorCode);
2152     if (U_FAILURE(errorCode)) {
2153         log_err("ubidi_getLevels failed for multiparaTestString\n");
2154         ubidi_close(pBidi);
2155         return;
2156     }
2157     for (i = 0; i < UPRV_LENGTHOF(multiparaTestString); i++) {
2158         if (gotLevels[i] != multiparaTestLevels[i]) {
2159             log_err("Error on level for multiparaTestString at index %d, "
2160                     "expected=%d, actual=%d\n",
2161                     i, multiparaTestLevels[i], gotLevels[i]);
2162         }
2163     }
2164     ubidi_close(pBidi);
2165 
2166 }
2167 
2168 
2169 /* inverse BiDi ------------------------------------------------------------- */
2170 
2171 static int countRoundtrips=0, countNonRoundtrips=0;
2172 
2173 #define STRING_TEST_CASE(s) { (s), UPRV_LENGTHOF(s) }
2174 
2175 static void
testInverse(void)2176 testInverse(void) {
2177     static const UChar
2178         string0[]={ 0x6c, 0x61, 0x28, 0x74, 0x69, 0x6e, 0x20, 0x5d0, 0x5d1, 0x29, 0x5d2, 0x5d3 },
2179         string1[]={ 0x6c, 0x61, 0x74, 0x20, 0x5d0, 0x5d1, 0x5d2, 0x20, 0x31, 0x32, 0x33 },
2180         string2[]={ 0x6c, 0x61, 0x74, 0x20, 0x5d0, 0x28, 0x5d1, 0x5d2, 0x20, 0x31, 0x29, 0x32, 0x33 },
2181         string3[]={ 0x31, 0x32, 0x33, 0x20, 0x5d0, 0x5d1, 0x5d2, 0x20, 0x34, 0x35, 0x36 },
2182         string4[]={ 0x61, 0x62, 0x20, 0x61, 0x62, 0x20, 0x661, 0x662 };
2183 
2184     static const struct {
2185         const UChar *s;
2186         int32_t length;
2187     } testCases[]={
2188         STRING_TEST_CASE(string0),
2189         STRING_TEST_CASE(string1),
2190         STRING_TEST_CASE(string2),
2191         STRING_TEST_CASE(string3),
2192         STRING_TEST_CASE(string4)
2193     };
2194 
2195     UBiDi *pBiDi;
2196     UErrorCode errorCode;
2197     int i;
2198 
2199     log_verbose("\nEntering TestInverse\n\n");
2200     pBiDi=ubidi_open();
2201     if(pBiDi==NULL) {
2202         log_err("unable to open a UBiDi object (out of memory)\n");
2203         return;
2204     }
2205 
2206     log_verbose("inverse Bidi: testInverse(L) with %u test cases ---\n", UPRV_LENGTHOF(testCases));
2207      for(i=0; i<UPRV_LENGTHOF(testCases); ++i) {
2208         log_verbose("Testing case %d\n", i);
2209         errorCode=U_ZERO_ERROR;
2210         _testInverseBidi(pBiDi, testCases[i].s, testCases[i].length, 0, &errorCode);
2211     }
2212 
2213     log_verbose("inverse Bidi: testInverse(R) with %u test cases ---\n", UPRV_LENGTHOF(testCases));
2214     for(i=0; i<UPRV_LENGTHOF(testCases); ++i) {
2215         log_verbose("Testing case %d\n", i);
2216         errorCode=U_ZERO_ERROR;
2217         _testInverseBidi(pBiDi, testCases[i].s, testCases[i].length, 1, &errorCode);
2218     }
2219 
2220     _testManyInverseBidi(pBiDi, 0);
2221     _testManyInverseBidi(pBiDi, 1);
2222 
2223     ubidi_close(pBiDi);
2224 
2225     log_verbose("inverse Bidi: rountrips: %5u\nnon-roundtrips: %5u\n", countRoundtrips, countNonRoundtrips);
2226 
2227     _testWriteReverse();
2228 
2229     _testManyAddedPoints();
2230 
2231     _testMisc();
2232 
2233     log_verbose("\nExiting TestInverse\n\n");
2234 }
2235 
2236 #define COUNT_REPEAT_SEGMENTS 6
2237 
2238 static const UChar repeatSegments[COUNT_REPEAT_SEGMENTS][2]={
2239     { 0x61, 0x62 },     /* L */
2240     { 0x5d0, 0x5d1 },   /* R */
2241     { 0x627, 0x628 },   /* AL */
2242     { 0x31, 0x32 },     /* EN */
2243     { 0x661, 0x662 },   /* AN */
2244     { 0x20, 0x20 }      /* WS (N) */
2245 };
2246 
2247 static void
_testManyInverseBidi(UBiDi * pBiDi,UBiDiLevel direction)2248 _testManyInverseBidi(UBiDi *pBiDi, UBiDiLevel direction) {
2249     UChar text[8]={ 0, 0, 0x20, 0, 0, 0x20, 0, 0 };
2250     int i, j, k;
2251     UErrorCode errorCode;
2252 
2253     log_verbose("inverse Bidi: testManyInverseBidi(%c) - test permutations of text snippets ---\n",
2254                  direction==0 ? 'L' : 'R');
2255     for(i=0; i<COUNT_REPEAT_SEGMENTS; ++i) {
2256         text[0]=repeatSegments[i][0];
2257         text[1]=repeatSegments[i][1];
2258         for(j=0; j<COUNT_REPEAT_SEGMENTS; ++j) {
2259             text[3]=repeatSegments[j][0];
2260             text[4]=repeatSegments[j][1];
2261             for(k=0; k<COUNT_REPEAT_SEGMENTS; ++k) {
2262                 text[6]=repeatSegments[k][0];
2263                 text[7]=repeatSegments[k][1];
2264 
2265                 errorCode=U_ZERO_ERROR;
2266                 log_verbose("inverse Bidi: testManyInverseBidi()[%u %u %u]\n", i, j, k);
2267                 _testInverseBidi(pBiDi, text, 8, direction, &errorCode);
2268             }
2269         }
2270     }
2271 }
2272 
2273 static void
_testInverseBidi(UBiDi * pBiDi,const UChar * src,int32_t srcLength,UBiDiLevel direction,UErrorCode * pErrorCode)2274 _testInverseBidi(UBiDi *pBiDi, const UChar *src, int32_t srcLength,
2275                 UBiDiLevel direction, UErrorCode *pErrorCode) {
2276     UChar visualLTR[MAXLEN], logicalDest[MAXLEN], visualDest[MAXLEN];
2277     int32_t ltrLength, logicalLength, visualLength;
2278 
2279     if(direction==0) {
2280         log_verbose("inverse Bidi: testInverse(L)\n");
2281 
2282         /* convert visual to logical */
2283         ubidi_setInverse(pBiDi, TRUE);
2284         if (!ubidi_isInverse(pBiDi)) {
2285             log_err("Error while doing ubidi_setInverse(TRUE)\n");
2286         }
2287         ubidi_setPara(pBiDi, src, srcLength, 0, NULL, pErrorCode);
2288         if (src != ubidi_getText(pBiDi)) {
2289             log_err("Wrong value returned by ubidi_getText\n");
2290         }
2291         logicalLength=ubidi_writeReordered(pBiDi, logicalDest, UPRV_LENGTHOF(logicalDest),
2292                                            UBIDI_DO_MIRRORING|UBIDI_INSERT_LRM_FOR_NUMERIC, pErrorCode);
2293         log_verbose("  v ");
2294         printUnicode(src, srcLength, ubidi_getLevels(pBiDi, pErrorCode));
2295         log_verbose("\n");
2296 
2297         /* convert back to visual LTR */
2298         ubidi_setInverse(pBiDi, FALSE);
2299         if (ubidi_isInverse(pBiDi)) {
2300             log_err("Error while doing ubidi_setInverse(FALSE)\n");
2301         }
2302         ubidi_setPara(pBiDi, logicalDest, logicalLength, 0, NULL, pErrorCode);
2303         visualLength=ubidi_writeReordered(pBiDi, visualDest, UPRV_LENGTHOF(visualDest),
2304                                           UBIDI_DO_MIRRORING|UBIDI_REMOVE_BIDI_CONTROLS, pErrorCode);
2305     } else {
2306         log_verbose("inverse Bidi: testInverse(R)\n");
2307 
2308         /* reverse visual from RTL to LTR */
2309         ltrLength=ubidi_writeReverse(src, srcLength, visualLTR, UPRV_LENGTHOF(visualLTR), 0, pErrorCode);
2310         log_verbose("  vr");
2311         printUnicode(src, srcLength, NULL);
2312         log_verbose("\n");
2313 
2314         /* convert visual RTL to logical */
2315         ubidi_setInverse(pBiDi, TRUE);
2316         ubidi_setPara(pBiDi, visualLTR, ltrLength, 0, NULL, pErrorCode);
2317         logicalLength=ubidi_writeReordered(pBiDi, logicalDest, UPRV_LENGTHOF(logicalDest),
2318                                            UBIDI_DO_MIRRORING|UBIDI_INSERT_LRM_FOR_NUMERIC, pErrorCode);
2319         log_verbose("  vl");
2320         printUnicode(visualLTR, ltrLength, ubidi_getLevels(pBiDi, pErrorCode));
2321         log_verbose("\n");
2322 
2323         /* convert back to visual RTL */
2324         ubidi_setInverse(pBiDi, FALSE);
2325         ubidi_setPara(pBiDi, logicalDest, logicalLength, 0, NULL, pErrorCode);
2326         visualLength=ubidi_writeReordered(pBiDi, visualDest, UPRV_LENGTHOF(visualDest),
2327                                           UBIDI_DO_MIRRORING|UBIDI_REMOVE_BIDI_CONTROLS|UBIDI_OUTPUT_REVERSE, pErrorCode);
2328     }
2329     log_verbose("  l ");
2330     printUnicode(logicalDest, logicalLength, ubidi_getLevels(pBiDi, pErrorCode));
2331     log_verbose("\n");
2332     log_verbose("  v ");
2333     printUnicode(visualDest, visualLength, NULL);
2334     log_verbose("\n");
2335 
2336     /* check and print results */
2337     if(U_FAILURE(*pErrorCode)) {
2338         log_err("inverse BiDi: *** error %s\n"
2339                 "                 turn on verbose mode to see details\n", u_errorName(*pErrorCode));
2340     } else if(srcLength==visualLength && memcmp(src, visualDest, srcLength*U_SIZEOF_UCHAR)==0) {
2341         ++countRoundtrips;
2342         log_verbose(" + roundtripped\n");
2343     } else {
2344         ++countNonRoundtrips;
2345         log_verbose(" * did not roundtrip\n");
2346         log_err("inverse BiDi: transformation visual->logical->visual did not roundtrip the text;\n"
2347                 "                 turn on verbose mode to see details\n");
2348     }
2349 }
2350 
2351 static void
_testWriteReverse(void)2352 _testWriteReverse(void) {
2353     /* U+064e and U+0650 are combining marks (Mn) */
2354     static const UChar forward[]={
2355         0x200f, 0x627, 0x64e, 0x650, 0x20, 0x28, 0x31, 0x29
2356     }, reverseKeepCombining[]={
2357         0x29, 0x31, 0x28, 0x20, 0x627, 0x64e, 0x650, 0x200f
2358     }, reverseRemoveControlsKeepCombiningDoMirror[]={
2359         0x28, 0x31, 0x29, 0x20, 0x627, 0x64e, 0x650
2360     };
2361     UChar reverse[10];
2362     UErrorCode errorCode;
2363     int32_t length;
2364 
2365     /* test ubidi_writeReverse() with "interesting" options */
2366     errorCode=U_ZERO_ERROR;
2367     length=ubidi_writeReverse(forward, UPRV_LENGTHOF(forward),
2368                               reverse, UPRV_LENGTHOF(reverse),
2369                               UBIDI_KEEP_BASE_COMBINING,
2370                               &errorCode);
2371     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(reverseKeepCombining) || memcmp(reverse, reverseKeepCombining, length*U_SIZEOF_UCHAR)!=0) {
2372         log_err("failure in ubidi_writeReverse(UBIDI_KEEP_BASE_COMBINING): length=%d (should be %d), error code %s\n",
2373                 length, UPRV_LENGTHOF(reverseKeepCombining), u_errorName(errorCode));
2374     }
2375 
2376     memset(reverse, 0xa5, UPRV_LENGTHOF(reverse)*U_SIZEOF_UCHAR);
2377     errorCode=U_ZERO_ERROR;
2378     length=ubidi_writeReverse(forward, UPRV_LENGTHOF(forward),
2379                               reverse, UPRV_LENGTHOF(reverse),
2380                               UBIDI_REMOVE_BIDI_CONTROLS|UBIDI_DO_MIRRORING|UBIDI_KEEP_BASE_COMBINING,
2381                               &errorCode);
2382     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(reverseRemoveControlsKeepCombiningDoMirror) || memcmp(reverse, reverseRemoveControlsKeepCombiningDoMirror, length*U_SIZEOF_UCHAR)!=0) {
2383         log_err("failure in ubidi_writeReverse(UBIDI_REMOVE_BIDI_CONTROLS|UBIDI_DO_MIRRORING|UBIDI_KEEP_BASE_COMBINING):\n"
2384                 "    length=%d (should be %d), error code %s\n",
2385                 length, UPRV_LENGTHOF(reverseRemoveControlsKeepCombiningDoMirror), u_errorName(errorCode));
2386     }
2387 }
2388 
_testManyAddedPoints(void)2389 static void _testManyAddedPoints(void) {
2390     UErrorCode errorCode = U_ZERO_ERROR;
2391     UBiDi *bidi = ubidi_open();
2392     UChar text[90], dest[MAXLEN], expected[120];
2393     int destLen, i;
2394     for (i = 0; i < UPRV_LENGTHOF(text); i+=3) {
2395         text[i] = 0x0061; /* 'a' */
2396         text[i+1] = 0x05d0;
2397         text[i+2] = 0x0033; /* '3' */
2398     }
2399     ubidi_setReorderingMode(bidi, UBIDI_REORDER_INVERSE_LIKE_DIRECT);
2400     ubidi_setReorderingOptions(bidi, UBIDI_OPTION_INSERT_MARKS);
2401     ubidi_setPara(bidi, text, UPRV_LENGTHOF(text), UBIDI_LTR, NULL, &errorCode);
2402     destLen = ubidi_writeReordered(bidi, dest, MAXLEN, 0, &errorCode);
2403     for (i = 0; i < UPRV_LENGTHOF(expected); i+=4) {
2404         expected[i] = 0x0061; /* 'a' */
2405         expected[i+1] = 0x05d0;
2406         expected[i+2] = 0x200e;
2407         expected[i+3] = 0x0033; /* '3' */
2408     }
2409     if (memcmp(dest, expected, destLen * sizeof(UChar))) {
2410         log_err("\nInvalid output with many added points, "
2411                 "expected '%s', got '%s'\n",
2412                 aescstrdup(expected, UPRV_LENGTHOF(expected)),
2413                 aescstrdup(dest, destLen));
2414     }
2415     ubidi_close(bidi);
2416 }
2417 
_testMisc(void)2418 static void _testMisc(void) {
2419     UErrorCode errorCode = U_ZERO_ERROR;
2420     UBiDi *bidi = ubidi_open();
2421     UChar src[3], dest[MAXLEN], expected[5];
2422     int destLen;
2423     ubidi_setInverse(bidi, TRUE);
2424     src[0] = src[1] = src[2] = 0x0020;
2425     ubidi_setPara(bidi, src, UPRV_LENGTHOF(src), UBIDI_RTL, NULL, &errorCode);
2426     destLen = ubidi_writeReordered(bidi, dest, MAXLEN,
2427               UBIDI_OUTPUT_REVERSE | UBIDI_INSERT_LRM_FOR_NUMERIC,
2428               &errorCode);
2429     u_unescape("\\u200f   \\u200f", expected, 5);
2430     if (memcmp(dest, expected, destLen * sizeof(UChar))) {
2431         log_err("\nInvalid output with RLM at both sides, "
2432                 "expected '%s', got '%s'\n",
2433                 aescstrdup(expected, UPRV_LENGTHOF(expected)),
2434                 aescstrdup(dest, destLen));
2435     }
2436     ubidi_close(bidi);
2437 }
2438 
2439 /* arabic shaping ----------------------------------------------------------- */
2440 
2441 static void
doArabicShapingTest(void)2442 doArabicShapingTest(void) {
2443     static const UChar
2444     source[]={
2445         0x31,   /* en:1 */
2446         0x627,  /* arabic:alef */
2447         0x32,   /* en:2 */
2448         0x6f3,  /* an:3 */
2449         0x61,   /* latin:a */
2450         0x34,   /* en:4 */
2451         0
2452     }, en2an[]={
2453         0x661, 0x627, 0x662, 0x6f3, 0x61, 0x664, 0
2454     }, an2en[]={
2455         0x31, 0x627, 0x32, 0x33, 0x61, 0x34, 0
2456     }, logical_alen2an_init_lr[]={
2457         0x31, 0x627, 0x662, 0x6f3, 0x61, 0x34, 0
2458     }, logical_alen2an_init_al[]={
2459         0x6f1, 0x627, 0x6f2, 0x6f3, 0x61, 0x34, 0
2460     }, reverse_alen2an_init_lr[]={
2461         0x661, 0x627, 0x32, 0x6f3, 0x61, 0x34, 0
2462     }, reverse_alen2an_init_al[]={
2463         0x6f1, 0x627, 0x32, 0x6f3, 0x61, 0x6f4, 0
2464     }, lamalef[]={
2465         0xfefb, 0
2466     };
2467     UChar dest[8];
2468     UErrorCode errorCode;
2469     int32_t length;
2470 
2471     /* test number shaping */
2472 
2473     /* european->arabic */
2474     errorCode=U_ZERO_ERROR;
2475     length=u_shapeArabic(source, UPRV_LENGTHOF(source),
2476                          dest, UPRV_LENGTHOF(dest),
2477                          U_SHAPE_DIGITS_EN2AN|U_SHAPE_DIGIT_TYPE_AN,
2478                          &errorCode);
2479     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(source) || memcmp(dest, en2an, length*U_SIZEOF_UCHAR)!=0) {
2480         log_err("failure in u_shapeArabic(en2an)\n");
2481     }
2482 
2483     /* arabic->european */
2484     errorCode=U_ZERO_ERROR;
2485     length=u_shapeArabic(source, -1,
2486                          dest, UPRV_LENGTHOF(dest),
2487                          U_SHAPE_DIGITS_AN2EN|U_SHAPE_DIGIT_TYPE_AN_EXTENDED,
2488                          &errorCode);
2489     if(U_FAILURE(errorCode) || length!=u_strlen(source) || memcmp(dest, an2en, length*U_SIZEOF_UCHAR)!=0) {
2490         log_err("failure in u_shapeArabic(an2en)\n");
2491     }
2492 
2493     /* european->arabic with context, logical order, initial state not AL */
2494     errorCode=U_ZERO_ERROR;
2495     length=u_shapeArabic(source, UPRV_LENGTHOF(source),
2496                          dest, UPRV_LENGTHOF(dest),
2497                          U_SHAPE_DIGITS_ALEN2AN_INIT_LR|U_SHAPE_DIGIT_TYPE_AN,
2498                          &errorCode);
2499     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(source) || memcmp(dest, logical_alen2an_init_lr, length*U_SIZEOF_UCHAR)!=0) {
2500         log_err("failure in u_shapeArabic(logical_alen2an_init_lr)\n");
2501     }
2502 
2503     /* european->arabic with context, logical order, initial state AL */
2504     errorCode=U_ZERO_ERROR;
2505     length=u_shapeArabic(source, UPRV_LENGTHOF(source),
2506                          dest, UPRV_LENGTHOF(dest),
2507                          U_SHAPE_DIGITS_ALEN2AN_INIT_AL|U_SHAPE_DIGIT_TYPE_AN_EXTENDED,
2508                          &errorCode);
2509     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(source) || memcmp(dest, logical_alen2an_init_al, length*U_SIZEOF_UCHAR)!=0) {
2510         log_err("failure in u_shapeArabic(logical_alen2an_init_al)\n");
2511     }
2512 
2513     /* european->arabic with context, reverse order, initial state not AL */
2514     errorCode=U_ZERO_ERROR;
2515     length=u_shapeArabic(source, UPRV_LENGTHOF(source),
2516                          dest, UPRV_LENGTHOF(dest),
2517                          U_SHAPE_DIGITS_ALEN2AN_INIT_LR|U_SHAPE_DIGIT_TYPE_AN|U_SHAPE_TEXT_DIRECTION_VISUAL_LTR,
2518                          &errorCode);
2519     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(source) || memcmp(dest, reverse_alen2an_init_lr, length*U_SIZEOF_UCHAR)!=0) {
2520         log_err("failure in u_shapeArabic(reverse_alen2an_init_lr)\n");
2521     }
2522 
2523     /* european->arabic with context, reverse order, initial state AL */
2524     errorCode=U_ZERO_ERROR;
2525     length=u_shapeArabic(source, UPRV_LENGTHOF(source),
2526                          dest, UPRV_LENGTHOF(dest),
2527                          U_SHAPE_DIGITS_ALEN2AN_INIT_AL|U_SHAPE_DIGIT_TYPE_AN_EXTENDED|U_SHAPE_TEXT_DIRECTION_VISUAL_LTR,
2528                          &errorCode);
2529     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(source) || memcmp(dest, reverse_alen2an_init_al, length*U_SIZEOF_UCHAR)!=0) {
2530         log_err("failure in u_shapeArabic(reverse_alen2an_init_al)\n");
2531     }
2532 
2533     /* test noop */
2534     errorCode=U_ZERO_ERROR;
2535     length=u_shapeArabic(source, UPRV_LENGTHOF(source),
2536                          dest, UPRV_LENGTHOF(dest),
2537                          0,
2538                          &errorCode);
2539     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(source) || memcmp(dest, source, length*U_SIZEOF_UCHAR)!=0) {
2540         log_err("failure in u_shapeArabic(noop)\n");
2541     }
2542 
2543     errorCode=U_ZERO_ERROR;
2544     length=u_shapeArabic(source, 0,
2545                          dest, UPRV_LENGTHOF(dest),
2546                          U_SHAPE_DIGITS_EN2AN|U_SHAPE_DIGIT_TYPE_AN,
2547                          &errorCode);
2548     if(U_FAILURE(errorCode) || length!=0) {
2549         log_err("failure in u_shapeArabic(en2an, sourceLength=0), returned %d/%s\n", u_errorName(errorCode), UPRV_LENGTHOF(source));
2550     }
2551 
2552     /* preflight digit shaping */
2553     errorCode=U_ZERO_ERROR;
2554     length=u_shapeArabic(source, UPRV_LENGTHOF(source),
2555                          NULL, 0,
2556                          U_SHAPE_DIGITS_EN2AN|U_SHAPE_DIGIT_TYPE_AN,
2557                          &errorCode);
2558     if(errorCode!=U_BUFFER_OVERFLOW_ERROR || length!=UPRV_LENGTHOF(source)) {
2559         log_err("failure in u_shapeArabic(en2an preflighting), returned %d/%s instead of %d/U_BUFFER_OVERFLOW_ERROR\n",
2560                 length, u_errorName(errorCode), UPRV_LENGTHOF(source));
2561     }
2562 
2563     /* test illegal arguments */
2564     errorCode=U_ZERO_ERROR;
2565     length=u_shapeArabic(NULL, UPRV_LENGTHOF(source),
2566                          dest, UPRV_LENGTHOF(dest),
2567                          U_SHAPE_DIGITS_EN2AN|U_SHAPE_DIGIT_TYPE_AN,
2568                          &errorCode);
2569     if(errorCode!=U_ILLEGAL_ARGUMENT_ERROR) {
2570         log_err("failure in u_shapeArabic(source=NULL), returned %s instead of U_ILLEGAL_ARGUMENT_ERROR\n", u_errorName(errorCode));
2571     }
2572 
2573     errorCode=U_ZERO_ERROR;
2574     length=u_shapeArabic(source, -2,
2575                          dest, UPRV_LENGTHOF(dest),
2576                          U_SHAPE_DIGITS_EN2AN|U_SHAPE_DIGIT_TYPE_AN,
2577                          &errorCode);
2578     if(errorCode!=U_ILLEGAL_ARGUMENT_ERROR) {
2579         log_err("failure in u_shapeArabic(sourceLength=-2), returned %s instead of U_ILLEGAL_ARGUMENT_ERROR\n", u_errorName(errorCode));
2580     }
2581 
2582     errorCode=U_ZERO_ERROR;
2583     length=u_shapeArabic(source, UPRV_LENGTHOF(source),
2584                          NULL, UPRV_LENGTHOF(dest),
2585                          U_SHAPE_DIGITS_EN2AN|U_SHAPE_DIGIT_TYPE_AN,
2586                          &errorCode);
2587     if(errorCode!=U_ILLEGAL_ARGUMENT_ERROR) {
2588         log_err("failure in u_shapeArabic(dest=NULL), returned %s instead of U_ILLEGAL_ARGUMENT_ERROR\n", u_errorName(errorCode));
2589     }
2590 
2591     errorCode=U_ZERO_ERROR;
2592     length=u_shapeArabic(source, UPRV_LENGTHOF(source),
2593                          dest, -1,
2594                          U_SHAPE_DIGITS_EN2AN|U_SHAPE_DIGIT_TYPE_AN,
2595                          &errorCode);
2596     if(errorCode!=U_ILLEGAL_ARGUMENT_ERROR) {
2597         log_err("failure in u_shapeArabic(destSize=-1), returned %s instead of U_ILLEGAL_ARGUMENT_ERROR\n", u_errorName(errorCode));
2598     }
2599 
2600     errorCode=U_ZERO_ERROR;
2601     length=u_shapeArabic(source, UPRV_LENGTHOF(source),
2602                          dest, UPRV_LENGTHOF(dest),
2603                          U_SHAPE_DIGITS_RESERVED|U_SHAPE_DIGIT_TYPE_AN,
2604                          &errorCode);
2605     if(errorCode!=U_ILLEGAL_ARGUMENT_ERROR) {
2606         log_err("failure in u_shapeArabic(U_SHAPE_DIGITS_RESERVED), returned %s instead of U_ILLEGAL_ARGUMENT_ERROR\n", u_errorName(errorCode));
2607     }
2608 
2609     errorCode=U_ZERO_ERROR;
2610     length=u_shapeArabic(source, UPRV_LENGTHOF(source),
2611                          dest, UPRV_LENGTHOF(dest),
2612                          U_SHAPE_DIGITS_EN2AN|U_SHAPE_DIGIT_TYPE_RESERVED,
2613                          &errorCode);
2614     if(errorCode!=U_ILLEGAL_ARGUMENT_ERROR) {
2615         log_err("failure in u_shapeArabic(U_SHAPE_DIGIT_TYPE_RESERVED), returned %s instead of U_ILLEGAL_ARGUMENT_ERROR\n", u_errorName(errorCode));
2616     }
2617 
2618     errorCode=U_ZERO_ERROR;
2619     length=u_shapeArabic(source, UPRV_LENGTHOF(source),
2620                          (UChar *)(source+2), UPRV_LENGTHOF(dest), /* overlap source and destination */
2621                          U_SHAPE_DIGITS_EN2AN|U_SHAPE_DIGIT_TYPE_AN,
2622                          &errorCode);
2623     if(errorCode!=U_ILLEGAL_ARGUMENT_ERROR) {
2624         log_err("failure in u_shapeArabic(U_SHAPE_DIGIT_TYPE_RESERVED), returned %s instead of U_ILLEGAL_ARGUMENT_ERROR\n", u_errorName(errorCode));
2625     }
2626 
2627     errorCode=U_ZERO_ERROR;
2628     length=u_shapeArabic(lamalef, UPRV_LENGTHOF(lamalef),
2629                          dest, UPRV_LENGTHOF(dest),
2630                          U_SHAPE_LETTERS_UNSHAPE | U_SHAPE_LENGTH_GROW_SHRINK | U_SHAPE_TEXT_DIRECTION_VISUAL_LTR,
2631                          &errorCode);
2632     if(U_FAILURE(errorCode) || length == UPRV_LENGTHOF(lamalef)) {
2633         log_err("failure in u_shapeArabic(U_SHAPE_LETTERS_UNSHAPE | U_SHAPE_LENGTH_GROW_SHRINK | U_SHAPE_TEXT_DIRECTION_VISUAL_LTR)\n");
2634         log_err("returned %s instead of U_ZERO_ERROR or returned length %d instead of 3\n", u_errorName(errorCode), length);
2635     }
2636 }
2637 
2638 static void
doLamAlefSpecialVLTRArabicShapingTest(void)2639 doLamAlefSpecialVLTRArabicShapingTest(void) {
2640     static const UChar
2641     source[]={
2642 /*a*/   0x20 ,0x646,0x622,0x644,0x627,0x20,
2643 /*b*/   0x646,0x623,0x64E,0x644,0x627,0x20,
2644 /*c*/   0x646,0x627,0x670,0x644,0x627,0x20,
2645 /*d*/   0x646,0x622,0x653,0x644,0x627,0x20,
2646 /*e*/   0x646,0x625,0x655,0x644,0x627,0x20,
2647 /*f*/   0x646,0x622,0x654,0x644,0x627,0x20,
2648 /*g*/   0xFEFC,0x639
2649     }, shape_near[]={
2650         0x20,0xfee5,0x20,0xfef5,0xfe8d,0x20,0xfee5,0x20,0xfe76,0xfef7,0xfe8d,0x20,
2651         0xfee5,0x20,0x670,0xfefb,0xfe8d,0x20,0xfee5,0x20,0x653,0xfef5,0xfe8d,0x20,
2652         0xfee5,0x20,0x655,0xfef9,0xfe8d,0x20,0xfee5,0x20,0x654,0xfef5,0xfe8d,0x20,
2653         0xfefc,0xfecb
2654     }, shape_at_end[]={
2655         0x20,0xfee5,0xfef5,0xfe8d,0x20,0xfee5,0xfe76,0xfef7,0xfe8d,0x20,0xfee5,0x670,
2656         0xfefb,0xfe8d,0x20,0xfee5,0x653,0xfef5,0xfe8d,0x20,0xfee5,0x655,0xfef9,0xfe8d,
2657         0x20,0xfee5,0x654,0xfef5,0xfe8d,0x20,0xfefc,0xfecb,0x20,0x20,0x20,0x20,0x20,0x20
2658     }, shape_at_begin[]={
2659         0x20,0x20,0x20,0x20,0x20,0x20,0x20,0xfee5,0xfef5,0xfe8d,0x20,0xfee5,0xfe76,
2660         0xfef7,0xfe8d,0x20,0xfee5,0x670,0xfefb,0xfe8d,0x20,0xfee5,0x653,0xfef5,0xfe8d,
2661         0x20,0xfee5,0x655,0xfef9,0xfe8d,0x20,0xfee5,0x654,0xfef5,0xfe8d,0x20,0xfefc,0xfecb
2662     }, shape_grow_shrink[]={
2663         0x20,0xfee5,0xfef5,0xfe8d,0x20,0xfee5,0xfe76,0xfef7,0xfe8d,0x20,0xfee5,
2664         0x670,0xfefb,0xfe8d,0x20,0xfee5,0x653,0xfef5,0xfe8d,0x20,0xfee5,0x655,0xfef9,
2665         0xfe8d,0x20,0xfee5,0x654,0xfef5,0xfe8d,0x20,0xfefc,0xfecb
2666     }, shape_excepttashkeel_near[]={
2667         0x20,0xfee5,0x20,0xfef5,0xfe8d,0x20,0xfee5,0x20,0xfe76,0xfef7,0xfe8d,0x20,
2668         0xfee5,0x20,0x670,0xfefb,0xfe8d,0x20,0xfee5,0x20,0x653,0xfef5,0xfe8d,0x20,
2669         0xfee5,0x20,0x655,0xfef9,0xfe8d,0x20,0xfee5,0x20,0x654,0xfef5,0xfe8d,0x20,
2670         0xfefc,0xfecb
2671     }, shape_excepttashkeel_at_end[]={
2672         0x20,0xfee5,0xfef5,0xfe8d,0x20,0xfee5,0xfe76,0xfef7,0xfe8d,0x20,0xfee5,
2673         0x670,0xfefb,0xfe8d,0x20,0xfee5,0x653,0xfef5,0xfe8d,0x20,0xfee5,0x655,0xfef9,
2674         0xfe8d,0x20,0xfee5,0x654,0xfef5,0xfe8d,0x20,0xfefc,0xfecb,0x20,0x20,0x20,
2675         0x20,0x20,0x20
2676     }, shape_excepttashkeel_at_begin[]={
2677         0x20,0x20,0x20,0x20,0x20,0x20,0x20,0xfee5,0xfef5,0xfe8d,0x20,0xfee5,0xfe76,
2678         0xfef7,0xfe8d,0x20,0xfee5,0x670,0xfefb,0xfe8d,0x20,0xfee5,0x653,0xfef5,0xfe8d,
2679         0x20,0xfee5,0x655,0xfef9,0xfe8d,0x20,0xfee5,0x654,0xfef5,0xfe8d,0x20,0xfefc,0xfecb
2680     }, shape_excepttashkeel_grow_shrink[]={
2681         0x20,0xfee5,0xfef5,0xfe8d,0x20,0xfee5,0xfe76,0xfef7,0xfe8d,0x20,0xfee5,0x670,
2682         0xfefb,0xfe8d,0x20,0xfee5,0x653,0xfef5,0xfe8d,0x20,0xfee5,0x655,0xfef9,0xfe8d,
2683         0x20,0xfee5,0x654,0xfef5,0xfe8d,0x20,0xfefc,0xfecb
2684     };
2685 
2686     UChar dest[38];
2687     UErrorCode errorCode;
2688     int32_t length;
2689 
2690     errorCode=U_ZERO_ERROR;
2691 
2692     length=u_shapeArabic(source, UPRV_LENGTHOF(source),
2693                          dest, UPRV_LENGTHOF(dest),
2694                          U_SHAPE_LETTERS_SHAPE|U_SHAPE_LENGTH_FIXED_SPACES_NEAR|
2695                          U_SHAPE_TEXT_DIRECTION_VISUAL_LTR,
2696                          &errorCode);
2697 
2698     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(shape_near) || memcmp(dest, shape_near, length*U_SIZEOF_UCHAR)!=0) {
2699         log_err("failure in u_shapeArabic(LAMALEF shape_near)\n");
2700     }
2701 
2702     errorCode=U_ZERO_ERROR;
2703 
2704     length=u_shapeArabic(source, UPRV_LENGTHOF(source),
2705                          dest, UPRV_LENGTHOF(dest),
2706                          U_SHAPE_LETTERS_SHAPE|U_SHAPE_LENGTH_FIXED_SPACES_AT_END|
2707                          U_SHAPE_TEXT_DIRECTION_VISUAL_LTR,
2708                          &errorCode);
2709 
2710     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(shape_at_end) || memcmp(dest, shape_at_end, length*U_SIZEOF_UCHAR)!=0) {
2711         log_err("failure in u_shapeArabic(LAMALEF shape_at_end)\n");
2712     }
2713 
2714     errorCode=U_ZERO_ERROR;
2715 
2716     length=u_shapeArabic(source, UPRV_LENGTHOF(source),
2717                          dest, UPRV_LENGTHOF(dest),
2718                          U_SHAPE_LETTERS_SHAPE|U_SHAPE_LENGTH_FIXED_SPACES_AT_BEGINNING|
2719                          U_SHAPE_TEXT_DIRECTION_VISUAL_LTR,
2720                          &errorCode);
2721 
2722     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(shape_at_begin) || memcmp(dest, shape_at_begin, length*U_SIZEOF_UCHAR)!=0) {
2723         log_err("failure in u_shapeArabic(LAMALEF shape_at_begin)\n");
2724     }
2725 
2726     errorCode=U_ZERO_ERROR;
2727 
2728     length=u_shapeArabic(source, UPRV_LENGTHOF(source),
2729                          dest, UPRV_LENGTHOF(dest),
2730                          U_SHAPE_LETTERS_SHAPE|U_SHAPE_LENGTH_GROW_SHRINK|
2731                          U_SHAPE_TEXT_DIRECTION_VISUAL_LTR,
2732                          &errorCode);
2733 
2734     if(U_FAILURE(errorCode) || memcmp(dest, shape_grow_shrink, length*U_SIZEOF_UCHAR)!=0) {
2735         log_err("failure in u_shapeArabic(LAMALEF shape_grow_shrink)\n");
2736     }
2737 
2738     /* ==================== U_SHAPE_LETTERS_SHAPE_TASHKEEL_ISOLATED ==================== */
2739 
2740     errorCode=U_ZERO_ERROR;
2741 
2742     length=u_shapeArabic(source, UPRV_LENGTHOF(source),
2743                          dest, UPRV_LENGTHOF(dest),
2744                          U_SHAPE_LETTERS_SHAPE_TASHKEEL_ISOLATED|U_SHAPE_LENGTH_FIXED_SPACES_NEAR|
2745                          U_SHAPE_TEXT_DIRECTION_VISUAL_LTR,
2746                          &errorCode);
2747 
2748     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(shape_excepttashkeel_near) || memcmp(dest, shape_excepttashkeel_near, length*U_SIZEOF_UCHAR)!=0) {
2749         log_err("failure in u_shapeArabic(LAMALEF shape_excepttashkeel_near)\n");
2750     }
2751 
2752     errorCode=U_ZERO_ERROR;
2753 
2754     length=u_shapeArabic(source, UPRV_LENGTHOF(source),
2755                          dest, UPRV_LENGTHOF(dest),
2756                          U_SHAPE_LETTERS_SHAPE_TASHKEEL_ISOLATED|U_SHAPE_LENGTH_FIXED_SPACES_AT_END|
2757                          U_SHAPE_TEXT_DIRECTION_VISUAL_LTR,
2758                          &errorCode);
2759 
2760     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(shape_excepttashkeel_at_end) || memcmp(dest,shape_excepttashkeel_at_end , length*U_SIZEOF_UCHAR)!=0) {
2761         log_err("failure in u_shapeArabic(LAMALEF shape_excepttashkeel_at_end)\n");
2762     }
2763 
2764     errorCode=U_ZERO_ERROR;
2765 
2766     length=u_shapeArabic(source, UPRV_LENGTHOF(source),
2767                          dest, UPRV_LENGTHOF(dest),
2768                          U_SHAPE_LETTERS_SHAPE_TASHKEEL_ISOLATED|U_SHAPE_LENGTH_FIXED_SPACES_AT_BEGINNING|
2769                          U_SHAPE_TEXT_DIRECTION_VISUAL_LTR,
2770                          &errorCode);
2771 
2772     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(shape_excepttashkeel_at_begin) || memcmp(dest, shape_excepttashkeel_at_begin, length*U_SIZEOF_UCHAR)!=0) {
2773         log_err("failure in u_shapeArabic(LAMALEF shape_excepttashkeel_at_begin)\n");
2774     }
2775 
2776     errorCode=U_ZERO_ERROR;
2777 
2778     length=u_shapeArabic(source, UPRV_LENGTHOF(source),
2779                          dest, UPRV_LENGTHOF(dest),
2780                          U_SHAPE_LETTERS_SHAPE_TASHKEEL_ISOLATED|U_SHAPE_LENGTH_GROW_SHRINK|
2781                          U_SHAPE_TEXT_DIRECTION_VISUAL_LTR,
2782                          &errorCode);
2783 
2784     if(U_FAILURE(errorCode) || memcmp(dest, shape_excepttashkeel_grow_shrink, length*U_SIZEOF_UCHAR)!=0) {
2785         log_err("failure in u_shapeArabic(LAMALEF shape_excepttashkeel_grow_shrink)\n");
2786     }
2787 }
2788 
2789 static void
doTashkeelSpecialVLTRArabicShapingTest(void)2790 doTashkeelSpecialVLTRArabicShapingTest(void) {
2791     static const UChar
2792     source[]={
2793         0x64A,0x628,0x631,0x639,0x20,
2794         0x64A,0x628,0x651,0x631,0x64E,0x639,0x20,
2795         0x64C,0x64A,0x628,0x631,0x64F,0x639,0x20,
2796         0x628,0x670,0x631,0x670,0x639,0x20,
2797         0x628,0x653,0x631,0x653,0x639,0x20,
2798         0x628,0x654,0x631,0x654,0x639,0x20,
2799         0x628,0x655,0x631,0x655,0x639,0x20,
2800     }, shape_near[]={
2801         0xfef2,0xfe91,0xfeae,0xfecb,0x20,0xfef2,0xfe91,0xfe7c,0xfeae,0xfe77,0xfecb,
2802         0x20,0xfe72,0xfef2,0xfe91,0xfeae,0xfe79,0xfecb,0x20,0xfe8f,0x670,0xfeae,0x670,
2803         0xfecb,0x20,0xfe8f,0x653,0xfeae,0x653,0xfecb,0x20,0xfe8f,0x654,0xfeae,0x654,
2804         0xfecb,0x20,0xfe8f,0x655,0xfeae,0x655,0xfecb,0x20
2805     }, shape_excepttashkeel_near[]={
2806         0xfef2,0xfe91,0xfeae,0xfecb,0x20,0xfef2,0xfe91,0xfe7c,0xfeae,0xfe76,0xfecb,0x20,
2807         0xfe72,0xfef2,0xfe91,0xfeae,0xfe78,0xfecb,0x20,0xfe8f,0x670,0xfeae,0x670,0xfecb,
2808         0x20,0xfe8f,0x653,0xfeae,0x653,0xfecb,0x20,0xfe8f,0x654,0xfeae,0x654,0xfecb,0x20,
2809         0xfe8f,0x655,0xfeae,0x655,0xfecb,0x20
2810     };
2811 
2812     UChar dest[43];
2813     UErrorCode errorCode;
2814     int32_t length;
2815 
2816     errorCode=U_ZERO_ERROR;
2817 
2818     length=u_shapeArabic(source, UPRV_LENGTHOF(source),
2819                          dest, UPRV_LENGTHOF(dest),
2820                          U_SHAPE_LETTERS_SHAPE|U_SHAPE_LENGTH_FIXED_SPACES_NEAR|
2821                          U_SHAPE_TEXT_DIRECTION_VISUAL_LTR,
2822                          &errorCode);
2823 
2824     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(shape_near) || memcmp(dest, shape_near, length*U_SIZEOF_UCHAR)!=0) {
2825         log_err("failure in u_shapeArabic(TASHKEEL shape_near)\n");
2826     }
2827 
2828     errorCode=U_ZERO_ERROR;
2829 
2830     length=u_shapeArabic(source, UPRV_LENGTHOF(source),
2831                          dest, UPRV_LENGTHOF(dest),
2832                          U_SHAPE_LETTERS_SHAPE_TASHKEEL_ISOLATED|U_SHAPE_LENGTH_FIXED_SPACES_NEAR|
2833                          U_SHAPE_TEXT_DIRECTION_VISUAL_LTR,
2834                          &errorCode);
2835 
2836     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(shape_excepttashkeel_near) || memcmp(dest, shape_excepttashkeel_near, length*U_SIZEOF_UCHAR)!=0) {
2837         log_err("failure in u_shapeArabic(TASHKEEL shape_excepttashkeel_near)\n");
2838     }
2839 }
2840 
2841 static void
doLOGICALArabicDeShapingTest(void)2842 doLOGICALArabicDeShapingTest(void) {
2843     static const UChar
2844     source[]={
2845         0x0020,0x0020,0x0020,0xFE8D,0xFEF5,0x0020,0xFEE5,0x0020,0xFE8D,0xFEF7,0x0020,
2846         0xFED7,0xFEFC,0x0020,0xFEE1,0x0020,0xFE8D,0xFEDF,0xFECC,0xFEAE,0xFE91,0xFEF4,
2847         0xFE94,0x0020,0xFE8D,0xFEDF,0xFEA4,0xFEAE,0xFE93,0x0020,0x0020,0x0020,0x0020
2848     }, unshape_near[]={
2849         0x20,0x20,0x20,0x627,0x644,0x622,0x646,0x20,0x627,0x644,0x623,0x642,0x644,0x627,
2850         0x645,0x20,0x627,0x644,0x639,0x631,0x628,0x64a,0x629,0x20,0x627,0x644,0x62d,0x631,
2851         0x629,0x20,0x20,0x20,0x20
2852     }, unshape_at_end[]={
2853         0x20,0x20,0x20,0x627,0x644,0x622,0x20,0x646,0x20,0x627,0x644,0x623,0x20,0x642,
2854         0x644,0x627,0x20,0x645,0x20,0x627,0x644,0x639,0x631,0x628,0x64a,0x629,0x20,0x627,
2855         0x644,0x62d,0x631,0x629,0x20
2856     }, unshape_at_begin[]={
2857         0x627,0x644,0x622,0x20,0x646,0x20,0x627,0x644,0x623,0x20,0x642,0x644,0x627,0x20,
2858         0x645,0x20,0x627,0x644,0x639,0x631,0x628,0x64a,0x629,0x20,0x627,0x644,0x62d,0x631,
2859         0x629,0x20,0x20,0x20,0x20
2860     }, unshape_grow_shrink[]={
2861         0x20,0x20,0x20,0x627,0x644,0x622,0x20,0x646,0x20,0x627,0x644,0x623,0x20,0x642,
2862         0x644,0x627,0x20,0x645,0x20,0x627,0x644,0x639,0x631,0x628,0x64a,0x629,0x20,0x627,
2863         0x644,0x62d,0x631,0x629,0x20,0x20,0x20,0x20
2864     };
2865 
2866     UChar dest[36];
2867     UErrorCode errorCode;
2868     int32_t length;
2869 
2870     errorCode=U_ZERO_ERROR;
2871 
2872     length=u_shapeArabic(source, UPRV_LENGTHOF(source),
2873                          dest, UPRV_LENGTHOF(dest),
2874                          U_SHAPE_LETTERS_UNSHAPE|U_SHAPE_LENGTH_FIXED_SPACES_NEAR|
2875                          U_SHAPE_TEXT_DIRECTION_LOGICAL,
2876                          &errorCode);
2877 
2878     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(unshape_near) || memcmp(dest, unshape_near, length*U_SIZEOF_UCHAR)!=0) {
2879         log_err("failure in u_shapeArabic(unshape_near)\n");
2880     }
2881 
2882     errorCode=U_ZERO_ERROR;
2883 
2884     length=u_shapeArabic(source, UPRV_LENGTHOF(source),
2885                          dest, UPRV_LENGTHOF(dest),
2886                          U_SHAPE_LETTERS_UNSHAPE|U_SHAPE_LENGTH_FIXED_SPACES_AT_END|
2887                          U_SHAPE_TEXT_DIRECTION_LOGICAL,
2888                          &errorCode);
2889 
2890     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(unshape_at_end) || memcmp(dest, unshape_at_end, length*U_SIZEOF_UCHAR)!=0) {
2891         log_err("failure in u_shapeArabic(unshape_at_end)\n");
2892     }
2893 
2894     errorCode=U_ZERO_ERROR;
2895 
2896     length=u_shapeArabic(source, UPRV_LENGTHOF(source),
2897                          dest, UPRV_LENGTHOF(dest),
2898                          U_SHAPE_LETTERS_UNSHAPE|U_SHAPE_LENGTH_FIXED_SPACES_AT_BEGINNING|
2899                          U_SHAPE_TEXT_DIRECTION_LOGICAL,
2900                          &errorCode);
2901 
2902     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(unshape_at_begin) || memcmp(dest, unshape_at_begin, length*U_SIZEOF_UCHAR)!=0) {
2903         log_err("failure in u_shapeArabic(unshape_at_begin)\n");
2904     }
2905 
2906     errorCode=U_ZERO_ERROR;
2907 
2908     length=u_shapeArabic(source, UPRV_LENGTHOF(source),
2909                          dest, UPRV_LENGTHOF(dest),
2910                          U_SHAPE_LETTERS_UNSHAPE|U_SHAPE_LENGTH_GROW_SHRINK|
2911                          U_SHAPE_TEXT_DIRECTION_LOGICAL,
2912                          &errorCode);
2913 
2914     if(U_FAILURE(errorCode) || memcmp(dest, unshape_grow_shrink, length*U_SIZEOF_UCHAR)!=0) {
2915         log_err("failure in u_shapeArabic(unshape_grow_shrink)\n");
2916     }
2917 
2918 }
2919 
2920 static void
doTailTest(void)2921 doTailTest(void) {
2922   static const UChar src[] = { 0x0020, 0x0633, 0 };
2923   static const UChar dst_old[] = { 0xFEB1, 0x200B,0 };
2924   static const UChar dst_new[] = { 0xFEB1, 0xFE73,0 };
2925   UChar dst[3] = { 0x0000, 0x0000,0 };
2926   int32_t length;
2927   UErrorCode status;
2928 
2929   log_verbose("SRC: U+%04X U+%04X\n", src[0],src[1]);
2930 
2931   log_verbose("Trying old tail\n");
2932   status = U_ZERO_ERROR;
2933   length = u_shapeArabic(src, -1, dst, UPRV_LENGTHOF(dst),
2934                          U_SHAPE_LETTERS_SHAPE|U_SHAPE_SEEN_TWOCELL_NEAR, &status);
2935   if(U_FAILURE(status)) {
2936     log_err("Fail: status %s\n", u_errorName(status));
2937   } else if(length!=2) {
2938     log_err("Fail: len %d expected 3\n", length);
2939   } else if(u_strncmp(dst,dst_old,UPRV_LENGTHOF(dst))) {
2940     log_err("Fail: got U+%04X U+%04X expected U+%04X U+%04X\n",
2941             dst[0],dst[1],dst_old[0],dst_old[1]);
2942   } else {
2943     log_verbose("OK:  U+%04X U+%04X len %d err %s\n",
2944             dst[0],dst[1],length,u_errorName(status));
2945   }
2946 
2947 
2948   log_verbose("Trying new tail\n");
2949   status = U_ZERO_ERROR;
2950   length = u_shapeArabic(src, -1, dst, UPRV_LENGTHOF(dst),
2951                          U_SHAPE_LETTERS_SHAPE|U_SHAPE_SEEN_TWOCELL_NEAR|U_SHAPE_TAIL_NEW_UNICODE, &status);
2952   if(U_FAILURE(status)) {
2953     log_err("Fail: status %s\n", u_errorName(status));
2954   } else if(length!=2) {
2955     log_err("Fail: len %d expected 3\n", length);
2956   } else if(u_strncmp(dst,dst_new,UPRV_LENGTHOF(dst))) {
2957     log_err("Fail: got U+%04X U+%04X expected U+%04X U+%04X\n",
2958             dst[0],dst[1],dst_new[0],dst_new[1]);
2959   } else {
2960     log_verbose("OK:  U+%04X U+%04X len %d err %s\n",
2961             dst[0],dst[1],length,u_errorName(status));
2962   }
2963 }
2964 
2965 static void
doArabicShapingTestForBug5421(void)2966 doArabicShapingTestForBug5421(void) {
2967     static const UChar
2968     persian_letters_source[]={
2969         0x0020, 0x0698, 0x067E, 0x0686, 0x06AF, 0x0020
2970     }, persian_letters[]={
2971         0x0020, 0xFB8B, 0xFB59, 0xFB7D, 0xFB94, 0x0020
2972     }, tashkeel_aggregation_source[]={
2973         0x0020, 0x0628, 0x0651, 0x064E, 0x062A, 0x0631, 0x0645, 0x0020,
2974         0x0628, 0x064E, 0x0651, 0x062A, 0x0631, 0x0645, 0x0020
2975     }, tashkeel_aggregation[]={
2976         0x0020, 0xFE90, 0xFC60, 0xFE97, 0xFEAE, 0xFEE3,
2977         0x0020, 0xFE90, 0xFC60, 0xFE97, 0xFEAE, 0xFEE3, 0x0020
2978     }, untouched_presentation_source[]={
2979         0x0020 ,0x0627, 0xfe90,0x0020
2980     }, untouched_presentation[]={
2981         0x0020,0xfe8D, 0xfe90,0x0020
2982     }, untouched_presentation_r_source[]={
2983         0x0020 ,0xfe90, 0x0627, 0x0020
2984     }, untouched_presentation_r[]={
2985         0x0020, 0xfe90,0xfe8D,0x0020
2986     };
2987 
2988     UChar dest[38];
2989     UErrorCode errorCode;
2990     int32_t length;
2991 
2992     errorCode=U_ZERO_ERROR;
2993 
2994     length=u_shapeArabic(persian_letters_source, UPRV_LENGTHOF(persian_letters_source),
2995                          dest, UPRV_LENGTHOF(dest),
2996                          U_SHAPE_LETTERS_SHAPE|U_SHAPE_TEXT_DIRECTION_VISUAL_LTR,
2997                          &errorCode);
2998 
2999     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(persian_letters) || memcmp(dest, persian_letters, length*U_SIZEOF_UCHAR)!=0) {
3000         log_err("failure in u_shapeArabic(persian_letters)\n");
3001     }
3002 
3003     errorCode=U_ZERO_ERROR;
3004 
3005     length=u_shapeArabic(tashkeel_aggregation_source, UPRV_LENGTHOF(tashkeel_aggregation_source),
3006                          dest, UPRV_LENGTHOF(dest),
3007                          U_SHAPE_AGGREGATE_TASHKEEL|U_SHAPE_PRESERVE_PRESENTATION|
3008                          U_SHAPE_LETTERS_SHAPE_TASHKEEL_ISOLATED|U_SHAPE_TEXT_DIRECTION_VISUAL_LTR,
3009                          &errorCode);
3010 
3011     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(tashkeel_aggregation) || memcmp(dest, tashkeel_aggregation, length*U_SIZEOF_UCHAR)!=0) {
3012         log_err("failure in u_shapeArabic(tashkeel_aggregation)\n");
3013     }
3014 
3015     errorCode=U_ZERO_ERROR;
3016 
3017     length=u_shapeArabic(untouched_presentation_source, UPRV_LENGTHOF(untouched_presentation_source),
3018                          dest, UPRV_LENGTHOF(dest),
3019                          U_SHAPE_PRESERVE_PRESENTATION|
3020                          U_SHAPE_LETTERS_SHAPE|U_SHAPE_TEXT_DIRECTION_VISUAL_LTR,
3021                          &errorCode);
3022 
3023     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(untouched_presentation) || memcmp(dest, untouched_presentation, length*U_SIZEOF_UCHAR)!=0) {
3024         log_err("failure in u_shapeArabic(untouched_presentation)\n");
3025     }
3026 
3027     errorCode=U_ZERO_ERROR;
3028 
3029     length=u_shapeArabic(untouched_presentation_r_source, UPRV_LENGTHOF(untouched_presentation_r_source),
3030                          dest, UPRV_LENGTHOF(dest),
3031                          U_SHAPE_PRESERVE_PRESENTATION|
3032                          U_SHAPE_LETTERS_SHAPE|U_SHAPE_TEXT_DIRECTION_LOGICAL,
3033                          &errorCode);
3034 
3035     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(untouched_presentation_r) || memcmp(dest, untouched_presentation_r, length*U_SIZEOF_UCHAR)!=0) {
3036         log_err("failure in u_shapeArabic(untouched_presentation_r)\n");
3037     }
3038 }
3039 
3040 static void
doArabicShapingTestForBug8703(void)3041 doArabicShapingTestForBug8703(void) {
3042     static const UChar
3043     letters_source1[]={
3044         0x0634,0x0651,0x0645,0x0652,0x0633
3045     }, letters_source2[]={
3046         0x0634,0x0651,0x0645,0x0652,0x0633
3047     }, letters_source3[]={
3048        0x0634,0x0651,0x0645,0x0652,0x0633
3049     }, letters_source4[]={
3050         0x0634,0x0651,0x0645,0x0652,0x0633
3051     }, letters_source5[]={
3052         0x0633,0x0652,0x0645,0x0651,0x0634
3053     }, letters_source6[]={
3054         0x0633,0x0652,0x0645,0x0651,0x0634
3055     }, letters_source7[]={
3056         0x0633,0x0652,0x0645,0x0651,0x0634
3057     }, letters_source8[]={
3058         0x0633,0x0652,0x0645,0x0651,0x0634
3059     }, letters_dest1[]={
3060         0x0020,0xFEB7,0xFE7D,0xFEE4,0xFEB2
3061     }, letters_dest2[]={
3062         0xFEB7,0xFE7D,0xFEE4,0xFEB2,0x0020
3063     }, letters_dest3[]={
3064         0xFEB7,0xFE7D,0xFEE4,0xFEB2
3065     }, letters_dest4[]={
3066         0xFEB7,0xFE7D,0xFEE4,0x0640,0xFEB2
3067     }, letters_dest5[]={
3068         0x0020,0xFEB2,0xFEE4,0xFE7D,0xFEB7
3069     }, letters_dest6[]={
3070         0xFEB2,0xFEE4,0xFE7D,0xFEB7,0x0020
3071     }, letters_dest7[]={
3072         0xFEB2,0xFEE4,0xFE7D,0xFEB7
3073     }, letters_dest8[]={
3074         0xFEB2,0x0640,0xFEE4,0xFE7D,0xFEB7
3075     };
3076 
3077     UChar dest[20];
3078     UErrorCode errorCode;
3079     int32_t length;
3080 
3081     errorCode=U_ZERO_ERROR;
3082 
3083     length=u_shapeArabic(letters_source1, UPRV_LENGTHOF(letters_source1),
3084                          dest, UPRV_LENGTHOF(dest),
3085                          U_SHAPE_TEXT_DIRECTION_VISUAL_RTL | U_SHAPE_TASHKEEL_BEGIN | U_SHAPE_LETTERS_SHAPE,
3086                          &errorCode);
3087 
3088     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(letters_dest1) || memcmp(dest, letters_dest1, length*U_SIZEOF_UCHAR)!=0) {
3089         log_err("failure in u_shapeArabic(letters_source1)\n");
3090     }
3091 
3092     errorCode=U_ZERO_ERROR;
3093 
3094     length=u_shapeArabic(letters_source2, UPRV_LENGTHOF(letters_source2),
3095                          dest, UPRV_LENGTHOF(dest),
3096                          U_SHAPE_TEXT_DIRECTION_VISUAL_RTL | U_SHAPE_TASHKEEL_END | U_SHAPE_LETTERS_SHAPE,
3097                          &errorCode);
3098 
3099     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(letters_dest2) || memcmp(dest, letters_dest2, length*U_SIZEOF_UCHAR)!=0) {
3100         log_err("failure in u_shapeArabic(letters_source2)\n");
3101     }
3102 
3103     errorCode=U_ZERO_ERROR;
3104 
3105     length=u_shapeArabic(letters_source3, UPRV_LENGTHOF(letters_source3),
3106                          dest, UPRV_LENGTHOF(dest),
3107                          U_SHAPE_TEXT_DIRECTION_VISUAL_RTL | U_SHAPE_TASHKEEL_RESIZE | U_SHAPE_LETTERS_SHAPE,
3108                          &errorCode);
3109 
3110     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(letters_dest3) || memcmp(dest, letters_dest3, length*U_SIZEOF_UCHAR)!=0) {
3111         log_err("failure in u_shapeArabic(letters_source3)\n");
3112     }
3113 
3114     errorCode=U_ZERO_ERROR;
3115 
3116     length=u_shapeArabic(letters_source4, UPRV_LENGTHOF(letters_source4),
3117                          dest, UPRV_LENGTHOF(dest),
3118                          U_SHAPE_TEXT_DIRECTION_VISUAL_RTL | U_SHAPE_TASHKEEL_REPLACE_BY_TATWEEL | U_SHAPE_LETTERS_SHAPE,
3119                          &errorCode);
3120 
3121     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(letters_dest4) || memcmp(dest, letters_dest4, length*U_SIZEOF_UCHAR)!=0) {
3122         log_err("failure in u_shapeArabic(letters_source4)\n");
3123     }
3124 
3125     errorCode=U_ZERO_ERROR;
3126 
3127     length=u_shapeArabic(letters_source5, UPRV_LENGTHOF(letters_source5),
3128                          dest, UPRV_LENGTHOF(dest),
3129                          U_SHAPE_TEXT_DIRECTION_VISUAL_LTR | U_SHAPE_TASHKEEL_BEGIN | U_SHAPE_LETTERS_SHAPE,
3130                          &errorCode);
3131 
3132     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(letters_dest5) || memcmp(dest, letters_dest5, length*U_SIZEOF_UCHAR)!=0) {
3133         log_err("failure in u_shapeArabic(letters_source5)\n");
3134     }
3135 
3136     errorCode=U_ZERO_ERROR;
3137 
3138     length=u_shapeArabic(letters_source6, UPRV_LENGTHOF(letters_source6),
3139                          dest, UPRV_LENGTHOF(dest),
3140                          U_SHAPE_TEXT_DIRECTION_VISUAL_LTR | U_SHAPE_TASHKEEL_END | U_SHAPE_LETTERS_SHAPE,
3141                          &errorCode);
3142 
3143     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(letters_dest6) || memcmp(dest, letters_dest6, length*U_SIZEOF_UCHAR)!=0) {
3144         log_err("failure in u_shapeArabic(letters_source6)\n");
3145     }
3146 
3147     errorCode=U_ZERO_ERROR;
3148 
3149     length=u_shapeArabic(letters_source7, UPRV_LENGTHOF(letters_source7),
3150                          dest, UPRV_LENGTHOF(dest),
3151                          U_SHAPE_TEXT_DIRECTION_VISUAL_LTR | U_SHAPE_TASHKEEL_RESIZE | U_SHAPE_LETTERS_SHAPE,
3152                          &errorCode);
3153 
3154     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(letters_dest7) || memcmp(dest, letters_dest7, length*U_SIZEOF_UCHAR)!=0) {
3155         log_err("failure in u_shapeArabic(letters_source7)\n");
3156     }
3157 
3158     errorCode=U_ZERO_ERROR;
3159 
3160     length=u_shapeArabic(letters_source8, UPRV_LENGTHOF(letters_source8),
3161                          dest, UPRV_LENGTHOF(dest),
3162                          U_SHAPE_TEXT_DIRECTION_VISUAL_LTR | U_SHAPE_TASHKEEL_REPLACE_BY_TATWEEL | U_SHAPE_LETTERS_SHAPE,
3163                          &errorCode);
3164 
3165     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(letters_dest8) || memcmp(dest, letters_dest8, length*U_SIZEOF_UCHAR)!=0) {
3166         log_err("failure in u_shapeArabic(letters_source8)\n");
3167     }
3168 }
3169 
3170 static void
doArabicShapingTestForBug9024(void)3171 doArabicShapingTestForBug9024(void) {
3172     static const UChar
3173     letters_source1[]={  /* Arabic mathematical Symbols 0x1EE00 - 0x1EE1B */
3174         0xD83B, 0xDE00, 0xD83B, 0xDE01, 0xD83B, 0xDE02, 0xD83B, 0xDE03, 0x20,
3175         0xD83B, 0xDE24, 0xD83B, 0xDE05, 0xD83B, 0xDE06, 0x20,
3176         0xD83B, 0xDE07, 0xD83B, 0xDE08, 0xD83B, 0xDE09, 0x20,
3177         0xD83B, 0xDE0A, 0xD83B, 0xDE0B, 0xD83B, 0xDE0C, 0xD83B, 0xDE0D, 0x20,
3178         0xD83B, 0xDE0E, 0xD83B, 0xDE0F, 0xD83B, 0xDE10, 0xD83B, 0xDE11, 0x20,
3179         0xD83B, 0xDE12, 0xD83B, 0xDE13, 0xD83B, 0xDE14, 0xD83B, 0xDE15, 0x20,
3180         0xD83B, 0xDE16, 0xD83B, 0xDE17, 0xD83B, 0xDE18, 0x20,
3181         0xD83B, 0xDE19, 0xD83B, 0xDE1A, 0xD83B, 0xDE1B
3182     }, letters_source2[]={/* Arabic mathematical Symbols - Looped Symbols, 0x1EE80 - 0x1EE9B */
3183         0xD83B, 0xDE80, 0xD83B, 0xDE81, 0xD83B, 0xDE82, 0xD83B, 0xDE83, 0x20,
3184         0xD83B, 0xDE84, 0xD83B, 0xDE85, 0xD83B, 0xDE86, 0x20,
3185         0xD83B, 0xDE87, 0xD83B, 0xDE88, 0xD83B, 0xDE89, 0x20,
3186         0xD83B, 0xDE8B, 0xD83B, 0xDE8C, 0xD83B, 0xDE8D, 0x20,
3187         0xD83B, 0xDE8E, 0xD83B, 0xDE8F, 0xD83B, 0xDE90, 0xD83B, 0xDE91, 0x20,
3188         0xD83B, 0xDE92, 0xD83B, 0xDE93, 0xD83B, 0xDE94, 0xD83B, 0xDE95, 0x20,
3189         0xD83B, 0xDE96, 0xD83B, 0xDE97, 0xD83B, 0xDE98, 0x20,
3190         0xD83B, 0xDE99, 0xD83B, 0xDE9A, 0xD83B, 0xDE9B
3191     }, letters_source3[]={/* Arabic mathematical Symbols - Double-struck Symbols, 0x1EEA1 - 0x1EEBB */
3192         0xD83B, 0xDEA1, 0xD83B, 0xDEA2, 0xD83B, 0xDEA3, 0x20,
3193         0xD83B, 0xDEA5, 0xD83B, 0xDEA6, 0x20,
3194         0xD83B, 0xDEA7, 0xD83B, 0xDEA8, 0xD83B, 0xDEA9, 0x20,
3195         0xD83B, 0xDEAB, 0xD83B, 0xDEAC, 0xD83B, 0xDEAD, 0x20,
3196         0xD83B, 0xDEAE, 0xD83B, 0xDEAF, 0xD83B, 0xDEB0, 0xD83B, 0xDEB1, 0x20,
3197         0xD83B, 0xDEB2, 0xD83B, 0xDEB3, 0xD83B, 0xDEB4, 0xD83B, 0xDEB5, 0x20,
3198         0xD83B, 0xDEB6, 0xD83B, 0xDEB7, 0xD83B, 0xDEB8, 0x20,
3199         0xD83B, 0xDEB9, 0xD83B, 0xDEBA, 0xD83B, 0xDEBB
3200     }, letters_source4[]={/* Arabic mathematical Symbols - Initial Symbols, 0x1EE21 - 0x1EE3B */
3201         0xD83B, 0xDE21, 0xD83B, 0xDE22, 0x20,
3202         0xD83B, 0xDE27, 0xD83B, 0xDE29, 0x20,
3203         0xD83B, 0xDE2A, 0xD83B, 0xDE2B, 0xD83B, 0xDE2C, 0xD83B, 0xDE2D, 0x20,
3204         0xD83B, 0xDE2E, 0xD83B, 0xDE2F, 0xD83B, 0xDE30, 0xD83B, 0xDE31, 0x20,
3205         0xD83B, 0xDE32, 0xD83B, 0xDE34, 0xD83B, 0xDE35, 0x20,
3206         0xD83B, 0xDE36, 0xD83B, 0xDE37, 0x20,
3207         0xD83B, 0xDE39, 0xD83B, 0xDE3B
3208     }, letters_source5[]={/* Arabic mathematical Symbols - Tailed Symbols */
3209         0xD83B, 0xDE42, 0xD83B, 0xDE47, 0xD83B, 0xDE49, 0xD83B, 0xDE4B, 0x20,
3210         0xD83B, 0xDE4D, 0xD83B, 0xDE4E, 0xD83B, 0xDE4F, 0x20,
3211         0xD83B, 0xDE51, 0xD83B, 0xDE52, 0xD83B, 0xDE54, 0xD83B, 0xDE57, 0x20,
3212         0xD83B, 0xDE59, 0xD83B, 0xDE5B, 0xD83B, 0xDE5D, 0xD83B, 0xDE5F
3213     }, letters_source6[]={/* Arabic mathematical Symbols - Stretched Symbols with 06 range */
3214         0xD83B, 0xDE21, 0x0633, 0xD83B, 0xDE62, 0x0647
3215     }, letters_dest1[]={
3216         0xD83B, 0xDE00, 0xD83B, 0xDE01, 0xD83B, 0xDE02, 0xD83B, 0xDE03, 0x20,
3217         0xD83B, 0xDE24, 0xD83B, 0xDE05, 0xD83B, 0xDE06, 0x20,
3218         0xD83B, 0xDE07, 0xD83B, 0xDE08, 0xD83B, 0xDE09, 0x20,
3219         0xD83B, 0xDE0A, 0xD83B, 0xDE0B, 0xD83B, 0xDE0C, 0xD83B, 0xDE0D, 0x20,
3220         0xD83B, 0xDE0E, 0xD83B, 0xDE0F, 0xD83B, 0xDE10, 0xD83B, 0xDE11, 0x20,
3221         0xD83B, 0xDE12, 0xD83B, 0xDE13, 0xD83B, 0xDE14, 0xD83B, 0xDE15, 0x20,
3222         0xD83B, 0xDE16, 0xD83B, 0xDE17, 0xD83B, 0xDE18, 0x20,
3223         0xD83B, 0xDE19, 0xD83B, 0xDE1A, 0xD83B, 0xDE1B
3224     }, letters_dest2[]={
3225         0xD83B, 0xDE80, 0xD83B, 0xDE81, 0xD83B, 0xDE82, 0xD83B, 0xDE83, 0x20,
3226         0xD83B, 0xDE84, 0xD83B, 0xDE85, 0xD83B, 0xDE86, 0x20,
3227         0xD83B, 0xDE87, 0xD83B, 0xDE88, 0xD83B, 0xDE89, 0x20,
3228         0xD83B, 0xDE8B, 0xD83B, 0xDE8C, 0xD83B, 0xDE8D, 0x20,
3229         0xD83B, 0xDE8E, 0xD83B, 0xDE8F, 0xD83B, 0xDE90, 0xD83B, 0xDE91, 0x20,
3230         0xD83B, 0xDE92, 0xD83B, 0xDE93, 0xD83B, 0xDE94, 0xD83B, 0xDE95, 0x20,
3231         0xD83B, 0xDE96, 0xD83B, 0xDE97, 0xD83B, 0xDE98, 0x20,
3232         0xD83B, 0xDE99, 0xD83B, 0xDE9A, 0xD83B, 0xDE9B
3233     }, letters_dest3[]={
3234         0xD83B, 0xDEA1, 0xD83B, 0xDEA2, 0xD83B, 0xDEA3, 0x20,
3235         0xD83B, 0xDEA5, 0xD83B, 0xDEA6, 0x20,
3236         0xD83B, 0xDEA7, 0xD83B, 0xDEA8, 0xD83B, 0xDEA9, 0x20,
3237         0xD83B, 0xDEAB, 0xD83B, 0xDEAC, 0xD83B, 0xDEAD, 0x20,
3238         0xD83B, 0xDEAE, 0xD83B, 0xDEAF, 0xD83B, 0xDEB0, 0xD83B, 0xDEB1, 0x20,
3239         0xD83B, 0xDEB2, 0xD83B, 0xDEB3, 0xD83B, 0xDEB4, 0xD83B, 0xDEB5, 0x20,
3240         0xD83B, 0xDEB6, 0xD83B, 0xDEB7, 0xD83B, 0xDEB8, 0x20,
3241         0xD83B, 0xDEB9, 0xD83B, 0xDEBA, 0xD83B, 0xDEBB
3242     }, letters_dest4[]={
3243         0xD83B, 0xDE21, 0xD83B, 0xDE22, 0x20,
3244         0xD83B, 0xDE27, 0xD83B, 0xDE29, 0x20,
3245         0xD83B, 0xDE2A, 0xD83B, 0xDE2B, 0xD83B, 0xDE2C, 0xD83B, 0xDE2D, 0x20,
3246         0xD83B, 0xDE2E, 0xD83B, 0xDE2F, 0xD83B, 0xDE30, 0xD83B, 0xDE31, 0x20,
3247         0xD83B, 0xDE32, 0xD83B, 0xDE34, 0xD83B, 0xDE35, 0x20,
3248         0xD83B, 0xDE36, 0xD83B, 0xDE37, 0x20,
3249         0xD83B, 0xDE39, 0xD83B, 0xDE3B
3250     }, letters_dest5[]={
3251         0xD83B, 0xDE42, 0xD83B, 0xDE47, 0xD83B, 0xDE49, 0xD83B, 0xDE4B, 0x20,
3252         0xD83B, 0xDE4D, 0xD83B, 0xDE4E, 0xD83B, 0xDE4F, 0x20,
3253         0xD83B, 0xDE51, 0xD83B, 0xDE52, 0xD83B, 0xDE54, 0xD83B, 0xDE57, 0x20,
3254         0xD83B, 0xDE59, 0xD83B, 0xDE5B, 0xD83B, 0xDE5D, 0xD83B, 0xDE5F
3255     }, letters_dest6[]={
3256         0xD83B, 0xDE21, 0xFEB1, 0xD83B, 0xDE62, 0xFEE9
3257     };
3258 
3259     UChar dest[MAXLEN];
3260     UErrorCode errorCode;
3261     int32_t length;
3262 
3263     errorCode=U_ZERO_ERROR;
3264 
3265     length=u_shapeArabic(letters_source1, UPRV_LENGTHOF(letters_source1),
3266                          dest, UPRV_LENGTHOF(dest),
3267                          U_SHAPE_TEXT_DIRECTION_VISUAL_RTL | U_SHAPE_TASHKEEL_BEGIN | U_SHAPE_LETTERS_SHAPE,
3268                          &errorCode);
3269 
3270     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(letters_dest1) || memcmp(dest, letters_dest1, length*U_SIZEOF_UCHAR)!=0) {
3271         log_err("failure in u_shapeArabic(letters_source1)\n");
3272     }
3273 
3274     errorCode=U_ZERO_ERROR;
3275 
3276     length=u_shapeArabic(letters_source2, UPRV_LENGTHOF(letters_source2),
3277                          dest, UPRV_LENGTHOF(dest),
3278                          U_SHAPE_TEXT_DIRECTION_VISUAL_RTL | U_SHAPE_TASHKEEL_END | U_SHAPE_LETTERS_SHAPE,
3279                          &errorCode);
3280 
3281     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(letters_dest2) || memcmp(dest, letters_dest2, length*U_SIZEOF_UCHAR)!=0) {
3282         log_err("failure in u_shapeArabic(letters_source2)\n");
3283     }
3284 
3285     errorCode=U_ZERO_ERROR;
3286 
3287     length=u_shapeArabic(letters_source3, UPRV_LENGTHOF(letters_source3),
3288                          dest, UPRV_LENGTHOF(dest),
3289                          U_SHAPE_TEXT_DIRECTION_VISUAL_RTL | U_SHAPE_TASHKEEL_RESIZE | U_SHAPE_LETTERS_SHAPE,
3290                          &errorCode);
3291 
3292     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(letters_dest3) || memcmp(dest, letters_dest3, length*U_SIZEOF_UCHAR)!=0) {
3293         log_err("failure in u_shapeArabic(letters_source3)\n");
3294     }
3295 
3296     errorCode=U_ZERO_ERROR;
3297 
3298     length=u_shapeArabic(letters_source4, UPRV_LENGTHOF(letters_source4),
3299                          dest, UPRV_LENGTHOF(dest),
3300                          U_SHAPE_TEXT_DIRECTION_VISUAL_RTL | U_SHAPE_TASHKEEL_REPLACE_BY_TATWEEL | U_SHAPE_LETTERS_SHAPE,
3301                          &errorCode);
3302 
3303     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(letters_dest4) || memcmp(dest, letters_dest4, length*U_SIZEOF_UCHAR)!=0) {
3304         log_err("failure in u_shapeArabic(letters_source4)\n");
3305     }
3306 
3307     errorCode=U_ZERO_ERROR;
3308 
3309     length=u_shapeArabic(letters_source5, UPRV_LENGTHOF(letters_source5),
3310                          dest, UPRV_LENGTHOF(dest),
3311                          U_SHAPE_TEXT_DIRECTION_VISUAL_LTR | U_SHAPE_TASHKEEL_BEGIN | U_SHAPE_LETTERS_SHAPE,
3312                          &errorCode);
3313 
3314     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(letters_dest5) || memcmp(dest, letters_dest5, length*U_SIZEOF_UCHAR)!=0) {
3315         log_err("failure in u_shapeArabic(letters_source5)\n");
3316     }
3317 
3318     errorCode=U_ZERO_ERROR;
3319 
3320     length=u_shapeArabic(letters_source6, UPRV_LENGTHOF(letters_source6),
3321                          dest, UPRV_LENGTHOF(dest),
3322                          U_SHAPE_TEXT_DIRECTION_VISUAL_LTR | U_SHAPE_TASHKEEL_END | U_SHAPE_LETTERS_SHAPE,
3323                          &errorCode);
3324 
3325     if(U_FAILURE(errorCode) || length!=UPRV_LENGTHOF(letters_dest6) || memcmp(dest, letters_dest6, length*U_SIZEOF_UCHAR)!=0) {
3326         log_err("failure in u_shapeArabic(letters_source6)\n");
3327     }
3328 
3329 }
3330 
_testPresentationForms(const UChar * in)3331 static void _testPresentationForms(const UChar* in) {
3332   enum Forms { GENERIC, ISOLATED, FINAL, INITIAL, MEDIAL };
3333   /* This character is used to check whether the in-character is rewritten correctly
3334      and whether the surrounding characters are shaped correctly as well. */
3335   UChar otherChar[] = {0x0628, 0xfe8f, 0xfe90, 0xfe91, 0xfe92};
3336   UChar src[3];
3337   UChar dst[3];
3338   UErrorCode errorCode;
3339   int32_t length;
3340 
3341   /* Testing isolated shaping */
3342   src[0] = in[GENERIC];
3343   errorCode=U_ZERO_ERROR;
3344   length=u_shapeArabic(src, 1,
3345                        dst, 1,
3346                        U_SHAPE_LETTERS_SHAPE,
3347                        &errorCode);
3348   if(U_FAILURE(errorCode) || length!=1 || dst[0] != in[ISOLATED]) {
3349       log_err("failure in u_shapeArabic(_testAllForms: shaping isolated): %x\n", in[GENERIC]);
3350   }
3351   errorCode=U_ZERO_ERROR;
3352   length=u_shapeArabic(dst, 1,
3353                        src, 1,
3354                        U_SHAPE_LETTERS_UNSHAPE,
3355                        &errorCode);
3356   if(U_FAILURE(errorCode) || length!=1 || src[0] != in[GENERIC]) {
3357       log_err("failure in u_shapeArabic(_testAllForms: unshaping isolated): %x\n", in[GENERIC]);
3358   }
3359 
3360   /* Testing final shaping */
3361   src[0] = otherChar[GENERIC];
3362   src[1] = in[GENERIC];
3363   if (in[FINAL] != 0) {
3364     errorCode=U_ZERO_ERROR;
3365     length=u_shapeArabic(src, 2,
3366                          dst, 2,
3367                          U_SHAPE_LETTERS_SHAPE,
3368                          &errorCode);
3369     if(U_FAILURE(errorCode) || length!=2 || dst[0] != otherChar[INITIAL] || dst[1] != in[FINAL]) {
3370       log_err("failure in u_shapeArabic(_testAllForms: shaping final): %x\n", in[GENERIC]);
3371     }
3372     errorCode=U_ZERO_ERROR;
3373     length=u_shapeArabic(dst, 2,
3374                          src, 2,
3375                          U_SHAPE_LETTERS_UNSHAPE,
3376                          &errorCode);
3377     if(U_FAILURE(errorCode) || length!=2 || src[0] != otherChar[GENERIC] || src[1] != in[GENERIC]) {
3378       log_err("failure in u_shapeArabic(_testAllForms: unshaping final): %x\n", in[GENERIC]);
3379     }
3380   } else {
3381     errorCode=U_ZERO_ERROR;
3382     length=u_shapeArabic(src, 2,
3383                          dst, 2,
3384                          U_SHAPE_LETTERS_SHAPE,
3385                          &errorCode);
3386     if(U_FAILURE(errorCode) || length!=2 || dst[0] != otherChar[ISOLATED] || dst[1] != in[ISOLATED]) {
3387       log_err("failure in u_shapeArabic(_testAllForms: shaping final): %x\n", in[GENERIC]);
3388     }
3389     errorCode=U_ZERO_ERROR;
3390     length=u_shapeArabic(dst, 2,
3391                          src, 2,
3392                          U_SHAPE_LETTERS_UNSHAPE,
3393                          &errorCode);
3394     if(U_FAILURE(errorCode) || length!=2 || src[0] != otherChar[GENERIC] || src[1] != in[GENERIC]) {
3395       log_err("failure in u_shapeArabic(_testAllForms: unshaping final): %x\n", in[GENERIC]);
3396     }
3397   }
3398 
3399   /* Testing initial shaping */
3400   src[0] = in[GENERIC];
3401   src[1] = otherChar[GENERIC];
3402   if (in[INITIAL] != 0) {
3403     /* Testing characters that have an initial form */
3404     errorCode=U_ZERO_ERROR;
3405     length=u_shapeArabic(src, 2,
3406                          dst, 2,
3407                          U_SHAPE_LETTERS_SHAPE,
3408                          &errorCode);
3409     if(U_FAILURE(errorCode) || length!=2 || dst[0] != in[INITIAL] || dst[1] != otherChar[FINAL]) {
3410       log_err("failure in u_shapeArabic(_testAllForms: shaping initial): %x\n", in[GENERIC]);
3411     }
3412     errorCode=U_ZERO_ERROR;
3413     length=u_shapeArabic(dst, 2,
3414                          src, 2,
3415                          U_SHAPE_LETTERS_UNSHAPE,
3416                          &errorCode);
3417     if(U_FAILURE(errorCode) || length!=2 || src[0] != in[GENERIC] || src[1] != otherChar[GENERIC]) {
3418       log_err("failure in u_shapeArabic(_testAllForms: unshaping initial): %x\n", in[GENERIC]);
3419     }
3420   } else {
3421     /* Testing characters that do not have an initial form */
3422     errorCode=U_ZERO_ERROR;
3423     length=u_shapeArabic(src, 2,
3424                          dst, 2,
3425                          U_SHAPE_LETTERS_SHAPE,
3426                          &errorCode);
3427     if(U_FAILURE(errorCode) || length!=2 || dst[0] != in[ISOLATED] || dst[1] != otherChar[ISOLATED]) {
3428       log_err("failure in u_shapeArabic(_testTwoForms: shaping initial): %x\n", in[GENERIC]);
3429     }
3430     errorCode=U_ZERO_ERROR;
3431     length=u_shapeArabic(dst, 2,
3432                          src, 2,
3433                          U_SHAPE_LETTERS_UNSHAPE,
3434                          &errorCode);
3435     if(U_FAILURE(errorCode) || length!=2 || src[0] != in[GENERIC] || src[1] != otherChar[GENERIC]) {
3436       log_err("failure in u_shapeArabic(_testTwoForms: unshaping initial): %x\n", in[GENERIC]);
3437     }
3438   }
3439 
3440   /* Testing medial shaping */
3441   src[0] = otherChar[0];
3442   src[1] = in[GENERIC];
3443   src[2] = otherChar[0];
3444   errorCode=U_ZERO_ERROR;
3445   if (in[MEDIAL] != 0) {
3446     /* Testing characters that have an medial form */
3447     length=u_shapeArabic(src, 3,
3448                          dst, 3,
3449                          U_SHAPE_LETTERS_SHAPE,
3450                          &errorCode);
3451     if(U_FAILURE(errorCode) || length!=3 || dst[0] != otherChar[INITIAL] || dst[1] != in[MEDIAL] || dst[2] != otherChar[FINAL]) {
3452       log_err("failure in u_shapeArabic(_testAllForms: shaping medial): %x\n", in[GENERIC]);
3453     }
3454     errorCode=U_ZERO_ERROR;
3455     length=u_shapeArabic(dst, 3,
3456                          src, 3,
3457                          U_SHAPE_LETTERS_UNSHAPE,
3458                          &errorCode);
3459     if(U_FAILURE(errorCode) || length!=3 || src[0] != otherChar[GENERIC] || src[1] != in[GENERIC] || src[2] != otherChar[GENERIC]) {
3460       log_err("failure in u_shapeArabic(_testAllForms: unshaping medial): %x\n", in[GENERIC]);
3461     }
3462   } else {
3463     /* Testing characters that do not have an medial form */
3464     errorCode=U_ZERO_ERROR;
3465     length=u_shapeArabic(src, 3,
3466                          dst, 3,
3467                          U_SHAPE_LETTERS_SHAPE,
3468                          &errorCode);
3469     if(U_FAILURE(errorCode) || length!=3 || dst[0] != otherChar[INITIAL] || dst[1] != in[FINAL] || dst[2] != otherChar[ISOLATED]) {
3470       log_err("failure in u_shapeArabic(_testTwoForms: shaping medial): %x\n", in[GENERIC]);
3471     }
3472     errorCode=U_ZERO_ERROR;
3473     length=u_shapeArabic(dst, 3,
3474                          src, 3,
3475                          U_SHAPE_LETTERS_UNSHAPE,
3476                          &errorCode);
3477     if(U_FAILURE(errorCode) || length!=3 || src[0] != otherChar[GENERIC] || src[1] != in[GENERIC] || src[2] != otherChar[GENERIC]) {
3478       log_err("failure in u_shapeArabic(_testTwoForms: unshaping medial): %x\n", in[GENERIC]);
3479     }
3480   }
3481 }
3482 
3483 static void
doArabicShapingTestForNewCharacters(void)3484 doArabicShapingTestForNewCharacters(void) {
3485   static const UChar letterForms[][5]={
3486     { 0x0679, 0xFB66, 0xFB67, 0xFB68, 0xFB69 },  /* TTEH */
3487     { 0x067A, 0xFB5E, 0xFB5F, 0xFB60, 0xFB61 },  /* TTEHEH */
3488     { 0x067B, 0xFB52, 0xFB53, 0xFB54, 0xFB55 },  /* BEEH */
3489     { 0x0688, 0xFB88, 0xFB89, 0, 0 },            /* DDAL */
3490     { 0x068C, 0xFB84, 0xFB85, 0, 0 },            /* DAHAL */
3491     { 0x068D, 0xFB82, 0xFB83, 0, 0 },            /* DDAHAL */
3492     { 0x068E, 0xFB86, 0xFB87, 0, 0 },            /* DUL */
3493     { 0x0691, 0xFB8C, 0xFB8D, 0, 0 },            /* RREH */
3494     { 0x06BA, 0xFB9E, 0xFB9F, 0, 0 },            /* NOON GHUNNA */
3495     { 0x06BB, 0xFBA0, 0xFBA1, 0xFBA2, 0xFBA3 },  /* RNOON */
3496     { 0x06BE, 0xFBAA, 0xFBAB, 0xFBAC, 0xFBAD },  /* HEH DOACHASHMEE */
3497     { 0x06C0, 0xFBA4, 0xFBA5, 0, 0 },            /* HEH WITH YEH ABOVE */
3498     { 0x06C1, 0xFBA6, 0xFBA7, 0xFBA8, 0xFBA9 },  /* HEH GOAL */
3499     { 0x06C5, 0xFBE0, 0xFBE1, 0, 0 },            /* KIRGIHIZ OE */
3500     { 0x06C6, 0xFBD9, 0xFBDA, 0, 0 },            /* OE */
3501     { 0x06C7, 0xFBD7, 0xFBD8, 0, 0 },            /* U */
3502     { 0x06C8, 0xFBDB, 0xFBDC, 0, 0 },            /* YU */
3503     { 0x06C9, 0xFBE2, 0xFBE3, 0, 0 },            /* KIRGIZ YU */
3504     { 0x06CB, 0xFBDE, 0xFBDF, 0, 0},             /* VE */
3505     { 0x06D0, 0xFBE4, 0xFBE5, 0xFBE6, 0xFBE7 },  /* E */
3506     { 0x06D2, 0xFBAE, 0xFBAF, 0, 0 },            /* YEH BARREE */
3507     { 0x06D3, 0xFBB0, 0xFBB1, 0, 0 },            /* YEH BARREE WITH HAMZA ABOVE */
3508     { 0x0622, 0xFE81, 0xFE82, 0, 0, },           /* ALEF WITH MADDA ABOVE */
3509     { 0x0623, 0xFE83, 0xFE84, 0, 0, },           /* ALEF WITH HAMZA ABOVE */
3510     { 0x0624, 0xFE85, 0xFE86, 0, 0, },           /* WAW WITH HAMZA ABOVE */
3511     { 0x0625, 0xFE87, 0xFE88, 0, 0, },           /* ALEF WITH HAMZA BELOW */
3512     { 0x0626, 0xFE89, 0xFE8A, 0xFE8B, 0xFE8C, }, /* YEH WITH HAMZA ABOVE */
3513     { 0x0627, 0xFE8D, 0xFE8E, 0, 0, },           /* ALEF */
3514     { 0x0628, 0xFE8F, 0xFE90, 0xFE91, 0xFE92, }, /* BEH */
3515     { 0x0629, 0xFE93, 0xFE94, 0, 0, },           /* TEH MARBUTA */
3516     { 0x062A, 0xFE95, 0xFE96, 0xFE97, 0xFE98, }, /* TEH */
3517     { 0x062B, 0xFE99, 0xFE9A, 0xFE9B, 0xFE9C, }, /* THEH */
3518     { 0x062C, 0xFE9D, 0xFE9E, 0xFE9F, 0xFEA0, }, /* JEEM */
3519     { 0x062D, 0xFEA1, 0xFEA2, 0xFEA3, 0xFEA4, }, /* HAH */
3520     { 0x062E, 0xFEA5, 0xFEA6, 0xFEA7, 0xFEA8, }, /* KHAH */
3521     { 0x062F, 0xFEA9, 0xFEAA, 0, 0, },           /* DAL */
3522     { 0x0630, 0xFEAB, 0xFEAC, 0, 0, },           /* THAL */
3523     { 0x0631, 0xFEAD, 0xFEAE, 0, 0, },           /* REH */
3524     { 0x0632, 0xFEAF, 0xFEB0, 0, 0, },           /* ZAIN */
3525     { 0x0633, 0xFEB1, 0xFEB2, 0xFEB3, 0xFEB4, }, /* SEEN */
3526     { 0x0634, 0xFEB5, 0xFEB6, 0xFEB7, 0xFEB8, }, /* SHEEN */
3527     { 0x0635, 0xFEB9, 0xFEBA, 0xFEBB, 0xFEBC, }, /* SAD */
3528     { 0x0636, 0xFEBD, 0xFEBE, 0xFEBF, 0xFEC0, }, /* DAD */
3529     { 0x0637, 0xFEC1, 0xFEC2, 0xFEC3, 0xFEC4, }, /* TAH */
3530     { 0x0638, 0xFEC5, 0xFEC6, 0xFEC7, 0xFEC8, }, /* ZAH */
3531     { 0x0639, 0xFEC9, 0xFECA, 0xFECB, 0xFECC, }, /* AIN */
3532     { 0x063A, 0xFECD, 0xFECE, 0xFECF, 0xFED0, }, /* GHAIN */
3533     { 0x0641, 0xFED1, 0xFED2, 0xFED3, 0xFED4, }, /* FEH */
3534     { 0x0642, 0xFED5, 0xFED6, 0xFED7, 0xFED8, }, /* QAF */
3535     { 0x0643, 0xFED9, 0xFEDA, 0xFEDB, 0xFEDC, }, /* KAF */
3536     { 0x0644, 0xFEDD, 0xFEDE, 0xFEDF, 0xFEE0, }, /* LAM */
3537     { 0x0645, 0xFEE1, 0xFEE2, 0xFEE3, 0xFEE4, }, /* MEEM */
3538     { 0x0646, 0xFEE5, 0xFEE6, 0xFEE7, 0xFEE8, }, /* NOON */
3539     { 0x0647, 0xFEE9, 0xFEEA, 0xFEEB, 0xFEEC, }, /* HEH */
3540     { 0x0648, 0xFEED, 0xFEEE, 0, 0, },           /* WAW */
3541     { 0x0649, 0xFEEF, 0xFEF0, 0, 0, },           /* ALEF MAKSURA */
3542     { 0x064A, 0xFEF1, 0xFEF2, 0xFEF3, 0xFEF4, }, /* YEH */
3543     { 0x064E, 0xFE76, 0, 0, 0xFE77, },           /* FATHA */
3544     { 0x064F, 0xFE78, 0, 0, 0xFE79, },           /* DAMMA */
3545     { 0x0650, 0xFE7A, 0, 0, 0xFE7B, },           /* KASRA */
3546     { 0x0651, 0xFE7C, 0, 0, 0xFE7D, },           /* SHADDA */
3547     { 0x0652, 0xFE7E, 0, 0, 0xFE7F, },           /* SUKUN */
3548     { 0x0679, 0xFB66, 0xFB67, 0xFB68, 0xFB69, }, /* TTEH */
3549     { 0x067E, 0xFB56, 0xFB57, 0xFB58, 0xFB59, }, /* PEH */
3550     { 0x0686, 0xFB7A, 0xFB7B, 0xFB7C, 0xFB7D, }, /* TCHEH */
3551     { 0x0688, 0xFB88, 0xFB89, 0, 0, },           /* DDAL */
3552     { 0x0691, 0xFB8C, 0xFB8D, 0, 0, },           /* RREH */
3553     { 0x0698, 0xFB8A, 0xFB8B, 0, 0, },           /* JEH */
3554     { 0x06A9, 0xFB8E, 0xFB8F, 0xFB90, 0xFB91, }, /* KEHEH */
3555     { 0x06AF, 0xFB92, 0xFB93, 0xFB94, 0xFB95, }, /* GAF */
3556     { 0x06BA, 0xFB9E, 0xFB9F, 0, 0, },           /* NOON GHUNNA */
3557     { 0x06BE, 0xFBAA, 0xFBAB, 0xFBAC, 0xFBAD, }, /* HEH DOACHASHMEE */
3558     { 0x06C0, 0xFBA4, 0xFBA5, 0, 0, },           /* HEH WITH YEH ABOVE */
3559     { 0x06C1, 0xFBA6, 0xFBA7, 0xFBA8, 0xFBA9, }, /* HEH GOAL */
3560     { 0x06CC, 0xFBFC, 0xFBFD, 0xFBFE, 0xFBFF, }, /* FARSI YEH */
3561     { 0x06D2, 0xFBAE, 0xFBAF, 0, 0, },           /* YEH BARREE */
3562     { 0x06D3, 0xFBB0, 0xFBB1, 0, 0, }};          /* YEH BARREE WITH HAMZA ABOVE */
3563   int32_t i;
3564   for (i = 0; i < UPRV_LENGTHOF(letterForms); ++i) {
3565     _testPresentationForms(letterForms[i]);
3566   }
3567 }
3568 
3569 /* helpers ------------------------------------------------------------------ */
3570 
initCharFromDirProps(void)3571 static void initCharFromDirProps(void) {
3572     static const UVersionInfo ucd401={ 4, 0, 1, 0 };
3573     static UVersionInfo ucdVersion={ 0, 0, 0, 0 };
3574 
3575     /* lazy initialization */
3576     if(ucdVersion[0]>0) {
3577         return;
3578     }
3579 
3580     u_getUnicodeVersion(ucdVersion);
3581     if(memcmp(ucdVersion, ucd401, sizeof(UVersionInfo))>=0) {
3582         /* Unicode 4.0.1 changes bidi classes for +-/ */
3583         charFromDirProp[U_EUROPEAN_NUMBER_SEPARATOR]=0x2b; /* change ES character from / to + */
3584     }
3585 }
3586 
3587 /* return a string with characters according to the desired directional properties */
3588 static UChar *
getStringFromDirProps(const uint8_t * dirProps,int32_t length,UChar * buffer)3589 getStringFromDirProps(const uint8_t *dirProps, int32_t length, UChar *buffer) {
3590     int32_t i;
3591 
3592     initCharFromDirProps();
3593 
3594     /* this part would have to be modified for UTF-x */
3595     for(i=0; i<length; ++i) {
3596         buffer[i]=charFromDirProp[dirProps[i]];
3597     }
3598     buffer[length]=0;
3599     return buffer;
3600 }
3601 
printUnicode(const UChar * s,int32_t length,const UBiDiLevel * levels)3602 static void printUnicode(const UChar *s, int32_t length, const UBiDiLevel *levels) {
3603     int32_t i;
3604 
3605     log_verbose("{ ");
3606     for(i=0; i<length; ++i) {
3607         if(levels!=NULL) {
3608             log_verbose("%4x.%u  ", s[i], levels[i]);
3609         } else {
3610             log_verbose("%4x    ", s[i]);
3611         }
3612     }
3613     log_verbose(" }");
3614 }
3615 
3616 /* new BIDI API */
3617 
3618 /* Reordering Mode BiDi --------------------------------------------------------- */
3619 
3620 static const UBiDiLevel paraLevels[] = { UBIDI_LTR, UBIDI_RTL };
3621 
3622 static UBool
assertSuccessful(const char * message,UErrorCode * rc)3623 assertSuccessful(const char* message, UErrorCode* rc) {
3624     if (rc != NULL && U_FAILURE(*rc)) {
3625         log_err("%s() failed with error %s.\n", message, myErrorName(*rc));
3626         return FALSE;
3627     }
3628     return TRUE;
3629 }
3630 
3631 static UBool
assertStringsEqual(const char * expected,const char * actual,const char * src,const char * mode,const char * option,UBiDi * pBiDi)3632 assertStringsEqual(const char* expected, const char* actual, const char* src,
3633                    const char* mode, const char* option, UBiDi* pBiDi) {
3634     if (uprv_strcmp(expected, actual)) {
3635         char formatChars[MAXLEN];
3636         log_err("\nActual and expected output mismatch.\n"
3637             "%20s %s\n%20s %s\n%20s %s\n%20s %s\n%20s %d %s\n%20s %u\n%20s %d %s\n",
3638             "Input:", src,
3639             "Actual output:", actual,
3640             "Expected output:", expected,
3641             "Levels:", formatLevels(pBiDi, formatChars),
3642             "Reordering mode:", ubidi_getReorderingMode(pBiDi), mode,
3643             "Paragraph level:", ubidi_getParaLevel(pBiDi),
3644             "Reordering option:", ubidi_getReorderingOptions(pBiDi), option);
3645         return FALSE;
3646     }
3647     return TRUE;
3648 }
3649 
3650 static UBiDi*
getBiDiObject(void)3651 getBiDiObject(void) {
3652     UBiDi* pBiDi = ubidi_open();
3653     if (pBiDi == NULL) {
3654         log_err("Unable to allocate a UBiDi object. Tests are skipped.\n");
3655     }
3656     return pBiDi;
3657 }
3658 
3659 #define MAKE_ITEMS(val) val, #val
3660 
3661 static const struct {
3662     UBiDiReorderingMode value;
3663     const char* description;
3664 }
3665 modes[] = {
3666     { MAKE_ITEMS(UBIDI_REORDER_GROUP_NUMBERS_WITH_R) },
3667     { MAKE_ITEMS(UBIDI_REORDER_INVERSE_LIKE_DIRECT) },
3668     { MAKE_ITEMS(UBIDI_REORDER_NUMBERS_SPECIAL) },
3669     { MAKE_ITEMS(UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL) },
3670     { MAKE_ITEMS(UBIDI_REORDER_INVERSE_NUMBERS_AS_L) }
3671 };
3672 static const struct {
3673     uint32_t value;
3674     const char* description;
3675 }
3676 options[] = {
3677     { MAKE_ITEMS(UBIDI_OPTION_INSERT_MARKS) },
3678     { MAKE_ITEMS(0) }
3679 };
3680 
3681 #define TC_COUNT                UPRV_LENGTHOF(textIn)
3682 #define MODES_COUNT             UPRV_LENGTHOF(modes)
3683 #define OPTIONS_COUNT           UPRV_LENGTHOF(options)
3684 #define LEVELS_COUNT            UPRV_LENGTHOF(paraLevels)
3685 
3686 static const char* const textIn[] = {
3687 /* (0) 123 */
3688     "123",
3689 /* (1) .123->4.5 */
3690     ".123->4.5",
3691 /* (2) 678 */
3692     "678",
3693 /* (3) .678->8.9 */
3694     ".678->8.9",
3695 /* (4) JIH1.2,3MLK */
3696     "JIH1.2,3MLK",
3697 /* (5) FE.>12-> */
3698     "FE.>12->",
3699 /* (6) JIH.>12->a */
3700     "JIH.>12->a",
3701 /* (7) CBA.>67->89=a */
3702     "CBA.>67->89=a",
3703 /* (8) CBA.123->xyz */
3704     "CBA.123->xyz",
3705 /* (9) .>12->xyz */
3706     ".>12->xyz",
3707 /* (10) a.>67->xyz */
3708     "a.>67->xyz",
3709 /* (11) 123JIH */
3710     "123JIH",
3711 /* (12) 123 JIH */
3712     "123 JIH"
3713 };
3714 
3715 static const char* const textOut[] = {
3716 /* TC 0: 123 */
3717     "123",                                                              /* (0) */
3718 /* TC 1: .123->4.5 */
3719     ".123->4.5",                                                        /* (1) */
3720     "4.5<-123.",                                                        /* (2) */
3721 /* TC 2: 678 */
3722     "678",                                                              /* (3) */
3723 /* TC 3: .678->8.9 */
3724     ".8.9<-678",                                                        /* (4) */
3725     "8.9<-678.",                                                        /* (5) */
3726     ".678->8.9",                                                        /* (6) */
3727 /* TC 4: MLK1.2,3JIH */
3728     "KLM1.2,3HIJ",                                                      /* (7) */
3729 /* TC 5: FE.>12-> */
3730     "12<.EF->",                                                         /* (8) */
3731     "<-12<.EF",                                                         /* (9) */
3732     "EF.>@12->",                                                        /* (10) */
3733 /* TC 6: JIH.>12->a */
3734     "12<.HIJ->a",                                                       /* (11) */
3735     "a<-12<.HIJ",                                                       /* (12) */
3736     "HIJ.>@12->a",                                                      /* (13) */
3737     "a&<-12<.HIJ",                                                      /* (14) */
3738 /* TC 7: CBA.>67->89=a */
3739     "ABC.>@67->89=a",                                                   /* (15) */
3740     "a=89<-67<.ABC",                                                    /* (16) */
3741     "a&=89<-67<.ABC",                                                   /* (17) */
3742     "89<-67<.ABC=a",                                                    /* (18) */
3743 /* TC 8: CBA.123->xyz */
3744     "123.ABC->xyz",                                                     /* (19) */
3745     "xyz<-123.ABC",                                                     /* (20) */
3746     "ABC.@123->xyz",                                                    /* (21) */
3747     "xyz&<-123.ABC",                                                    /* (22) */
3748 /* TC 9: .>12->xyz */
3749     ".>12->xyz",                                                        /* (23) */
3750     "xyz<-12<.",                                                        /* (24) */
3751     "xyz&<-12<.",                                                       /* (25) */
3752 /* TC 10: a.>67->xyz */
3753     "a.>67->xyz",                                                       /* (26) */
3754     "a.>@67@->xyz",                                                     /* (27) */
3755     "xyz<-67<.a",                                                       /* (28) */
3756 /* TC 11: 123JIH */
3757     "123HIJ",                                                           /* (29) */
3758     "HIJ123",                                                           /* (30) */
3759 /* TC 12: 123 JIH */
3760     "123 HIJ",                                                          /* (31) */
3761     "HIJ 123",                                                          /* (32) */
3762 };
3763 
3764 #define NO                  UBIDI_MAP_NOWHERE
3765 #define MAX_MAP_LENGTH      20
3766 
3767 static const int32_t forwardMap[][MAX_MAP_LENGTH] = {
3768 /* TC 0: 123 */
3769     { 0, 1, 2 },                                                        /* (0) */
3770 /* TC 1: .123->4.5 */
3771     { 0, 1, 2, 3, 4, 5, 6, 7, 8 },                                      /* (1) */
3772     { 8, 5, 6, 7, 4, 3, 0, 1, 2 },                                      /* (2) */
3773 /* TC 2: 678 */
3774     { 0, 1, 2 },                                                        /* (3) */
3775 /* TC 3: .678->8.9 */
3776     { 0, 6, 7, 8, 5, 4, 1, 2, 3 },                                      /* (4) */
3777     { 8, 5, 6, 7, 4, 3, 0, 1, 2 },                                      /* (5) */
3778     { 0, 1, 2, 3, 4, 5, 6, 7, 8 },                                      /* (6) */
3779 /* TC 4: MLK1.2,3JIH */
3780     { 10, 9, 8, 3, 4, 5, 6, 7, 2, 1, 0 },                               /* (7) */
3781 /* TC 5: FE.>12-> */
3782     { 5, 4, 3, 2, 0, 1, 6, 7 },                                         /* (8) */
3783     { 7, 6, 5, 4, 2, 3, 1, 0 },                                         /* (9) */
3784     { 1, 0, 2, 3, 5, 6, 7, 8 },                                         /* (10) */
3785 /* TC 6: JIH.>12->a */
3786     { 6, 5, 4, 3, 2, 0, 1, 7, 8, 9 },                                   /* (11) */
3787     { 9, 8, 7, 6, 5, 3, 4, 2, 1, 0 },                                   /* (12) */
3788     { 2, 1, 0, 3, 4, 6, 7, 8, 9, 10 },                                  /* (13) */
3789     { 10, 9, 8, 7, 6, 4, 5, 3, 2, 0 },                                  /* (14) */
3790 /* TC 7: CBA.>67->89=a */
3791     { 2, 1, 0, 3, 4, 6, 7, 8, 9, 10, 11, 12, 13 },                      /* (15) */
3792     { 12, 11, 10, 9, 8, 6, 7, 5, 4, 2, 3, 1, 0 },                       /* (16) */
3793     { 13, 12, 11, 10, 9, 7, 8, 6, 5, 3, 4, 2, 0 },                      /* (17) */
3794     { 10, 9, 8, 7, 6, 4, 5, 3, 2, 0, 1, 11, 12 },                       /* (18) */
3795 /* TC 8: CBA.123->xyz */
3796     { 6, 5, 4, 3, 0, 1, 2, 7, 8, 9, 10, 11 },                           /* (19) */
3797     { 11, 10, 9, 8, 5, 6, 7, 4, 3, 0, 1, 2 },                           /* (20) */
3798     { 2, 1, 0, 3, 5, 6, 7, 8, 9, 10, 11, 12 },                          /* (21) */
3799     { 12, 11, 10, 9, 6, 7, 8, 5, 4, 0, 1, 2 },                          /* (22) */
3800 /* TC 9: .>12->xyz */
3801     { 0, 1, 2, 3, 4, 5, 6, 7, 8 },                                      /* (23) */
3802     { 8, 7, 5, 6, 4, 3, 0, 1, 2 },                                      /* (24) */
3803     { 9, 8, 6, 7, 5, 4, 0, 1, 2 },                                      /* (25) */
3804 /* TC 10: a.>67->xyz */
3805     { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },                                   /* (26) */
3806     { 0, 1, 2, 4, 5, 7, 8, 9, 10, 11 },                                 /* (27) */
3807     { 9, 8, 7, 5, 6, 4, 3, 0, 1, 2 },                                   /* (28) */
3808 /* TC 11: 123JIH */
3809     { 0, 1, 2, 5, 4, 3 },                                               /* (29) */
3810     { 3, 4, 5, 2, 1, 0 },                                               /* (30) */
3811 /* TC 12: 123 JIH */
3812     { 0, 1, 2, 3, 6, 5, 4 },                                            /* (31) */
3813     { 4, 5, 6, 3, 2, 1, 0 },                                            /* (32) */
3814 };
3815 
3816 static const int32_t inverseMap[][MAX_MAP_LENGTH] = {
3817 /* TC 0: 123 */
3818     { 0, 1, 2 },                                                        /* (0) */
3819 /* TC 1: .123->4.5 */
3820     { 0, 1, 2, 3, 4, 5, 6, 7, 8 },                                      /* (1) */
3821     { 6, 7, 8, 5, 4, 1, 2, 3, 0 },                                      /* (2) */
3822 /* TC 2: 678 */
3823     { 0, 1, 2 },                                                        /* (3) */
3824 /* TC 3: .678->8.9 */
3825     { 0, 6, 7, 8, 5, 4, 1, 2, 3 },                                      /* (4) */
3826     { 6, 7, 8, 5, 4, 1, 2, 3, 0 },                                      /* (5) */
3827     { 0, 1, 2, 3, 4, 5, 6, 7, 8 },                                      /* (6) */
3828 /* TC 4: MLK1.2,3JIH */
3829     { 10, 9, 8, 3, 4, 5, 6, 7, 2, 1, 0 },                               /* (7) */
3830 /* TC 5: FE.>12-> */
3831     { 4, 5, 3, 2, 1, 0, 6, 7 },                                         /* (8) */
3832     { 7, 6, 4, 5, 3, 2, 1, 0 },                                         /* (9) */
3833     { 1, 0, 2, 3, NO, 4, 5, 6, 7 },                                     /* (10) */
3834 /* TC 6: JIH.>12->a */
3835     { 5, 6, 4, 3, 2, 1, 0, 7, 8, 9 },                                   /* (11) */
3836     { 9, 8, 7, 5, 6, 4, 3, 2, 1, 0 },                                   /* (12) */
3837     { 2, 1, 0, 3, 4, NO, 5, 6, 7, 8, 9 },                               /* (13) */
3838     { 9, NO, 8, 7, 5, 6, 4, 3, 2, 1, 0 },                               /* (14) */
3839 /* TC 7: CBA.>67->89=a */
3840     { 2, 1, 0, 3, 4, NO, 5, 6, 7, 8, 9, 10, 11, 12 },                   /* (15) */
3841     { 12, 11, 9, 10, 8, 7, 5, 6, 4, 3, 2, 1, 0 },                       /* (16) */
3842     { 12, NO, 11, 9, 10, 8, 7, 5, 6, 4, 3, 2, 1, 0 },                   /* (17) */
3843     { 9, 10, 8, 7, 5, 6, 4, 3, 2, 1, 0, 11, 12 },                       /* (18) */
3844 /* TC 8: CBA.123->xyz */
3845     { 4, 5, 6, 3, 2, 1, 0, 7, 8, 9, 10, 11 },                           /* (19) */
3846     { 9, 10, 11, 8, 7, 4, 5, 6, 3, 2, 1, 0 },                           /* (20) */
3847     { 2, 1, 0, 3, NO, 4, 5, 6, 7, 8, 9, 10, 11 },                       /* (21) */
3848     { 9, 10, 11, NO, 8, 7, 4, 5, 6, 3, 2, 1, 0 },                       /* (22) */
3849 /* TC 9: .>12->xyz */
3850     { 0, 1, 2, 3, 4, 5, 6, 7, 8 },                                      /* (23) */
3851     { 6, 7, 8, 5, 4, 2, 3, 1, 0 },                                      /* (24) */
3852     { 6, 7, 8, NO, 5, 4, 2, 3, 1, 0 },                                  /* (25) */
3853 /* TC 10: a.>67->xyz */
3854     { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },                                   /* (26) */
3855     { 0, 1, 2, NO, 3, 4, NO, 5, 6, 7, 8, 9 },                           /* (27) */
3856     { 7, 8, 9, 6, 5, 3, 4, 2, 1, 0 },                                   /* (28) */
3857 /* TC 11: 123JIH */
3858     { 0, 1, 2, 5, 4, 3 },                                               /* (29) */
3859     { 5, 4, 3, 0, 1, 2 },                                               /* (30) */
3860 /* TC 12: 123 JIH */
3861     { 0, 1, 2, 3, 6, 5, 4 },                                            /* (31) */
3862     { 6, 5, 4, 3, 0, 1, 2 },                                            /* (32) */
3863 };
3864 
3865 static const char outIndices[TC_COUNT][MODES_COUNT - 1][OPTIONS_COUNT]
3866             [LEVELS_COUNT] = {
3867     { /* TC 0: 123 */
3868         {{ 0,  0}, { 0,  0}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
3869         {{ 0,  0}, { 0,  0}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
3870         {{ 0,  0}, { 0,  0}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
3871         {{ 0,  0}, { 0,  0}}  /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
3872     },
3873     { /* TC 1: .123->4.5 */
3874         {{ 1,  2}, { 1,  2}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
3875         {{ 1,  2}, { 1,  2}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
3876         {{ 1,  2}, { 1,  2}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
3877         {{ 1,  2}, { 1,  2}}  /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
3878     },
3879     { /* TC 2: 678 */
3880         {{ 3,  3}, { 3,  3}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
3881         {{ 3,  3}, { 3,  3}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
3882         {{ 3,  3}, { 3,  3}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
3883         {{ 3,  3}, { 3,  3}}  /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
3884     },
3885     { /* TC 3: .678->8.9 */
3886         {{ 6,  5}, { 6,  5}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
3887         {{ 4,  5}, { 4,  5}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
3888         {{ 6,  5}, { 6,  5}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
3889         {{ 6,  5}, { 6,  5}}  /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
3890     },
3891     { /* TC 4: MLK1.2,3JIH */
3892         {{ 7,  7}, { 7,  7}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
3893         {{ 7,  7}, { 7,  7}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
3894         {{ 7,  7}, { 7,  7}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
3895         {{ 7,  7}, { 7,  7}}  /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
3896     },
3897     { /* TC 5: FE.>12-> */
3898         {{ 8,  9}, { 8,  9}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
3899         {{10,  9}, { 8,  9}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
3900         {{ 8,  9}, { 8,  9}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
3901         {{10,  9}, { 8,  9}}  /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
3902     },
3903     { /* TC 6: JIH.>12->a */
3904         {{11, 12}, {11, 12}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
3905         {{13, 14}, {11, 12}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
3906         {{11, 12}, {11, 12}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
3907         {{13, 14}, {11, 12}}  /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
3908     },
3909     { /* TC 7: CBA.>67->89=a */
3910         {{18, 16}, {18, 16}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
3911         {{18, 17}, {18, 16}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
3912         {{18, 16}, {18, 16}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
3913         {{15, 17}, {18, 16}}  /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
3914     },
3915     { /* TC 8: CBA.>124->xyz */
3916         {{19, 20}, {19, 20}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
3917         {{21, 22}, {19, 20}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
3918         {{19, 20}, {19, 20}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
3919         {{21, 22}, {19, 20}}  /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
3920     },
3921     { /* TC 9: .>12->xyz */
3922         {{23, 24}, {23, 24}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
3923         {{23, 25}, {23, 24}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
3924         {{23, 24}, {23, 24}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
3925         {{23, 25}, {23, 24}}  /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
3926     },
3927     { /* TC 10: a.>67->xyz */
3928         {{26, 26}, {26, 26}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
3929         {{26, 27}, {26, 28}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
3930         {{26, 28}, {26, 28}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
3931         {{26, 27}, {26, 28}}  /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
3932     },
3933     { /* TC 11: 124JIH */
3934         {{30, 30}, {30, 30}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
3935         {{29, 30}, {29, 30}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
3936         {{30, 30}, {30, 30}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
3937         {{30, 30}, {30, 30}}  /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
3938     },
3939     { /* TC 12: 124 JIH */
3940         {{32, 32}, {32, 32}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
3941         {{31, 32}, {31, 32}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
3942         {{31, 32}, {31, 32}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
3943         {{31, 32}, {31, 32}}  /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
3944     }
3945 };
3946 
3947 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)3948 assertRoundTrip(UBiDi *pBiDi, int32_t tc, int32_t outIndex, const char *srcChars,
3949                 const char *destChars, const UChar *dest, int32_t destLen,
3950                 int mode, int option, UBiDiLevel level) {
3951 
3952     static const char roundtrip[TC_COUNT][MODES_COUNT][OPTIONS_COUNT]
3953                 [LEVELS_COUNT] = {
3954         { /* TC 0: 123 */
3955             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
3956             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
3957             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
3958             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
3959             {{ 1,  1}, { 1,  1}}  /* UBIDI_REORDER_INVERSE_NUMBERS_AS_L */
3960         },
3961         { /* TC 1: .123->4.5 */
3962             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
3963             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
3964             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
3965             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
3966             {{ 1,  1}, { 1,  1}}  /* UBIDI_REORDER_INVERSE_NUMBERS_AS_L */
3967         },
3968         { /* TC 2: 678 */
3969             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
3970             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
3971             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
3972             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
3973             {{ 1,  1}, { 1,  1}}  /* UBIDI_REORDER_INVERSE_NUMBERS_AS_L */
3974         },
3975         { /* TC 3: .678->8.9 */
3976             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
3977             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
3978             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
3979             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
3980             {{ 0,  0}, { 1,  1}}  /* UBIDI_REORDER_INVERSE_NUMBERS_AS_L */
3981         },
3982         { /* TC 4: MLK1.2,3JIH */
3983             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
3984             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
3985             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
3986             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
3987             {{ 1,  1}, { 1,  1}}  /* UBIDI_REORDER_INVERSE_NUMBERS_AS_L */
3988         },
3989         { /* TC 5: FE.>12-> */
3990             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
3991             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
3992             {{ 0,  1}, { 1,  1}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
3993             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
3994             {{ 1,  1}, { 1,  1}}  /* UBIDI_REORDER_INVERSE_NUMBERS_AS_L */
3995         },
3996         { /* TC 6: JIH.>12->a */
3997             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
3998             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
3999             {{ 0,  0}, { 1,  1}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
4000             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
4001             {{ 1,  1}, { 1,  1}}  /* UBIDI_REORDER_INVERSE_NUMBERS_AS_L */
4002         },
4003         { /* TC 7: CBA.>67->89=a */
4004             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
4005             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
4006             {{ 0,  1}, { 1,  1}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
4007             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
4008             {{ 0,  0}, { 1,  1}}  /* UBIDI_REORDER_INVERSE_NUMBERS_AS_L */
4009         },
4010         { /* TC 8: CBA.>123->xyz */
4011             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
4012             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
4013             {{ 0,  0}, { 1,  1}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
4014             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
4015             {{ 1,  1}, { 1,  1}}  /* UBIDI_REORDER_INVERSE_NUMBERS_AS_L */
4016         },
4017         { /* TC 9: .>12->xyz */
4018             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
4019             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
4020             {{ 1,  0}, { 1,  1}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
4021             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
4022             {{ 1,  1}, { 1,  1}}  /* UBIDI_REORDER_INVERSE_NUMBERS_AS_L */
4023         },
4024         { /* TC 10: a.>67->xyz */
4025             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
4026             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
4027             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
4028             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
4029             {{ 1,  0}, { 1,  1}}  /* UBIDI_REORDER_INVERSE_NUMBERS_AS_L */
4030         },
4031         { /* TC 11: 123JIH */
4032             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
4033             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
4034             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
4035             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
4036             {{ 1,  1}, { 1,  1}}  /* UBIDI_REORDER_INVERSE_NUMBERS_AS_L */
4037         },
4038         { /* TC 12: 123 JIH */
4039             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
4040             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
4041             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
4042             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
4043             {{ 1,  1}, { 1,  1}}  /* UBIDI_REORDER_INVERSE_NUMBERS_AS_L */
4044         }
4045     };
4046 
4047     #define SET_ROUND_TRIP_MODE(mode) \
4048         ubidi_setReorderingMode(pBiDi, mode); \
4049         desc = #mode; \
4050         break;
4051 
4052     UErrorCode rc = U_ZERO_ERROR;
4053     UChar dest2[MAXLEN];
4054     int32_t destLen2;
4055     const char* desc;
4056     char destChars2[MAXLEN];
4057     char destChars3[MAXLEN];
4058 
4059     switch (modes[mode].value) {
4060         case UBIDI_REORDER_NUMBERS_SPECIAL:
4061             SET_ROUND_TRIP_MODE(UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL)
4062         case UBIDI_REORDER_GROUP_NUMBERS_WITH_R:
4063             SET_ROUND_TRIP_MODE(UBIDI_REORDER_GROUP_NUMBERS_WITH_R)
4064         case UBIDI_REORDER_RUNS_ONLY:
4065             SET_ROUND_TRIP_MODE(UBIDI_REORDER_RUNS_ONLY)
4066         case UBIDI_REORDER_INVERSE_NUMBERS_AS_L:
4067             SET_ROUND_TRIP_MODE(UBIDI_REORDER_DEFAULT)
4068         case UBIDI_REORDER_INVERSE_LIKE_DIRECT:
4069             SET_ROUND_TRIP_MODE(UBIDI_REORDER_DEFAULT)
4070         case UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL:
4071             SET_ROUND_TRIP_MODE(UBIDI_REORDER_NUMBERS_SPECIAL)
4072         default:
4073             SET_ROUND_TRIP_MODE(UBIDI_REORDER_INVERSE_LIKE_DIRECT)
4074     }
4075     ubidi_setReorderingOptions(pBiDi, UBIDI_OPTION_REMOVE_CONTROLS);
4076 
4077     ubidi_setPara(pBiDi, dest, destLen, level, NULL, &rc);
4078     assertSuccessful("ubidi_setPara", &rc);
4079     *dest2 = 0;
4080     destLen2 = ubidi_writeReordered(pBiDi, dest2, MAXLEN, UBIDI_DO_MIRRORING,
4081                                     &rc);
4082     assertSuccessful("ubidi_writeReordered", &rc);
4083 
4084     u16ToPseudo(destLen, dest, destChars3);
4085     u16ToPseudo(destLen2, dest2, destChars2);
4086     checkWhatYouCan(pBiDi, destChars3, destChars2);
4087     if (strcmp(srcChars, destChars2)) {
4088         if (roundtrip[tc][mode][option][level]) {
4089             log_err("\nRound trip failed for case=%d mode=%d option=%d.\n"
4090                     "%20s %s\n%20s %s\n%20s %s\n%20s %s\n%20s %s"
4091                     "\n%20s %u\n", tc, mode, option,
4092                     "Original text:", srcChars,
4093                     "Round-tripped text:", destChars2,
4094                     "Intermediate  text:", destChars3,
4095                     "Reordering mode:", modes[mode].description,
4096                     "Reordering option:", options[option].description,
4097                     "Paragraph level:", level);
4098         }
4099         else {
4100             log_verbose("\nExpected round trip failure for case=%d mode=%d option=%d.\n"
4101                     "%20s %s\n%20s %s\n%20s %s\n%20s %s\n%20s %s"
4102                     "\n%20s %u\n", tc, mode, option,
4103                     "Original text:", srcChars,
4104                     "Round-tripped text:", destChars2,
4105                     "Intermediate  text:", destChars3,
4106                     "Reordering mode:", modes[mode].description,
4107                     "Reordering option:", options[option].description,
4108                     "Paragraph level:", level);
4109         }
4110         return FALSE;
4111     }
4112     if (!checkResultLength(pBiDi, destChars, destChars2, destLen2,
4113                            desc, "UBIDI_OPTION_REMOVE_CONTROLS", level)) {
4114         return FALSE;
4115     }
4116     if (outIndex > -1 && !checkMaps(pBiDi, outIndex, srcChars, destChars,
4117                                     desc, "UBIDI_OPTION_REMOVE_CONTROLS",
4118                                     level, FALSE)) {
4119         return FALSE;
4120     }
4121     return TRUE;
4122 }
4123 
4124 static UBool
checkResultLength(UBiDi * pBiDi,const char * srcChars,const char * destChars,int32_t destLen,const char * mode,const char * option,UBiDiLevel level)4125 checkResultLength(UBiDi *pBiDi, const char *srcChars, const char *destChars,
4126                   int32_t destLen, const char* mode,
4127                   const char* option, UBiDiLevel level) {
4128     int32_t actualLen;
4129     if (strcmp(mode, "UBIDI_REORDER_INVERSE_NUMBERS_AS_L") == 0)
4130         actualLen = (int32_t)strlen(destChars);
4131     else
4132         actualLen = ubidi_getResultLength(pBiDi);
4133     if (actualLen != destLen) {
4134         log_err("\nubidi_getResultLength failed.\n%20s %7d\n%20s %7d\n"
4135                 "%20s %s\n%20s %s\n%20s %s\n%20s %s\n%20s %u\n",
4136                 "Expected:", destLen, "Actual:", actualLen,
4137                 "Input:", srcChars, "Output:", destChars,
4138                 "Reordering mode:", mode, "Reordering option:", option,
4139                 "Paragraph level:", level);
4140         return FALSE;
4141     }
4142     return TRUE;
4143 }
4144 
4145 static void
testReorderRunsOnly(void)4146 testReorderRunsOnly(void) {
4147     static const struct {
4148         const char* textIn;
4149         const char* textOut[2][2];
4150         const char noroundtrip[2];
4151     } testCases[] = {
4152         {"ab 234 896 de", {{"de 896 ab 234", "de 896 ab 234"},                   /*0*/
4153                            {"ab 234 @896@ de", "de 896 ab 234"}}, {0, 0}},
4154         {"abcGHI", {{"GHIabc", "GHIabc"}, {"GHIabc", "GHIabc"}}, {0, 0}},        /*1*/
4155         {"a.>67->", {{"<-67<.a", "<-67<.a"}, {"<-67<.a", "<-67<.a"}}, {0, 0}},   /*2*/
4156         {"-=%$123/ *", {{"* /%$123=-", "* /%$123=-"},                            /*3*/
4157                         {"* /%$123=-", "* /%$123=-"}}, {0, 0}},
4158         {"abc->12..>JKL", {{"JKL<..12<-abc", "JKL<..abc->12"},                   /*4*/
4159                            {"JKL<..12<-abc", "JKL<..abc->12"}}, {0, 0}},
4160         {"JKL->12..>abc", {{"abc<..JKL->12", "abc<..12<-JKL"},                   /*5*/
4161                            {"abc<..JKL->12", "abc<..12<-JKL"}}, {0, 0}},
4162         {"123->abc", {{"abc<-123", "abc<-123"},                                  /*6*/
4163                       {"abc&<-123", "abc<-123"}}, {1, 0}},
4164         {"123->JKL", {{"JKL<-123", "123->JKL"},                                  /*7*/
4165                       {"JKL<-123", "JKL<-@123"}}, {0, 1}},
4166         {"*>12.>34->JKL", {{"JKL<-34<.12<*", "12.>34->JKL<*"},                   /*8*/
4167                            {"JKL<-34<.12<*", "JKL<-@34<.12<*"}}, {0, 1}},
4168         {"*>67.>89->JKL", {{"67.>89->JKL<*", "67.>89->JKL<*"},                   /*9*/
4169                            {"67.>89->JKL<*", "67.>89->JKL<*"}}, {0, 0}},
4170         {"* /abc-=$%123", {{"$%123=-abc/ *", "abc-=$%123/ *"},                   /*10*/
4171                            {"$%123=-abc/ *", "abc-=$%123/ *"}}, {0, 0}},
4172         {"* /$%def-=123", {{"123=-def%$/ *", "def-=123%$/ *"},                   /*11*/
4173                            {"123=-def%$/ *", "def-=123%$/ *"}}, {0, 0}},
4174         {"-=GHI* /123%$", {{"GHI* /123%$=-", "123%$/ *GHI=-"},                   /*12*/
4175                            {"GHI* /123%$=-", "123%$/ *GHI=-"}}, {0, 0}},
4176         {"-=%$JKL* /123", {{"JKL* /%$123=-", "123/ *JKL$%=-"},                   /*13*/
4177                            {"JKL* /%$123=-", "123/ *JKL$%=-"}}, {0, 0}},
4178         {"ab =#CD *?450", {{"CD *?450#= ab", "450?* CD#= ab"},                   /*14*/
4179                            {"CD *?450#= ab", "450?* CD#= ab"}}, {0, 0}},
4180         {"ab 234 896 de", {{"de 896 ab 234", "de 896 ab 234"},                   /*15*/
4181                            {"ab 234 @896@ de", "de 896 ab 234"}}, {0, 0}},
4182         {"abc-=%$LMN* /123", {{"LMN* /%$123=-abc", "123/ *LMN$%=-abc"},          /*16*/
4183                               {"LMN* /%$123=-abc", "123/ *LMN$%=-abc"}}, {0, 0}},
4184         {"123->JKL&MN&P", {{"JKLMNP<-123", "123->JKLMNP"},                       /*17*/
4185                            {"JKLMNP<-123", "JKLMNP<-@123"}}, {0, 1}},
4186         {"123", {{"123", "123"},                /* just one run */               /*18*/
4187                  {"123", "123"}}, {0, 0}}
4188     };
4189     UBiDi *pBiDi = getBiDiObject();
4190     UBiDi *pL2VBiDi = getBiDiObject();
4191     UChar src[MAXLEN], dest[MAXLEN], visual1[MAXLEN], visual2[MAXLEN];
4192     char destChars[MAXLEN], vis1Chars[MAXLEN], vis2Chars[MAXLEN];
4193     int32_t srcLen, destLen, vis1Len, vis2Len, option, i, j, nCases, paras;
4194     UErrorCode rc = U_ZERO_ERROR;
4195     UBiDiLevel level;
4196 
4197     log_verbose("\nEntering TestReorderRunsOnly\n\n");
4198 
4199     if(!pL2VBiDi) {
4200         ubidi_close(pBiDi);             /* in case this one was allocated */
4201         return;
4202     }
4203     ubidi_setReorderingMode(pBiDi, UBIDI_REORDER_RUNS_ONLY);
4204     ubidi_setReorderingOptions(pL2VBiDi, UBIDI_OPTION_REMOVE_CONTROLS);
4205 
4206     for (option = 0; option < 2; option++) {
4207         ubidi_setReorderingOptions(pBiDi, option==0 ? UBIDI_OPTION_REMOVE_CONTROLS
4208                                                     : UBIDI_OPTION_INSERT_MARKS);
4209         for (i = 0, nCases = UPRV_LENGTHOF(testCases); i < nCases; i++) {
4210             srcLen = (int32_t)strlen(testCases[i].textIn);
4211             pseudoToU16(srcLen, testCases[i].textIn, src);
4212             for(j = 0; j < 2; j++) {
4213                 log_verbose("Now doing test for option %d, case %d, level %d\n",
4214                             i, option, j);
4215                 level = paraLevels[j];
4216                 ubidi_setPara(pBiDi, src, srcLen, level, NULL, &rc);
4217                 assertSuccessful("ubidi_setPara", &rc);
4218                 *dest = 0;
4219                 destLen = ubidi_writeReordered(pBiDi, dest, MAXLEN, UBIDI_DO_MIRRORING, &rc);
4220                 assertSuccessful("ubidi_writeReordered", &rc);
4221                 u16ToPseudo(destLen, dest, destChars);
4222                 checkWhatYouCan(pBiDi, testCases[i].textIn, destChars);
4223                 assertStringsEqual(testCases[i].textOut[option][level], destChars,
4224                         testCases[i].textIn, "UBIDI_REORDER_RUNS_ONLY",
4225                         option==0 ? "0" : "UBIDI_OPTION_INSERT_MARKS",
4226                         pBiDi);
4227 
4228                 if((option==0) && testCases[i].noroundtrip[level]) {
4229                     continue;
4230                 }
4231                 ubidi_setPara(pL2VBiDi, src, srcLen, level, NULL, &rc);
4232                 assertSuccessful("ubidi_setPara1", &rc);
4233                 *visual1 = 0;
4234                 vis1Len = ubidi_writeReordered(pL2VBiDi, visual1, MAXLEN, UBIDI_DO_MIRRORING, &rc);
4235                 assertSuccessful("ubidi_writeReordered1", &rc);
4236                 u16ToPseudo(vis1Len, visual1, vis1Chars);
4237                 checkWhatYouCan(pL2VBiDi, testCases[i].textIn, vis1Chars);
4238                 ubidi_setPara(pL2VBiDi, dest, destLen, level^1, NULL, &rc);
4239                 assertSuccessful("ubidi_setPara2", &rc);
4240                 *visual2 = 0;
4241                 vis2Len = ubidi_writeReordered(pL2VBiDi, visual2, MAXLEN, UBIDI_DO_MIRRORING, &rc);
4242                 assertSuccessful("ubidi_writeReordered2", &rc);
4243                 u16ToPseudo(vis2Len, visual2, vis2Chars);
4244                 checkWhatYouCan(pL2VBiDi, destChars, vis2Chars);
4245                 assertStringsEqual(vis1Chars, vis2Chars,
4246                         testCases[i].textIn, "UBIDI_REORDER_RUNS_ONLY (2)",
4247                         option==0 ? "0" : "UBIDI_OPTION_INSERT_MARKS",
4248                         pBiDi);
4249             }
4250         }
4251     }
4252 
4253     /* test with null or empty text */
4254     ubidi_setPara(pBiDi, src, 0, UBIDI_LTR, NULL, &rc);
4255     assertSuccessful("ubidi_setPara3", &rc);
4256     paras = ubidi_countParagraphs(pBiDi);
4257     if (paras != 0) {
4258         log_err("\nInvalid number of paras (should be 0): %d\n", paras);
4259     }
4260 
4261     ubidi_close(pBiDi);
4262     ubidi_close(pL2VBiDi);
4263 
4264     log_verbose("\nExiting TestReorderRunsOnly\n\n");
4265 }
4266 
4267 static void
testReorderingMode(void)4268 testReorderingMode(void) {
4269 
4270     UChar src[MAXLEN], dest[MAXLEN];
4271     char destChars[MAXLEN];
4272     UBiDi *pBiDi = NULL, *pBiDi2 = NULL, *pBiDi3 = NULL;
4273     UErrorCode rc;
4274     int tc, mode, option, level;
4275     uint32_t optionValue, optionBack;
4276     UBiDiReorderingMode modeValue, modeBack;
4277     int32_t srcLen, destLen, idx;
4278     const char *expectedChars;
4279     UBool testOK = TRUE;
4280 
4281     log_verbose("\nEntering TestReorderingMode\n\n");
4282 
4283     pBiDi = getBiDiObject();
4284     pBiDi2 = getBiDiObject();
4285     pBiDi3 = getBiDiObject();
4286     if(!pBiDi3) {
4287         ubidi_close(pBiDi);             /* in case this one was allocated */
4288         ubidi_close(pBiDi2);            /* in case this one was allocated */
4289         return;
4290     }
4291 
4292     ubidi_setInverse(pBiDi2, TRUE);
4293 
4294     for (tc = 0; tc < TC_COUNT; tc++) {
4295         const char *srcChars = textIn[tc];
4296         srcLen = (int32_t)strlen(srcChars);
4297         pseudoToU16(srcLen, srcChars, src);
4298 
4299         for (mode = 0; mode < MODES_COUNT; mode++) {
4300             modeValue = modes[mode].value;
4301             ubidi_setReorderingMode(pBiDi, modeValue);
4302             modeBack = ubidi_getReorderingMode(pBiDi);
4303             if (modeValue != modeBack) {
4304                 log_err("Error while setting reordering mode to %d, returned %d\n",
4305                         modeValue, modeBack);
4306             }
4307 
4308             for (option = 0; option < OPTIONS_COUNT; option++) {
4309                 optionValue = options[option].value;
4310                 ubidi_setReorderingOptions(pBiDi, optionValue);
4311                 optionBack = ubidi_getReorderingOptions(pBiDi);
4312                 if (optionValue != optionBack) {
4313                     log_err("Error while setting reordering option to %d, returned %d\n",
4314                             optionValue, optionBack);
4315                 }
4316 
4317                 for (level = 0; level < LEVELS_COUNT; level++) {
4318                     log_verbose("starting test %d mode=%d option=%d level=%d\n",
4319                                 tc, modes[mode].value, options[option].value, level);
4320                     rc = U_ZERO_ERROR;
4321                     ubidi_setPara(pBiDi, src, srcLen, paraLevels[level], NULL, &rc);
4322                     assertSuccessful("ubidi_setPara", &rc);
4323 
4324                     *dest = 0;
4325                     destLen = ubidi_writeReordered(pBiDi, dest, MAXLEN,
4326                                                    UBIDI_DO_MIRRORING, &rc);
4327                     assertSuccessful("ubidi_writeReordered", &rc);
4328                     u16ToPseudo(destLen, dest, destChars);
4329                     if (!((modes[mode].value == UBIDI_REORDER_INVERSE_NUMBERS_AS_L) &&
4330                           (options[option].value == UBIDI_OPTION_INSERT_MARKS))) {
4331                         checkWhatYouCan(pBiDi, srcChars, destChars);
4332                     }
4333 
4334                     if (modes[mode].value == UBIDI_REORDER_INVERSE_NUMBERS_AS_L) {
4335                         idx = -1;
4336                         expectedChars = inverseBasic(pBiDi2, srcChars, srcLen,
4337                                 options[option].value, paraLevels[level], destChars);
4338                     }
4339                     else {
4340                         idx = outIndices[tc][mode][option][level];
4341                         expectedChars = textOut[idx];
4342                     }
4343                     if (!assertStringsEqual(expectedChars, destChars, srcChars,
4344                                 modes[mode].description,
4345                                 options[option].description,
4346                                 pBiDi)) {
4347                         testOK = FALSE;
4348                     }
4349                     if (options[option].value == UBIDI_OPTION_INSERT_MARKS &&
4350                              !assertRoundTrip(pBiDi3, tc, idx, srcChars,
4351                                               destChars, dest, destLen,
4352                                               mode, option, paraLevels[level])) {
4353                         testOK = FALSE;
4354                     }
4355                     else if (!checkResultLength(pBiDi, srcChars, destChars,
4356                                 destLen, modes[mode].description,
4357                                 options[option].description,
4358                                 paraLevels[level])) {
4359                         testOK = FALSE;
4360                     }
4361                     else if (idx > -1 && !checkMaps(pBiDi, idx, srcChars,
4362                             destChars, modes[mode].description,
4363                             options[option].description, paraLevels[level],
4364                             TRUE)) {
4365                         testOK = FALSE;
4366                     }
4367                 }
4368             }
4369         }
4370     }
4371     if (testOK == TRUE) {
4372         log_verbose("\nReordering mode test OK\n");
4373     }
4374     ubidi_close(pBiDi3);
4375     ubidi_close(pBiDi2);
4376     ubidi_close(pBiDi);
4377 
4378     log_verbose("\nExiting TestReorderingMode\n\n");
4379 }
4380 
inverseBasic(UBiDi * pBiDi,const char * srcChars,int32_t srcLen,uint32_t option,UBiDiLevel level,char * result)4381 static const char* inverseBasic(UBiDi *pBiDi, const char *srcChars, int32_t srcLen,
4382                                 uint32_t option, UBiDiLevel level, char *result) {
4383     UErrorCode rc = U_ZERO_ERROR;
4384     int32_t destLen;
4385     UChar src[MAXLEN], dest2[MAXLEN];
4386 
4387     if (pBiDi == NULL || srcChars == NULL) {
4388         return NULL;
4389     }
4390     ubidi_setReorderingOptions(pBiDi, option);
4391     pseudoToU16(srcLen, srcChars, src);
4392     ubidi_setPara(pBiDi, src, srcLen, level, NULL, &rc);
4393     assertSuccessful("ubidi_setPara", &rc);
4394 
4395     *dest2 = 0;
4396     destLen = ubidi_writeReordered(pBiDi, dest2, MAXLEN,
4397                                    UBIDI_DO_MIRRORING, &rc);
4398     assertSuccessful("ubidi_writeReordered", &rc);
4399     u16ToPseudo(destLen, dest2, result);
4400     if (!(option == UBIDI_OPTION_INSERT_MARKS)) {
4401         checkWhatYouCan(pBiDi, srcChars, result);
4402     }
4403     return result;
4404 }
4405 
4406 #define NULL_CHAR '\0'
4407 
4408 static void
testStreaming(void)4409 testStreaming(void) {
4410 #define MAXPORTIONS 10
4411 
4412     static const struct {
4413         const char* textIn;
4414         short int chunk;
4415         short int nPortions[2];
4416         char  portionLens[2][MAXPORTIONS];
4417         const char* message[2];
4418     } testData[] = {
4419         {   "123\\u000A"
4420             "abc45\\u000D"
4421             "67890\\u000A"
4422             "\\u000D"
4423             "02468\\u000D"
4424             "ghi",
4425             6, { 6, 6 }, {{ 4, 6, 6, 1, 6, 3}, { 4, 6, 6, 1, 6, 3 }},
4426             {"4, 6, 6, 1, 6, 3", "4, 6, 6, 1, 6, 3"}
4427         },
4428         {   "abcd\\u000Afgh\\u000D12345\\u000A456",
4429             6, { 4, 4 }, {{ 5, 4, 6, 3 }, { 5, 4, 6, 3 }},
4430             {"5, 4, 6, 3", "5, 4, 6, 3"}
4431         },
4432         {   "abcd\\u000Afgh\\u000D12345\\u000A45\\u000D",
4433             6, { 4, 4 }, {{ 5, 4, 6, 3 }, { 5, 4, 6, 3 }},
4434             {"5, 4, 6, 3", "5, 4, 6, 3"}
4435         },
4436         {   "abcde\\u000Afghi",
4437             10, { 2, 2 }, {{ 6, 4 }, { 6, 4 }},
4438             {"6, 4", "6, 4"}
4439         }
4440     };
4441     UChar src[MAXLEN];
4442     UBiDi *pBiDi = NULL;
4443     UChar *pSrc;
4444     UErrorCode rc = U_ZERO_ERROR;
4445     int32_t srcLen, processedLen, chunk, len, nPortions;
4446     int i, j, levelIndex;
4447     UBiDiLevel level;
4448     int nTests = UPRV_LENGTHOF(testData), nLevels = UPRV_LENGTHOF(paraLevels);
4449     UBool mismatch, testOK = TRUE;
4450    char processedLenStr[MAXPORTIONS * 5];
4451 
4452     log_verbose("\nEntering TestStreaming\n\n");
4453 
4454     pBiDi = getBiDiObject();
4455 
4456     ubidi_orderParagraphsLTR(pBiDi, TRUE);
4457 
4458     for (levelIndex = 0; levelIndex < nLevels; levelIndex++) {
4459         for (i = 0; i < nTests; i++) {
4460             srcLen = u_unescape(testData[i].textIn, src, MAXLEN);
4461             chunk = testData[i].chunk;
4462             nPortions = testData[i].nPortions[levelIndex];
4463             level = paraLevels[levelIndex];
4464             processedLenStr[0] = NULL_CHAR;
4465             log_verbose("Testing level %d, case %d\n", level, i);
4466 
4467             mismatch = FALSE;
4468 
4469             ubidi_setReorderingOptions(pBiDi, UBIDI_OPTION_STREAMING);
4470             for (j = 0, pSrc = src; j < MAXPORTIONS && srcLen > 0; j++) {
4471 
4472                 len = chunk < srcLen ? chunk : srcLen;
4473                 ubidi_setPara(pBiDi, pSrc, len, level, NULL, &rc);
4474                 if (!assertSuccessful("ubidi_setPara", &rc)) {
4475                     break;
4476                 }
4477 
4478                 processedLen = ubidi_getProcessedLength(pBiDi);
4479                 if (processedLen == 0) {
4480                     ubidi_setReorderingOptions(pBiDi, UBIDI_OPTION_DEFAULT);
4481                     j--;
4482                     continue;
4483                 }
4484                 ubidi_setReorderingOptions(pBiDi, UBIDI_OPTION_STREAMING);
4485 
4486                 mismatch |= (UBool)(j >= nPortions ||
4487                            processedLen != testData[i].portionLens[levelIndex][j]);
4488 
4489                 sprintf(processedLenStr + j * 4, "%4d", processedLen);
4490                 srcLen -= processedLen, pSrc += processedLen;
4491             }
4492 
4493             if (mismatch || j != nPortions) {
4494                 testOK = FALSE;
4495                 log_err("\nProcessed lengths mismatch.\n"
4496                     "\tParagraph level: %u\n"
4497                     "\tInput string: %s\n"
4498                     "\tActually processed portion lengths: { %s }\n"
4499                     "\tExpected portion lengths          : { %s }\n",
4500                     paraLevels[levelIndex], testData[i].textIn,
4501                     processedLenStr, testData[i].message[levelIndex]);
4502             }
4503         }
4504     }
4505     ubidi_close(pBiDi);
4506     if (testOK == TRUE) {
4507         log_verbose("\nBiDi streaming test OK\n");
4508     }
4509     log_verbose("\nExiting TestStreaming\n\n");
4510 }
4511 
4512 U_CDECL_BEGIN
4513 
4514 static UCharDirection U_CALLCONV
overrideBidiClass(const void * context,UChar32 c)4515 overrideBidiClass(const void *context, UChar32 c) {
4516 
4517 #define DEF U_BIDI_CLASS_DEFAULT
4518 
4519     static const UCharDirection customClasses[] = {
4520        /* 0/8    1/9    2/A    3/B    4/C    5/D    6/E    7/F  */
4521           DEF,   DEF,   DEF,   DEF,   DEF,   DEF,   DEF,   DEF, /* 00-07 */
4522           DEF,   DEF,   DEF,   DEF,   DEF,   DEF,   DEF,   DEF, /* 08-0F */
4523           DEF,   DEF,   DEF,   DEF,   DEF,   DEF,   DEF,   DEF, /* 10-17 */
4524           DEF,   DEF,   DEF,   DEF,   DEF,   DEF,   DEF,   DEF, /* 18-1F */
4525           DEF,   DEF,   DEF,   DEF,   DEF,   DEF,     R,   DEF, /* 20-27 */
4526           DEF,   DEF,   DEF,   DEF,   DEF,   DEF,   DEF,   DEF, /* 28-2F */
4527            EN,    EN,    EN,    EN,    EN,    EN,    AN,    AN, /* 30-37 */
4528            AN,    AN,   DEF,   DEF,   DEF,   DEF,   DEF,   DEF, /* 38-3F */
4529             L,    AL,    AL,    AL,    AL,    AL,    AL,     R, /* 40-47 */
4530             R,     R,     R,     R,     R,     R,     R,     R, /* 48-4F */
4531             R,     R,     R,     R,     R,     R,     R,     R, /* 50-57 */
4532             R,     R,     R,   LRE,   DEF,   RLE,   PDF,     S, /* 58-5F */
4533           NSM,   DEF,   DEF,   DEF,   DEF,   DEF,   DEF,   DEF, /* 60-67 */
4534           DEF,   DEF,   DEF,   DEF,   DEF,   DEF,   DEF,   DEF, /* 68-6F */
4535           DEF,   DEF,   DEF,   DEF,   DEF,   DEF,   DEF,   DEF, /* 70-77 */
4536           DEF,   DEF,   DEF,   LRO,     B,   RLO,    BN,   DEF  /* 78-7F */
4537     };
4538     static const int nEntries = UPRV_LENGTHOF(customClasses);
4539     const char *dummy = context;        /* just to avoid a compiler warning */
4540     dummy++;
4541 
4542     return c >= nEntries ? U_BIDI_CLASS_DEFAULT : customClasses[c];
4543 }
4544 
4545 U_CDECL_END
4546 
verifyCallbackParams(UBiDiClassCallback * fn,const void * context,UBiDiClassCallback * expectedFn,const void * expectedContext,int32_t sizeOfContext)4547 static void verifyCallbackParams(UBiDiClassCallback* fn, const void* context,
4548                                  UBiDiClassCallback* expectedFn,
4549                                  const void* expectedContext,
4550                                  int32_t sizeOfContext) {
4551     if (fn != expectedFn) {
4552         log_err("Class callback pointer is not set properly.\n");
4553     }
4554     if (context != expectedContext) {
4555         log_err("Class callback context is not set properly.\n");
4556     }
4557     else if (context != NULL &&
4558             memcmp(context, expectedContext, sizeOfContext)) {
4559         log_err("Callback context content doesn't match the expected one.\n");
4560     }
4561 }
4562 
4563 static void
testClassOverride(void)4564 testClassOverride(void) {
4565     static const char* const textSrc  = "JIH.>12->a \\u05D0\\u05D1 6 ABC78";
4566     static const char* const textResult = "12<.HIJ->a 78CBA 6 \\u05D1\\u05D0";
4567 
4568     UChar src[MAXLEN], dest[MAXLEN];
4569     UErrorCode rc = U_ZERO_ERROR;
4570     UBiDi *pBiDi = NULL;
4571     UBiDiClassCallback* oldFn = NULL;
4572     UBiDiClassCallback* newFn = overrideBidiClass;
4573     const void* oldContext = NULL;
4574     int32_t srcLen, destLen, textSrcSize = (int32_t)uprv_strlen(textSrc);
4575     char* destChars = NULL;
4576 
4577     log_verbose("\nEntering TestClassOverride\n\n");
4578 
4579     pBiDi = getBiDiObject();
4580     if(!pBiDi) {
4581         return;
4582     }
4583 
4584     ubidi_getClassCallback(pBiDi, &oldFn, &oldContext);
4585     verifyCallbackParams(oldFn, oldContext, NULL, NULL, 0);
4586 
4587     ubidi_setClassCallback(pBiDi, newFn, textSrc, &oldFn, &oldContext, &rc);
4588     if (!assertSuccessful("ubidi_setClassCallback", &rc)) {
4589         ubidi_close(pBiDi);
4590         return;
4591     }
4592     verifyCallbackParams(oldFn, oldContext, NULL, NULL, 0);
4593 
4594     ubidi_getClassCallback(pBiDi, &oldFn, &oldContext);
4595     verifyCallbackParams(oldFn, oldContext, newFn, textSrc, textSrcSize);
4596 
4597     ubidi_setClassCallback(pBiDi, newFn, textSrc, &oldFn, &oldContext, &rc);
4598     if (!assertSuccessful("ubidi_setClassCallback", &rc)) {
4599         ubidi_close(pBiDi);
4600         return;
4601     }
4602     verifyCallbackParams(oldFn, oldContext, newFn, textSrc, textSrcSize);
4603 
4604     srcLen = u_unescape(textSrc, src, MAXLEN);
4605     ubidi_setPara(pBiDi, src, srcLen, UBIDI_LTR, NULL, &rc);
4606     assertSuccessful("ubidi_setPara", &rc);
4607 
4608     destLen = ubidi_writeReordered(pBiDi, dest, MAXLEN,
4609                                    UBIDI_DO_MIRRORING, &rc);
4610     assertSuccessful("ubidi_writeReordered", &rc);
4611 
4612     destChars = aescstrdup(dest, destLen);
4613     if (uprv_strcmp(textResult, destChars)) {
4614         log_err("\nActual and expected output mismatch.\n"
4615             "%20s %s\n%20s %s\n%20s %s\n",
4616             "Input:", textSrc, "Actual output:", destChars,
4617             "Expected output:", textResult);
4618     }
4619     else {
4620         log_verbose("\nClass override test OK\n");
4621     }
4622     ubidi_close(pBiDi);
4623     log_verbose("\nExiting TestClassOverride\n\n");
4624 }
4625 
formatMap(const int32_t * map,int len,char * buffer)4626 static char * formatMap(const int32_t * map, int len, char * buffer)
4627 {
4628     int32_t i, k;
4629     char c;
4630     for (i = 0; i < len; i++) {
4631         k = map[i];
4632         if (k < 0)
4633             c = '-';
4634         else if (k >= (int32_t)sizeof(columns))
4635             c = '+';
4636         else
4637             c = columns[k];
4638         buffer[i] = c;
4639     }
4640     buffer[len] = '\0';
4641     return buffer;
4642 }
4643 
4644 static UBool
checkMaps(UBiDi * pBiDi,int32_t stringIndex,const char * src,const char * dest,const char * mode,const char * option,UBiDiLevel level,UBool forward)4645 checkMaps(UBiDi *pBiDi, int32_t stringIndex, const char *src, const char *dest,
4646           const char *mode, const char* option, UBiDiLevel level, UBool forward)
4647 {
4648     int32_t actualLogicalMap[MAX_MAP_LENGTH];
4649     int32_t actualVisualMap[MAX_MAP_LENGTH];
4650     int32_t getIndexMap[MAX_MAP_LENGTH];
4651     int32_t i, srcLen, resLen, idx;
4652     const int32_t *expectedLogicalMap, *expectedVisualMap;
4653     UErrorCode rc = U_ZERO_ERROR;
4654     UBool testOK = TRUE;
4655 
4656     if (forward) {
4657         expectedLogicalMap = forwardMap[stringIndex];
4658         expectedVisualMap  = inverseMap[stringIndex];
4659     }
4660     else {
4661         expectedLogicalMap = inverseMap[stringIndex];
4662         expectedVisualMap  = forwardMap[stringIndex];
4663     }
4664     ubidi_getLogicalMap(pBiDi, actualLogicalMap, &rc);
4665     if (!assertSuccessful("ubidi_getLogicalMap", &rc)) {
4666         testOK = FALSE;
4667     }
4668     srcLen = ubidi_getProcessedLength(pBiDi);
4669     if (memcmp(expectedLogicalMap, actualLogicalMap, srcLen * sizeof(int32_t))) {
4670         char expChars[MAX_MAP_LENGTH];
4671         char actChars[MAX_MAP_LENGTH];
4672         log_err("\nubidi_getLogicalMap() returns unexpected map for output string "
4673                 "index %d\n"
4674                 "source: %s\n"
4675                 "dest  : %s\n"
4676                 "Scale : %s\n"
4677                 "ExpMap: %s\n"
4678                 "Actual: %s\n"
4679                 "Paragraph level  : %d == %d\n"
4680                 "Reordering mode  : %s == %d\n"
4681                 "Reordering option: %s == %d\n"
4682                 "Forward flag     : %d\n",
4683                 stringIndex, src, dest, columns,
4684                 formatMap(expectedLogicalMap, srcLen, expChars),
4685                 formatMap(actualLogicalMap, srcLen, actChars),
4686                 level, ubidi_getParaLevel(pBiDi),
4687                 mode, ubidi_getReorderingMode(pBiDi),
4688                 option, ubidi_getReorderingOptions(pBiDi),
4689                 forward
4690                 );
4691         testOK = FALSE;
4692     }
4693     resLen = ubidi_getResultLength(pBiDi);
4694     ubidi_getVisualMap(pBiDi, actualVisualMap, &rc);
4695     assertSuccessful("ubidi_getVisualMap", &rc);
4696     if (memcmp(expectedVisualMap, actualVisualMap, resLen * sizeof(int32_t))) {
4697         char expChars[MAX_MAP_LENGTH];
4698         char actChars[MAX_MAP_LENGTH];
4699         log_err("\nubidi_getVisualMap() returns unexpected map for output string "
4700                 "index %d\n"
4701                 "source: %s\n"
4702                 "dest  : %s\n"
4703                 "Scale : %s\n"
4704                 "ExpMap: %s\n"
4705                 "Actual: %s\n"
4706                 "Paragraph level  : %d == %d\n"
4707                 "Reordering mode  : %s == %d\n"
4708                 "Reordering option: %s == %d\n"
4709                 "Forward flag     : %d\n",
4710                 stringIndex, src, dest, columns,
4711                 formatMap(expectedVisualMap, resLen, expChars),
4712                 formatMap(actualVisualMap, resLen, actChars),
4713                 level, ubidi_getParaLevel(pBiDi),
4714                 mode, ubidi_getReorderingMode(pBiDi),
4715                 option, ubidi_getReorderingOptions(pBiDi),
4716                 forward
4717                 );
4718         testOK = FALSE;
4719     }
4720     for (i = 0; i < srcLen; i++) {
4721         idx = ubidi_getVisualIndex(pBiDi, i, &rc);
4722         assertSuccessful("ubidi_getVisualIndex", &rc);
4723         getIndexMap[i] = idx;
4724     }
4725     if (memcmp(actualLogicalMap, getIndexMap, srcLen * sizeof(int32_t))) {
4726         char actChars[MAX_MAP_LENGTH];
4727         char gotChars[MAX_MAP_LENGTH];
4728         log_err("\nMismatch between ubidi_getLogicalMap and ubidi_getVisualIndex for output string "
4729                 "index %d\n"
4730                 "source: %s\n"
4731                 "dest  : %s\n"
4732                 "Scale : %s\n"
4733                 "ActMap: %s\n"
4734                 "IdxMap: %s\n"
4735                 "Paragraph level  : %d == %d\n"
4736                 "Reordering mode  : %s == %d\n"
4737                 "Reordering option: %s == %d\n"
4738                 "Forward flag     : %d\n",
4739                 stringIndex, src, dest, columns,
4740                 formatMap(actualLogicalMap, srcLen, actChars),
4741                 formatMap(getIndexMap, srcLen, gotChars),
4742                 level, ubidi_getParaLevel(pBiDi),
4743                 mode, ubidi_getReorderingMode(pBiDi),
4744                 option, ubidi_getReorderingOptions(pBiDi),
4745                 forward
4746                 );
4747         testOK = FALSE;
4748     }
4749     for (i = 0; i < resLen; i++) {
4750         idx = ubidi_getLogicalIndex(pBiDi, i, &rc);
4751         assertSuccessful("ubidi_getLogicalIndex", &rc);
4752         getIndexMap[i] = idx;
4753     }
4754     if (memcmp(actualVisualMap, getIndexMap, resLen * sizeof(int32_t))) {
4755         char actChars[MAX_MAP_LENGTH];
4756         char gotChars[MAX_MAP_LENGTH];
4757         log_err("\nMismatch between ubidi_getVisualMap and ubidi_getLogicalIndex for output string "
4758                 "index %d\n"
4759                 "source: %s\n"
4760                 "dest  : %s\n"
4761                 "Scale : %s\n"
4762                 "ActMap: %s\n"
4763                 "IdxMap: %s\n"
4764                 "Paragraph level  : %d == %d\n"
4765                 "Reordering mode  : %s == %d\n"
4766                 "Reordering option: %s == %d\n"
4767                 "Forward flag     : %d\n",
4768                 stringIndex, src, dest, columns,
4769                 formatMap(actualVisualMap, resLen, actChars),
4770                 formatMap(getIndexMap, resLen, gotChars),
4771                 level, ubidi_getParaLevel(pBiDi),
4772                 mode, ubidi_getReorderingMode(pBiDi),
4773                 option, ubidi_getReorderingOptions(pBiDi),
4774                 forward
4775                 );
4776         testOK = FALSE;
4777     }
4778     return testOK;
4779 }
4780 
4781 static UBool
assertIllegalArgument(const char * message,UErrorCode * rc)4782 assertIllegalArgument(const char* message, UErrorCode* rc) {
4783     if (*rc != U_ILLEGAL_ARGUMENT_ERROR) {
4784         log_err("%s() failed with error %s.\n", message, myErrorName(*rc));
4785         return FALSE;
4786     }
4787     return TRUE;
4788 }
4789 
4790 typedef struct {
4791     const char* prologue;
4792     const char* source;
4793     const char* epilogue;
4794     const char* expected;
4795     UBiDiLevel paraLevel;
4796 } contextCase;
4797 
4798 static const contextCase contextData[] = {
4799     /*00*/  {"", "", "", "", UBIDI_LTR},
4800     /*01*/  {"", ".-=JKL-+*", "", ".-=LKJ-+*", UBIDI_LTR},
4801     /*02*/  {" ", ".-=JKL-+*", " ", ".-=LKJ-+*", UBIDI_LTR},
4802     /*03*/  {"a", ".-=JKL-+*", "b", ".-=LKJ-+*", UBIDI_LTR},
4803     /*04*/  {"D", ".-=JKL-+*", "", "LKJ=-.-+*", UBIDI_LTR},
4804     /*05*/  {"", ".-=JKL-+*", " D", ".-=*+-LKJ", UBIDI_LTR},
4805     /*06*/  {"", ".-=JKL-+*", " 2", ".-=*+-LKJ", UBIDI_LTR},
4806     /*07*/  {"", ".-=JKL-+*", " 7", ".-=*+-LKJ", UBIDI_LTR},
4807     /*08*/  {" G 1", ".-=JKL-+*", " H", "*+-LKJ=-.", UBIDI_LTR},
4808     /*09*/  {"7", ".-=JKL-+*", " H", ".-=*+-LKJ", UBIDI_LTR},
4809     /*10*/  {"", ".-=abc-+*", "", "*+-abc=-.", UBIDI_RTL},
4810     /*11*/  {" ", ".-=abc-+*", " ", "*+-abc=-.", UBIDI_RTL},
4811     /*12*/  {"D", ".-=abc-+*", "G", "*+-abc=-.", UBIDI_RTL},
4812     /*13*/  {"x", ".-=abc-+*", "", "*+-.-=abc", UBIDI_RTL},
4813     /*14*/  {"", ".-=abc-+*", " y", "abc-+*=-.", UBIDI_RTL},
4814     /*15*/  {"", ".-=abc-+*", " 2", "abc-+*=-.", UBIDI_RTL},
4815     /*16*/  {" x 1", ".-=abc-+*", " 2", ".-=abc-+*", UBIDI_RTL},
4816     /*17*/  {" x 7", ".-=abc-+*", " 8", "*+-.-=abc", UBIDI_RTL},
4817     /*18*/  {"x|", ".-=abc-+*", " 8", "*+-abc=-.", UBIDI_RTL},
4818     /*19*/  {"G|y", ".-=abc-+*", " 8", "*+-.-=abc", UBIDI_RTL},
4819     /*20*/  {"", ".-=", "", ".-=", UBIDI_DEFAULT_LTR},
4820     /*21*/  {"D", ".-=", "", "=-.", UBIDI_DEFAULT_LTR},
4821     /*22*/  {"G", ".-=", "", "=-.", UBIDI_DEFAULT_LTR},
4822     /*23*/  {"xG", ".-=", "", ".-=", UBIDI_DEFAULT_LTR},
4823     /*24*/  {"x|G", ".-=", "", "=-.", UBIDI_DEFAULT_LTR},
4824     /*25*/  {"x|G", ".-=|-+*", "", "=-.|-+*", UBIDI_DEFAULT_LTR},
4825 };
4826 #define CONTEXT_COUNT       UPRV_LENGTHOF(contextData)
4827 
4828 static void
testContext(void)4829 testContext(void) {
4830 
4831     UChar prologue[MAXLEN], epilogue[MAXLEN], src[MAXLEN], dest[MAXLEN];
4832     char destChars[MAXLEN];
4833     UBiDi *pBiDi = NULL;
4834     UErrorCode rc;
4835     int32_t proLength, epiLength, srcLen, destLen, tc;
4836     contextCase cc;
4837     UBool testOK = TRUE;
4838 
4839     log_verbose("\nEntering TestContext \n\n");
4840 
4841     /* test null BiDi object */
4842     rc = U_ZERO_ERROR;
4843     ubidi_setContext(pBiDi, NULL, 0, NULL, 0, &rc);
4844     testOK &= assertIllegalArgument("Error when BiDi object is null", &rc);
4845 
4846     pBiDi = getBiDiObject();
4847     ubidi_orderParagraphsLTR(pBiDi, TRUE);
4848 
4849     /* test proLength < -1 */
4850     rc = U_ZERO_ERROR;
4851     ubidi_setContext(pBiDi, NULL, -2, NULL, 0, &rc);
4852     testOK &= assertIllegalArgument("Error when proLength < -1", &rc);
4853     /* test epiLength < -1 */
4854     rc = U_ZERO_ERROR;
4855     ubidi_setContext(pBiDi, NULL, 0, NULL, -2, &rc);
4856     testOK &= assertIllegalArgument("Error when epiLength < -1", &rc);
4857     /* test prologue == NULL */
4858     rc = U_ZERO_ERROR;
4859     ubidi_setContext(pBiDi, NULL, 3, NULL, 0, &rc);
4860     testOK &= assertIllegalArgument("Prologue is NULL", &rc);
4861     /* test epilogue == NULL */
4862     rc = U_ZERO_ERROR;
4863     ubidi_setContext(pBiDi, NULL, 0, NULL, 4, &rc);
4864     testOK &= assertIllegalArgument("Epilogue is NULL", &rc);
4865 
4866     for (tc = 0; tc < CONTEXT_COUNT; tc++) {
4867         cc = contextData[tc];
4868         proLength = (int32_t)strlen(cc.prologue);
4869         pseudoToU16(proLength, cc.prologue, prologue);
4870         epiLength = (int32_t)strlen(cc.epilogue);
4871         pseudoToU16(epiLength, cc.epilogue, epilogue);
4872         /* in the call below, prologue and epilogue are swapped to show
4873            that the next call will override this call */
4874         rc = U_ZERO_ERROR;
4875         ubidi_setContext(pBiDi, epilogue, epiLength, prologue, proLength, &rc);
4876         testOK &= assertSuccessful("swapped ubidi_setContext", &rc);
4877         ubidi_setContext(pBiDi, prologue, -1, epilogue, -1, &rc);
4878         testOK &= assertSuccessful("regular ubidi_setContext", &rc);
4879         srcLen = (int32_t)strlen(cc.source);
4880         pseudoToU16(srcLen, cc.source, src);
4881         ubidi_setPara(pBiDi, src, srcLen, cc.paraLevel, NULL, &rc);
4882         testOK &= assertSuccessful("ubidi_setPara", &rc);
4883         destLen = ubidi_writeReordered(pBiDi, dest, MAXLEN, UBIDI_DO_MIRRORING, &rc);
4884         assertSuccessful("ubidi_writeReordered", &rc);
4885         u16ToPseudo(destLen, dest, destChars);
4886         if (uprv_strcmp(cc.expected, destChars)) {
4887             char formatChars[MAXLEN];
4888             log_err("\nActual and expected output mismatch on case %d.\n"
4889                 "%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",
4890                 tc,
4891                 "Prologue:", cc.prologue,
4892                 "Input:", cc.source,
4893                 "Epilogue:", cc.epilogue,
4894                 "Expected output:", cc.expected,
4895                 "Actual output:", destChars,
4896                 "Levels:", formatLevels(pBiDi, formatChars),
4897                 "Reordering mode:", ubidi_getReorderingMode(pBiDi),
4898                 "Paragraph level:", ubidi_getParaLevel(pBiDi),
4899                 "Reordering option:", ubidi_getReorderingOptions(pBiDi));
4900             testOK = FALSE;
4901         }
4902     }
4903     if (testOK == TRUE) {
4904         log_verbose("\nContext test OK\n");
4905     }
4906     ubidi_close(pBiDi);
4907 
4908     log_verbose("\nExiting TestContext \n\n");
4909 }
4910 
4911 /* Ticket#11054 ubidi_setPara crash with heavily nested brackets */
4912 static void
testBracketOverflow(void)4913 testBracketOverflow(void) {
4914     static const char* TEXT = "(((((((((((((((((((((((((((((((((((((((((a)(A)))))))))))))))))))))))))))))))))))))))))";
4915     UErrorCode status = U_ZERO_ERROR;
4916     UBiDi* bidi;
4917     UChar src[100];
4918     int32_t len;
4919 
4920     bidi = ubidi_open();
4921     len = (int32_t)uprv_strlen(TEXT);
4922     pseudoToU16(len, TEXT, src);
4923     ubidi_setPara(bidi, src, len, UBIDI_DEFAULT_LTR , NULL, &status);
4924     if (U_FAILURE(status)) {
4925         log_err("setPara failed with heavily nested brackets - %s", u_errorName(status));
4926     }
4927 
4928     ubidi_close(bidi);
4929 }
4930 
TestExplicitLevel0(void)4931 static void TestExplicitLevel0(void) {
4932     // The following used to fail with an error, see ICU ticket #12922.
4933     static const UChar text[2] = { 0x202d, 0x05d0 };
4934     static UBiDiLevel embeddings[2] = { 0, 0 };
4935     UErrorCode errorCode = U_ZERO_ERROR;
4936     UBiDi *bidi = ubidi_open();
4937     ubidi_setPara(bidi, text, 2, UBIDI_DEFAULT_LTR , embeddings, &errorCode);
4938     if (U_FAILURE(errorCode)) {
4939         log_err("ubidi_setPara() - %s", u_errorName(errorCode));
4940     } else {
4941         UBiDiLevel level0 = ubidi_getLevelAt(bidi, 0);
4942         UBiDiLevel level1 = ubidi_getLevelAt(bidi, 1);
4943         if (level0 != 1 || level1 != 1) {
4944             log_err("resolved levels != 1: { %d, %d }\n", level0, level1);
4945         }
4946         if (embeddings[0] != 1 || embeddings[1] != 1) {
4947             log_err("modified embeddings[] levels != 1: { %d, %d }\n", embeddings[0], embeddings[1]);
4948         }
4949     }
4950     ubidi_close(bidi);
4951 }
4952