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