2 *******************************************************************************
\r
3 * Copyright (C) 2008, International Business Machines
\r
4 * Corporation and others. All Rights Reserved.
\r
5 *******************************************************************************
\r
8 package com.ibm.icu.dev.test.bidi;
\r
10 import java.util.Arrays;
\r
11 import com.ibm.icu.impl.Utility;
\r
12 import com.ibm.icu.text.Bidi;
\r
13 import com.ibm.icu.text.BidiRun;
\r
16 * Regression test for Bidi multiple paragraphs
\r
18 * @author Lina Kemmel, Matitiahu Allouche
\r
21 public class TestMultipleParagraphs extends BidiTest {
\r
23 private static final String text =
\r
24 "__ABC\u001c" /* Para #0 offset 0 */
\r
25 + "__\u05d0DE\u001c" /* 1 6 */
\r
26 + "__123\u001c" /* 2 12 */
\r
30 + "HI\r\n" /* 6 24 */
\r
34 + "JK\u001c"; /* 10 32 */
\r
35 private static final int paraCount = 11;
\r
36 private static final int[] paraBounds = {
\r
37 0, 6, 12, 18, 20, 23, 24, 28, 30, 31, 32, 35
\r
39 private static final byte[] paraLevels = {
\r
40 Bidi.LTR, Bidi.RTL, Bidi.LEVEL_DEFAULT_LTR, Bidi.LEVEL_DEFAULT_RTL, 22, 23
\r
42 private static final byte[][] multiLevels = {
\r
43 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
\r
44 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
\r
45 {0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0},
\r
46 {0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0},
\r
47 {22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22},
\r
48 {23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23}
\r
50 private static final String text2 = "\u05d0 1-2\u001c\u0630 1-2\u001c1-2";
\r
51 private static final byte[] levels2 = {
\r
52 1, 1, 2, 2, 2, 0, 1, 1, 2, 1, 2, 0, 2, 2, 2
\r
54 private static final char[] multiparaTestString = {
\r
55 0x5de, 0x5e0, 0x5e1, 0x5d4, 0x20, 0x5e1, 0x5e4, 0x5da,
\r
56 0x20, 0xa, 0xa, 0x41, 0x72, 0x74, 0x69, 0x73,
\r
57 0x74, 0x3a, 0x20, 0x5de, 0x5e0, 0x5e1, 0x5d4, 0x20,
\r
58 0x5e1, 0x5e4, 0x5da, 0x20, 0xa, 0xa, 0x41, 0x6c,
\r
59 0x62, 0x75, 0x6d, 0x3a, 0x20, 0x5de, 0x5e0, 0x5e1,
\r
60 0x5d4, 0x20, 0x5e1, 0x5e4, 0x5da, 0x20, 0xa, 0xa,
\r
61 0x54, 0x69, 0x6d, 0x65, 0x3a, 0x20, 0x32, 0x3a,
\r
62 0x32, 0x37, 0xa, 0xa
\r
64 private static final byte[] multiparaTestLevels = {
\r
65 1, 1, 1, 1, 1, 1, 1, 1,
\r
66 1, 1, 0, 0, 0, 0, 0, 0,
\r
67 0, 0, 0, 1, 1, 1, 1, 1,
\r
68 1, 1, 1, 0, 0, 0, 0, 0,
\r
69 0, 0, 0, 0, 0, 1, 1, 1,
\r
70 1, 1, 1, 1, 1, 0, 0, 0,
\r
71 0, 0, 0, 0, 0, 0, 0, 0,
\r
75 public void testMultipleParagraphs()
\r
79 boolean orderParagraphsLTR;
\r
81 Bidi bidi = new Bidi();
\r
83 int count, paraStart, paraLimit, paraIndex, length;
\r
86 logln("\nEntering TestMultipleParagraphs\n");
\r
88 bidi.setPara(text, Bidi.LTR, null);
\r
89 } catch (IllegalArgumentException e) {
\r
90 errln("1st Bidi.setPara failed, paraLevel = " + Bidi.LTR);
\r
93 /* check paragraph count and boundaries */
\r
94 if (paraCount != (count = bidi.countParagraphs())) {
\r
95 errln("1st Bidi.countParagraphs returned " + count + ", should be " +
\r
99 for (i = 0; i < paraCount; i++) {
\r
100 run = bidi.getParagraphByIndex(i);
\r
101 paraStart = run.getStart();
\r
102 paraLimit = run.getLimit();
\r
103 if ((paraStart != paraBounds[i]) ||
\r
104 (paraLimit != paraBounds[i + 1])) {
\r
105 errln("Found boundaries of paragraph " + i + ": " +
\r
106 paraStart + "-" + paraLimit + "; expected: " +
\r
107 paraBounds[i] + "-" + paraBounds[i + 1]);
\r
111 /* check with last paragraph not terminated by B */
\r
112 char[] chars = text.toCharArray();
\r
113 chars[chars.length - 1] = 'L';
\r
114 src = new String(chars);
\r
116 bidi.setPara(src, Bidi.LTR, null);
\r
117 } catch (IllegalArgumentException e) {
\r
118 errln("2nd Bidi.setPara failed, paraLevel = " + Bidi.LTR);
\r
120 if (paraCount != (count = bidi.countParagraphs())) {
\r
121 errln("2nd Bidi.countParagraphs returned " + count +
\r
122 ", should be " + paraCount);
\r
125 run = bidi.getParagraphByIndex(i);
\r
126 paraStart = run.getStart();
\r
127 paraLimit = run.getLimit();
\r
128 if ((paraStart != paraBounds[i]) ||
\r
129 (paraLimit != paraBounds[i + 1])) {
\r
130 errln("2nd Found boundaries of paragraph " + i + ": " +
\r
131 paraStart + "-" + paraLimit + "; expected: " +
\r
132 paraBounds[i] + "-" + paraBounds[i + 1]);
\r
135 /* check paraLevel for all paragraphs under various paraLevel specs */
\r
136 for (k = 0; k < 6; k++) {
\r
138 bidi.setPara(src, paraLevels[k], null);
\r
139 } catch (IllegalArgumentException e) {
\r
140 errln("3nd Bidi.setPara failed, paraLevel = " + paraLevels[k]);
\r
142 for (i = 0; i < paraCount; i++) {
\r
143 paraIndex = bidi.getParagraphIndex(paraBounds[i]);
\r
144 run = bidi.getParagraph(paraBounds[i]);
\r
145 if (paraIndex != i) {
\r
146 errln("#1 For paraLevel = " + paraLevels[k] +
\r
147 " paragraph = " + i + ", found paragraph" +
\r
148 " index = " + paraIndex + " expected = " + i);
\r
150 gotLevel = run.getEmbeddingLevel();
\r
151 if (gotLevel != multiLevels[k][i]) {
\r
152 errln("#2 For paraLevel = " + paraLevels[k] +
\r
153 " paragraph = " + i + ", found level = " + gotLevel +
\r
154 ", expected = " + multiLevels[k][i]);
\r
157 gotLevel = bidi.getParaLevel();
\r
158 if (gotLevel != multiLevels[k][0]) {
\r
159 errln("#3 For paraLevel = " + paraLevels[k] +
\r
160 " getParaLevel = " + gotLevel + ", expected " +
\r
161 multiLevels[k][0]);
\r
165 /* check that the result of Bidi.getParaLevel changes if the first
\r
166 * paragraph has a different level
\r
168 chars[0] = '\u05d2'; /* Hebrew letter Gimel */
\r
169 src = new String(chars);
\r
171 bidi.setPara(src, Bidi.LEVEL_DEFAULT_LTR, null);
\r
172 } catch (IllegalArgumentException e) {
\r
173 errln("Bidi.setPara failed, paraLevel = " + Bidi.LEVEL_DEFAULT_LTR);
\r
175 gotLevel = bidi.getParaLevel();
\r
176 if (gotLevel != Bidi.RTL) {
\r
177 errln("#4 For paraLevel = Bidi.LEVEL_DEFAULT_LTR getParaLevel = " +
\r
178 gotLevel + ", expected = " + Bidi.RTL);
\r
181 /* check that line cannot overlap paragraph boundaries */
\r
182 bidiLine = new Bidi();
\r
184 k = paraBounds[2] + 1;
\r
186 bidiLine = bidi.setLine(i, k);
\r
187 errln("For line limits " + i + "-" + k
\r
188 + " got success, while expected failure");
\r
189 } catch (Exception e) {}
\r
194 bidiLine = bidi.setLine(i, k);
\r
195 } catch (Exception e) {
\r
196 errln("For line limits " + i + "-" + k + " got failure");
\r
199 /* check level of block separator at end of paragraph when orderParagraphsLTR==FALSE */
\r
201 bidi.setPara(src, Bidi.RTL, null);
\r
202 } catch (IllegalArgumentException e) {
\r
203 errln("Bidi.setPara failed, paraLevel = " + Bidi.RTL);
\r
205 /* get levels through para Bidi block */
\r
207 gotLevels = bidi.getLevels();
\r
208 } catch (Exception e) {
\r
209 errln("Error on Bidi.getLevels");
\r
210 gotLevels = new byte[bidi.getLength()];
\r
211 Arrays.fill(gotLevels, (byte)-1);
\r
213 for (i = 26; i < 32; i++) {
\r
214 if (gotLevels[i] != Bidi.RTL) {
\r
215 errln("For char " + i + "(0x" + Utility.hex(chars[i]) +
\r
216 "), level = " + gotLevels[i] + ", expected = " + Bidi.RTL);
\r
219 /* get levels through para Line block */
\r
223 bidiLine = bidi.setLine(i, k);
\r
224 } catch (Exception e) {
\r
225 errln("For line limits " + i + "-" + k + " got failure");
\r
228 paraIndex = bidiLine.getParagraphIndex(i);
\r
229 run = bidiLine.getParagraph(i);
\r
231 gotLevels = bidiLine.getLevels();
\r
232 } catch (Exception e) {
\r
233 errln("Error on bidiLine.getLevels");
\r
234 gotLevels = new byte[bidiLine.getLength()];
\r
235 Arrays.fill(gotLevels, (byte)-1);
\r
237 length = bidiLine.getLength();
\r
238 gotLevel = run.getEmbeddingLevel();
\r
239 if ((gotLevel != Bidi.RTL) || (gotLevels[length - 1] != Bidi.RTL)) {
\r
240 errln("For paragraph " + paraIndex + " with limits " +
\r
241 run.getStart() + "-" + run.getLimit() +
\r
242 ", paraLevel = " + gotLevel +
\r
243 "expected = " + Bidi.RTL +
\r
244 ", level of separator = " + gotLevels[length - 1] +
\r
245 " expected = " + Bidi.RTL);
\r
247 orderParagraphsLTR = bidi.isOrderParagraphsLTR();
\r
248 assertFalse("orderParagraphsLTR is true", orderParagraphsLTR);
\r
249 bidi.orderParagraphsLTR(true);
\r
250 orderParagraphsLTR = bidi.isOrderParagraphsLTR();
\r
251 assertTrue("orderParagraphsLTR is false", orderParagraphsLTR);
\r
253 /* check level of block separator at end of paragraph when orderParagraphsLTR==TRUE */
\r
255 bidi.setPara(src, Bidi.RTL, null);
\r
256 } catch (IllegalArgumentException e) {
\r
257 errln("Bidi.setPara failed, paraLevel = " + Bidi.RTL);
\r
259 /* get levels through para Bidi block */
\r
261 gotLevels = bidi.getLevels();
\r
262 } catch (Exception e) {
\r
263 errln("Error on Bidi.getLevels");
\r
264 gotLevels = new byte[bidi.getLength()];
\r
265 Arrays.fill(gotLevels, (byte)-1);
\r
267 for (i = 26; i < 32; i++) {
\r
268 if (gotLevels[i] != 0) {
\r
269 errln("For char " + i + "(0x" + Utility.hex(chars[i]) +
\r
270 "), level = "+ gotLevels[i] + ", expected = 0");
\r
273 /* get levels through para Line block */
\r
276 paraStart = run.getStart();
\r
277 paraLimit = run.getLimit();
\r
279 bidiLine = bidi.setLine(paraStart, paraLimit);
\r
280 } catch (Exception e) {
\r
281 errln("For line limits " + paraStart + "-" + paraLimit +
\r
284 paraIndex = bidiLine.getParagraphIndex(i);
\r
285 run = bidiLine.getParagraph(i);
\r
287 gotLevels = bidiLine.getLevels();
\r
288 } catch (Exception e) {
\r
289 errln("Error on bidiLine.getLevels");
\r
290 gotLevels = new byte[bidiLine.getLength()];
\r
291 Arrays.fill(gotLevels, (byte)-1);
\r
293 length = bidiLine.getLength();
\r
294 gotLevel = run.getEmbeddingLevel();
\r
295 if ((gotLevel != Bidi.RTL) || (gotLevels[length - 1] != 0)) {
\r
296 err("\nFor paragraph " + paraIndex + " with limits " +
\r
297 run.getStart() + "-" + run.getLimit() +
\r
298 ", paraLevel = " + gotLevel + "expected = " + Bidi.RTL +
\r
299 ", level of separator = " + gotLevels[length - 1] +
\r
300 " expected = 0\nlevels = ");
\r
301 for (count = 0; count < length; count++) {
\r
302 errcont(gotLevels[count] + " ");
\r
307 /* test that the concatenation of separate invocations of the bidi code
\r
308 * on each individual paragraph in order matches the levels array that
\r
309 * results from invoking bidi once over the entire multiparagraph tests
\r
310 * (with orderParagraphsLTR false, of course)
\r
312 src = text; /* restore original content */
\r
313 bidi.orderParagraphsLTR(false);
\r
315 bidi.setPara(src, Bidi.LEVEL_DEFAULT_RTL, null);
\r
316 } catch (IllegalArgumentException e) {
\r
317 errln("Bidi.setPara failed, paraLevel = " + Bidi.LEVEL_DEFAULT_RTL);
\r
320 gotLevels = bidi.getLevels();
\r
321 } catch (Exception e) {
\r
322 errln("Error on bidiLine.getLevels");
\r
323 gotLevels = new byte[bidi.getLength()];
\r
324 Arrays.fill(gotLevels, (byte)-1);
\r
326 for (i = 0; i < paraCount; i++) {
\r
327 /* use pLine for individual paragraphs */
\r
328 paraStart = paraBounds[i];
\r
329 length = paraBounds[i + 1] - paraStart;
\r
331 bidiLine.setPara(src.substring(paraStart, paraStart + length),
\r
332 Bidi.LEVEL_DEFAULT_RTL, null);
\r
333 } catch (IllegalArgumentException e) {
\r
334 errln("Bidi.setPara failed, paraLevel = " + Bidi.LEVEL_DEFAULT_RTL);
\r
336 for (j = 0; j < length; j++) {
\r
337 if ((k = bidiLine.getLevelAt(j)) !=
\r
338 (gotLevel = gotLevels[paraStart + j])) {
\r
339 errln("Checking paragraph concatenation: for paragraph[" +
\r
340 i + "], char[" + j + "] = 0x" +
\r
341 Utility.hex(src.charAt(paraStart + j)) +
\r
342 ", level = " + k + ", expected = " + gotLevel);
\r
347 /* ensure that leading numerics in a paragraph are not treated as arabic
\r
348 numerals because of arabic text in a preceding paragraph
\r
351 bidi.orderParagraphsLTR(true);
\r
353 bidi.setPara(src, Bidi.RTL, null);
\r
354 } catch (IllegalArgumentException e) {
\r
355 errln("Bidi.setPara failed, paraLevel = " + Bidi.RTL);
\r
358 gotLevels = bidi.getLevels();
\r
359 } catch (Exception e) {
\r
360 errln("Error on Bidi.getLevels");
\r
361 gotLevels = new byte[bidi.getLength()];
\r
362 Arrays.fill(gotLevels, (byte)-1);
\r
364 for (i = 0, length = src.length(); i < length; i++) {
\r
365 if (gotLevels[i] != levels2[i]) {
\r
366 errln("Checking leading numerics: for char " + i + "(0x" +
\r
367 Utility.hex(src.charAt(i)) + "), level = " +
\r
368 gotLevels[i] + ", expected = " + levels2[i]);
\r
372 /* check handling of whitespace before end of paragraph separator when
\r
373 * orderParagraphsLTR==TRUE, when last paragraph has, and lacks, a terminating B
\r
375 chars = src.toCharArray();
\r
376 Arrays.fill(chars, '\u0020');
\r
377 bidi.orderParagraphsLTR(true);
\r
378 for (i = 0x001c; i <= 0x0020; i += (0x0020-0x001c)) {
\r
379 chars[4] = (char)i; /* with and without terminating B */
\r
380 for (j = 0x0041; j <= 0x05d0; j += (0x05d0-0x0041)) {
\r
381 chars[0] = (char)j; /* leading 'A' or Alef */
\r
382 src = new String(chars);
\r
383 for (gotLevel = 4; gotLevel <= 5; gotLevel++) {
\r
384 /* test even and odd paraLevel */
\r
386 bidi.setPara(src, gotLevel, null);
\r
387 } catch (IllegalArgumentException e) {
\r
388 errln("Bidi.setPara failed, paraLevel = " + gotLevel);
\r
391 gotLevels = bidi.getLevels();
\r
392 } catch (Exception e) {
\r
393 errln("Error on Bidi.getLevels");
\r
394 gotLevels = new byte[bidi.getLength()];
\r
395 Arrays.fill(gotLevels, (byte)-1);
\r
397 for (k = 1; k <= 3; k++) {
\r
398 if (gotLevels[k] != gotLevel) {
\r
399 errln("Checking trailing spaces for leading char 0x" +
\r
400 Utility.hex(chars[0]) + ", last_char = " +
\r
401 Utility.hex(chars[4]) + ", index = " + k +
\r
402 "level = " + gotLevels[k] +
\r
403 ", expected = " + gotLevel);
\r
410 /* check default orientation when inverse bidi and paragraph starts
\r
411 * with LTR strong char and ends with RTL strong char, with and without
\r
414 bidi.setReorderingMode(Bidi.REORDER_INVERSE_LIKE_DIRECT);
\r
415 bidi.setPara("abc \u05d2\u05d1\n", Bidi.LEVEL_DEFAULT_LTR, null);
\r
416 String out = bidi.writeReordered(0);
\r
417 assertEquals("\nInvalid output", "\u05d1\u05d2 abc\n", out);
\r
418 bidi.setPara("abc \u05d2\u05d1", Bidi.LEVEL_DEFAULT_LTR, null);
\r
419 out = bidi.writeReordered(0);
\r
420 assertEquals("\nInvalid output #1", "\u05d1\u05d2 abc", out);
\r
422 /* check multiple paragraphs together with explicit levels
\r
424 bidi.setReorderingMode(Bidi.REORDER_DEFAULT);
\r
425 gotLevels = new byte[] {0,0,0,0,0,0,0,0,0,0};
\r
426 bidi.setPara("ab\u05d1\u05d2\n\u05d3\u05d4123", Bidi.LTR, gotLevels);
\r
427 out = bidi.writeReordered(0);
\r
428 assertEquals("\nInvalid output #2", "ab\u05d2\u05d1\n123\u05d4\u05d3", out);
\r
429 assertEquals("\nInvalid number of paras", 2, bidi.countParagraphs());
\r
431 logln("\nExiting TestMultipleParagraphs\n");
\r
433 /* check levels in multiple paragraphs with default para level
\r
436 bidi.setPara(multiparaTestString, Bidi.LEVEL_DEFAULT_LTR, null);
\r
438 gotLevels = bidi.getLevels();
\r
439 } catch (Exception e) {
\r
440 errln("Error on Bidi.getLevels for multiparaTestString");
\r
443 for (i = 0; i < multiparaTestString.length; i++) {
\r
444 if (gotLevels[i] != multiparaTestLevels[i]) {
\r
445 errln("Error on level for multiparaTestString at index " + i +
\r
446 ", expected=" + multiparaTestLevels[i] +
\r
447 ", actual=" + gotLevels[i]);
\r
453 public static void main(String[] args) {
\r
455 new TestMultipleParagraphs().run(args);
\r
457 catch (Exception e) {
\r
458 System.out.println(e);
\r