2 *******************************************************************************
3 * Copyright (C) 2008-2010, International Business Machines
4 * Corporation and others. All Rights Reserved.
5 *******************************************************************************
8 package com.ibm.icu.dev.test.bidi;
10 import java.util.Arrays;
12 import com.ibm.icu.impl.Utility;
13 import com.ibm.icu.text.Bidi;
14 import com.ibm.icu.text.BidiRun;
17 * Regression test for Bidi multiple paragraphs
19 * @author Lina Kemmel, Matitiahu Allouche
22 public class TestMultipleParagraphs extends BidiTest {
24 private static final String text =
25 "__ABC\u001c" /* Para #0 offset 0 */
26 + "__\u05d0DE\u001c" /* 1 6 */
27 + "__123\u001c" /* 2 12 */
35 + "JK\u001c"; /* 10 32 */
36 private static final int paraCount = 11;
37 private static final int[] paraBounds = {
38 0, 6, 12, 18, 20, 23, 24, 28, 30, 31, 32, 35
40 private static final byte[] paraLevels = {
41 Bidi.LTR, Bidi.RTL, Bidi.LEVEL_DEFAULT_LTR, Bidi.LEVEL_DEFAULT_RTL, 22, 23
43 private static final byte[][] multiLevels = {
44 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
45 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
46 {0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0},
47 {0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0},
48 {22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22},
49 {23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23}
51 private static final String text2 = "\u05d0 1-2\u001c\u0630 1-2\u001c1-2";
52 private static final byte[] levels2 = {
53 1, 1, 2, 2, 2, 0, 1, 1, 2, 1, 2, 0, 2, 2, 2
55 private static final char[] multiparaTestString = {
56 0x5de, 0x5e0, 0x5e1, 0x5d4, 0x20, 0x5e1, 0x5e4, 0x5da,
57 0x20, 0xa, 0xa, 0x41, 0x72, 0x74, 0x69, 0x73,
58 0x74, 0x3a, 0x20, 0x5de, 0x5e0, 0x5e1, 0x5d4, 0x20,
59 0x5e1, 0x5e4, 0x5da, 0x20, 0xa, 0xa, 0x41, 0x6c,
60 0x62, 0x75, 0x6d, 0x3a, 0x20, 0x5de, 0x5e0, 0x5e1,
61 0x5d4, 0x20, 0x5e1, 0x5e4, 0x5da, 0x20, 0xa, 0xa,
62 0x54, 0x69, 0x6d, 0x65, 0x3a, 0x20, 0x32, 0x3a,
65 private static final byte[] multiparaTestLevels = {
66 1, 1, 1, 1, 1, 1, 1, 1,
67 1, 1, 0, 0, 0, 0, 0, 0,
68 0, 0, 0, 1, 1, 1, 1, 1,
69 1, 1, 1, 0, 0, 0, 0, 0,
70 0, 0, 0, 0, 0, 1, 1, 1,
71 1, 1, 1, 1, 1, 0, 0, 0,
72 0, 0, 0, 0, 0, 0, 0, 0,
76 public void testMultipleParagraphs()
80 boolean orderParagraphsLTR;
82 Bidi bidi = new Bidi();
84 int count, paraStart, paraLimit, paraIndex, length;
87 logln("\nEntering TestMultipleParagraphs\n");
89 bidi.setPara(text, Bidi.LTR, null);
90 } catch (IllegalArgumentException e) {
91 errln("1st Bidi.setPara failed, paraLevel = " + Bidi.LTR);
94 /* check paragraph count and boundaries */
95 if (paraCount != (count = bidi.countParagraphs())) {
96 errln("1st Bidi.countParagraphs returned " + count + ", should be " +
100 for (i = 0; i < paraCount; i++) {
101 run = bidi.getParagraphByIndex(i);
102 paraStart = run.getStart();
103 paraLimit = run.getLimit();
104 if ((paraStart != paraBounds[i]) ||
105 (paraLimit != paraBounds[i + 1])) {
106 errln("Found boundaries of paragraph " + i + ": " +
107 paraStart + "-" + paraLimit + "; expected: " +
108 paraBounds[i] + "-" + paraBounds[i + 1]);
112 /* check with last paragraph not terminated by B */
113 char[] chars = text.toCharArray();
114 chars[chars.length - 1] = 'L';
115 src = new String(chars);
117 bidi.setPara(src, Bidi.LTR, null);
118 } catch (IllegalArgumentException e) {
119 errln("2nd Bidi.setPara failed, paraLevel = " + Bidi.LTR);
121 if (paraCount != (count = bidi.countParagraphs())) {
122 errln("2nd Bidi.countParagraphs returned " + count +
123 ", should be " + paraCount);
126 run = bidi.getParagraphByIndex(i);
127 paraStart = run.getStart();
128 paraLimit = run.getLimit();
129 if ((paraStart != paraBounds[i]) ||
130 (paraLimit != paraBounds[i + 1])) {
131 errln("2nd Found boundaries of paragraph " + i + ": " +
132 paraStart + "-" + paraLimit + "; expected: " +
133 paraBounds[i] + "-" + paraBounds[i + 1]);
136 /* check paraLevel for all paragraphs under various paraLevel specs */
137 for (k = 0; k < 6; k++) {
139 bidi.setPara(src, paraLevels[k], null);
140 } catch (IllegalArgumentException e) {
141 errln("3nd Bidi.setPara failed, paraLevel = " + paraLevels[k]);
143 for (i = 0; i < paraCount; i++) {
144 paraIndex = bidi.getParagraphIndex(paraBounds[i]);
145 run = bidi.getParagraph(paraBounds[i]);
146 if (paraIndex != i) {
147 errln("#1 For paraLevel = " + paraLevels[k] +
148 " paragraph = " + i + ", found paragraph" +
149 " index = " + paraIndex + " expected = " + i);
151 gotLevel = run.getEmbeddingLevel();
152 if (gotLevel != multiLevels[k][i]) {
153 errln("#2 For paraLevel = " + paraLevels[k] +
154 " paragraph = " + i + ", found level = " + gotLevel +
155 ", expected = " + multiLevels[k][i]);
158 gotLevel = bidi.getParaLevel();
159 if (gotLevel != multiLevels[k][0]) {
160 errln("#3 For paraLevel = " + paraLevels[k] +
161 " getParaLevel = " + gotLevel + ", expected " +
166 /* check that the result of Bidi.getParaLevel changes if the first
167 * paragraph has a different level
169 chars[0] = '\u05d2'; /* Hebrew letter Gimel */
170 src = new String(chars);
172 bidi.setPara(src, Bidi.LEVEL_DEFAULT_LTR, null);
173 } catch (IllegalArgumentException e) {
174 errln("Bidi.setPara failed, paraLevel = " + Bidi.LEVEL_DEFAULT_LTR);
176 gotLevel = bidi.getParaLevel();
177 if (gotLevel != Bidi.RTL) {
178 errln("#4 For paraLevel = Bidi.LEVEL_DEFAULT_LTR getParaLevel = " +
179 gotLevel + ", expected = " + Bidi.RTL);
182 /* check that line cannot overlap paragraph boundaries */
183 bidiLine = new Bidi();
185 k = paraBounds[2] + 1;
187 bidiLine = bidi.setLine(i, k);
188 errln("For line limits " + i + "-" + k
189 + " got success, while expected failure");
190 } catch (Exception e) {}
195 bidiLine = bidi.setLine(i, k);
196 } catch (Exception e) {
197 errln("For line limits " + i + "-" + k + " got failure");
200 /* check level of block separator at end of paragraph when orderParagraphsLTR==FALSE */
202 bidi.setPara(src, Bidi.RTL, null);
203 } catch (IllegalArgumentException e) {
204 errln("Bidi.setPara failed, paraLevel = " + Bidi.RTL);
206 /* get levels through para Bidi block */
208 gotLevels = bidi.getLevels();
209 } catch (Exception e) {
210 errln("Error on Bidi.getLevels");
211 gotLevels = new byte[bidi.getLength()];
212 Arrays.fill(gotLevels, (byte)-1);
214 for (i = 26; i < 32; i++) {
215 if (gotLevels[i] != Bidi.RTL) {
216 errln("For char " + i + "(0x" + Utility.hex(chars[i]) +
217 "), level = " + gotLevels[i] + ", expected = " + Bidi.RTL);
220 /* get levels through para Line block */
224 bidiLine = bidi.setLine(i, k);
225 } catch (Exception e) {
226 errln("For line limits " + i + "-" + k + " got failure");
229 paraIndex = bidiLine.getParagraphIndex(i);
230 run = bidiLine.getParagraph(i);
232 gotLevels = bidiLine.getLevels();
233 } catch (Exception e) {
234 errln("Error on bidiLine.getLevels");
235 gotLevels = new byte[bidiLine.getLength()];
236 Arrays.fill(gotLevels, (byte)-1);
238 length = bidiLine.getLength();
239 gotLevel = run.getEmbeddingLevel();
240 if ((gotLevel != Bidi.RTL) || (gotLevels[length - 1] != Bidi.RTL)) {
241 errln("For paragraph " + paraIndex + " with limits " +
242 run.getStart() + "-" + run.getLimit() +
243 ", paraLevel = " + gotLevel +
244 "expected = " + Bidi.RTL +
245 ", level of separator = " + gotLevels[length - 1] +
246 " expected = " + Bidi.RTL);
248 orderParagraphsLTR = bidi.isOrderParagraphsLTR();
249 assertFalse("orderParagraphsLTR is true", orderParagraphsLTR);
250 bidi.orderParagraphsLTR(true);
251 orderParagraphsLTR = bidi.isOrderParagraphsLTR();
252 assertTrue("orderParagraphsLTR is false", orderParagraphsLTR);
254 /* check level of block separator at end of paragraph when orderParagraphsLTR==TRUE */
256 bidi.setPara(src, Bidi.RTL, null);
257 } catch (IllegalArgumentException e) {
258 errln("Bidi.setPara failed, paraLevel = " + Bidi.RTL);
260 /* get levels through para Bidi block */
262 gotLevels = bidi.getLevels();
263 } catch (Exception e) {
264 errln("Error on Bidi.getLevels");
265 gotLevels = new byte[bidi.getLength()];
266 Arrays.fill(gotLevels, (byte)-1);
268 for (i = 26; i < 32; i++) {
269 if (gotLevels[i] != 0) {
270 errln("For char " + i + "(0x" + Utility.hex(chars[i]) +
271 "), level = "+ gotLevels[i] + ", expected = 0");
274 /* get levels through para Line block */
277 paraStart = run.getStart();
278 paraLimit = run.getLimit();
280 bidiLine = bidi.setLine(paraStart, paraLimit);
281 } catch (Exception e) {
282 errln("For line limits " + paraStart + "-" + paraLimit +
285 paraIndex = bidiLine.getParagraphIndex(i);
286 run = bidiLine.getParagraph(i);
288 gotLevels = bidiLine.getLevels();
289 } catch (Exception e) {
290 errln("Error on bidiLine.getLevels");
291 gotLevels = new byte[bidiLine.getLength()];
292 Arrays.fill(gotLevels, (byte)-1);
294 length = bidiLine.getLength();
295 gotLevel = run.getEmbeddingLevel();
296 if ((gotLevel != Bidi.RTL) || (gotLevels[length - 1] != 0)) {
297 err("\nFor paragraph " + paraIndex + " with limits " +
298 run.getStart() + "-" + run.getLimit() +
299 ", paraLevel = " + gotLevel + "expected = " + Bidi.RTL +
300 ", level of separator = " + gotLevels[length - 1] +
301 " expected = 0\nlevels = ");
302 for (count = 0; count < length; count++) {
303 errcont(gotLevels[count] + " ");
308 /* test that the concatenation of separate invocations of the bidi code
309 * on each individual paragraph in order matches the levels array that
310 * results from invoking bidi once over the entire multiparagraph tests
311 * (with orderParagraphsLTR false, of course)
313 src = text; /* restore original content */
314 bidi.orderParagraphsLTR(false);
316 bidi.setPara(src, Bidi.LEVEL_DEFAULT_RTL, null);
317 } catch (IllegalArgumentException e) {
318 errln("Bidi.setPara failed, paraLevel = " + Bidi.LEVEL_DEFAULT_RTL);
321 gotLevels = bidi.getLevels();
322 } catch (Exception e) {
323 errln("Error on bidiLine.getLevels");
324 gotLevels = new byte[bidi.getLength()];
325 Arrays.fill(gotLevels, (byte)-1);
327 for (i = 0; i < paraCount; i++) {
328 /* use pLine for individual paragraphs */
329 paraStart = paraBounds[i];
330 length = paraBounds[i + 1] - paraStart;
332 bidiLine.setPara(src.substring(paraStart, paraStart + length),
333 Bidi.LEVEL_DEFAULT_RTL, null);
334 } catch (IllegalArgumentException e) {
335 errln("Bidi.setPara failed, paraLevel = " + Bidi.LEVEL_DEFAULT_RTL);
337 for (j = 0; j < length; j++) {
338 if ((k = bidiLine.getLevelAt(j)) !=
339 (gotLevel = gotLevels[paraStart + j])) {
340 errln("Checking paragraph concatenation: for paragraph[" +
341 i + "], char[" + j + "] = 0x" +
342 Utility.hex(src.charAt(paraStart + j)) +
343 ", level = " + k + ", expected = " + gotLevel);
348 /* ensure that leading numerics in a paragraph are not treated as arabic
349 numerals because of arabic text in a preceding paragraph
352 bidi.orderParagraphsLTR(true);
354 bidi.setPara(src, Bidi.RTL, null);
355 } catch (IllegalArgumentException e) {
356 errln("Bidi.setPara failed, paraLevel = " + Bidi.RTL);
359 gotLevels = bidi.getLevels();
360 } catch (Exception e) {
361 errln("Error on Bidi.getLevels");
362 gotLevels = new byte[bidi.getLength()];
363 Arrays.fill(gotLevels, (byte)-1);
365 for (i = 0, length = src.length(); i < length; i++) {
366 if (gotLevels[i] != levels2[i]) {
367 errln("Checking leading numerics: for char " + i + "(0x" +
368 Utility.hex(src.charAt(i)) + "), level = " +
369 gotLevels[i] + ", expected = " + levels2[i]);
373 /* check handling of whitespace before end of paragraph separator when
374 * orderParagraphsLTR==TRUE, when last paragraph has, and lacks, a terminating B
376 chars = src.toCharArray();
377 Arrays.fill(chars, '\u0020');
378 bidi.orderParagraphsLTR(true);
379 for (i = 0x001c; i <= 0x0020; i += (0x0020-0x001c)) {
380 chars[4] = (char)i; /* with and without terminating B */
381 for (j = 0x0041; j <= 0x05d0; j += (0x05d0-0x0041)) {
382 chars[0] = (char)j; /* leading 'A' or Alef */
383 src = new String(chars);
384 for (gotLevel = 4; gotLevel <= 5; gotLevel++) {
385 /* test even and odd paraLevel */
387 bidi.setPara(src, gotLevel, null);
388 } catch (IllegalArgumentException e) {
389 errln("Bidi.setPara failed, paraLevel = " + gotLevel);
392 gotLevels = bidi.getLevels();
393 } catch (Exception e) {
394 errln("Error on Bidi.getLevels");
395 gotLevels = new byte[bidi.getLength()];
396 Arrays.fill(gotLevels, (byte)-1);
398 for (k = 1; k <= 3; k++) {
399 if (gotLevels[k] != gotLevel) {
400 errln("Checking trailing spaces for leading char 0x" +
401 Utility.hex(chars[0]) + ", last_char = " +
402 Utility.hex(chars[4]) + ", index = " + k +
403 "level = " + gotLevels[k] +
404 ", expected = " + gotLevel);
411 /* check default orientation when inverse bidi and paragraph starts
412 * with LTR strong char and ends with RTL strong char, with and without
415 bidi.setReorderingMode(Bidi.REORDER_INVERSE_LIKE_DIRECT);
416 bidi.setPara("abc \u05d2\u05d1\n", Bidi.LEVEL_DEFAULT_LTR, null);
417 String out = bidi.writeReordered(0);
418 assertEquals("\nInvalid output", "\u05d1\u05d2 abc\n", out);
419 bidi.setPara("abc \u05d2\u05d1", Bidi.LEVEL_DEFAULT_LTR, null);
420 out = bidi.writeReordered(0);
421 assertEquals("\nInvalid output #1", "\u05d1\u05d2 abc", out);
423 /* check multiple paragraphs together with explicit levels
425 bidi.setReorderingMode(Bidi.REORDER_DEFAULT);
426 gotLevels = new byte[] {0,0,0,0,0,0,0,0,0,0};
427 bidi.setPara("ab\u05d1\u05d2\n\u05d3\u05d4123", Bidi.LTR, gotLevels);
428 out = bidi.writeReordered(0);
429 assertEquals("\nInvalid output #2", "ab\u05d2\u05d1\n123\u05d4\u05d3", out);
430 assertEquals("\nInvalid number of paras", 2, bidi.countParagraphs());
432 logln("\nExiting TestMultipleParagraphs\n");
434 /* check levels in multiple paragraphs with default para level
437 bidi.setPara(multiparaTestString, Bidi.LEVEL_DEFAULT_LTR, null);
439 gotLevels = bidi.getLevels();
440 } catch (Exception e) {
441 errln("Error on Bidi.getLevels for multiparaTestString");
444 for (i = 0; i < multiparaTestString.length; i++) {
445 if (gotLevels[i] != multiparaTestLevels[i]) {
446 errln("Error on level for multiparaTestString at index " + i +
447 ", expected=" + multiparaTestLevels[i] +
448 ", actual=" + gotLevels[i]);
454 public static void main(String[] args) {
456 new TestMultipleParagraphs().run(args);
458 catch (Exception e) {
459 System.out.println(e);