1 /* 2 ******************************************************************************* 3 * Copyright (C) 2008-2010, International Business Machines 4 * Corporation and others. All Rights Reserved. 5 ******************************************************************************* 6 */ 7 8 package com.ibm.icu.dev.test.bidi; 9 10 import java.util.Arrays; 11 12 import com.ibm.icu.impl.Utility; 13 import com.ibm.icu.text.Bidi; 14 import com.ibm.icu.text.BidiRun; 15 16 /** 17 * Regression test for Bidi multiple paragraphs 18 * 19 * @author Lina Kemmel, Matitiahu Allouche 20 */ 21 22 public class TestMultipleParagraphs extends BidiTest { 23 24 private static final String text = 25 "__ABC\u001c" /* Para #0 offset 0 */ 26 + "__\u05d0DE\u001c" /* 1 6 */ 27 + "__123\u001c" /* 2 12 */ 28 + "\r\n" /* 3 18 */ 29 + "FG\r" /* 4 20 */ 30 + "\r" /* 5 23 */ 31 + "HI\r\n" /* 6 24 */ 32 + "\r\n" /* 7 28 */ 33 + "\n" /* 8 30 */ 34 + "\n" /* 9 31 */ 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 39 }; 40 private static final byte[] paraLevels = { 41 Bidi.LTR, Bidi.RTL, Bidi.LEVEL_DEFAULT_LTR, Bidi.LEVEL_DEFAULT_RTL, 22, 23 42 }; 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} 50 }; 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 54 }; 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, 63 0x32, 0x37, 0xa, 0xa 64 }; 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, 73 0, 0, 0, 0 74 }; 75 76 public void testMultipleParagraphs() 77 { 78 byte gotLevel; 79 byte[] gotLevels; 80 boolean orderParagraphsLTR; 81 String src; 82 Bidi bidi = new Bidi(); 83 Bidi bidiLine; 84 int count, paraStart, paraLimit, paraIndex, length; 85 int i, j, k; 86 87 logln("\nEntering TestMultipleParagraphs\n"); 88 try { 89 bidi.setPara(text, Bidi.LTR, null); 90 } catch (IllegalArgumentException e) { 91 errln("1st Bidi.setPara failed, paraLevel = " + Bidi.LTR); 92 } 93 94 /* check paragraph count and boundaries */ 95 if (paraCount != (count = bidi.countParagraphs())) { 96 errln("1st Bidi.countParagraphs returned " + count + ", should be " + 97 paraCount); 98 } 99 BidiRun run; 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]); 109 } 110 } 111 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); 116 try { 117 bidi.setPara(src, Bidi.LTR, null); 118 } catch (IllegalArgumentException e) { 119 errln("2nd Bidi.setPara failed, paraLevel = " + Bidi.LTR); 120 } 121 if (paraCount != (count = bidi.countParagraphs())) { 122 errln("2nd Bidi.countParagraphs returned " + count + 123 ", should be " + paraCount); 124 } 125 i = paraCount - 1; 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]); 134 } 135 136 /* check paraLevel for all paragraphs under various paraLevel specs */ 137 for (k = 0; k < 6; k++) { 138 try { 139 bidi.setPara(src, paraLevels[k], null); 140 } catch (IllegalArgumentException e) { 141 errln("3nd Bidi.setPara failed, paraLevel = " + paraLevels[k]); 142 } 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); 150 } 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]); 156 } 157 } 158 gotLevel = bidi.getParaLevel(); 159 if (gotLevel != multiLevels[k][0]) { 160 errln("#3 For paraLevel = " + paraLevels[k] + 161 " getParaLevel = " + gotLevel + ", expected " + 162 multiLevels[k][0]); 163 } 164 } 165 166 /* check that the result of Bidi.getParaLevel changes if the first 167 * paragraph has a different level 168 */ 169 chars[0] = '\u05d2'; /* Hebrew letter Gimel */ 170 src = new String(chars); 171 try { 172 bidi.setPara(src, Bidi.LEVEL_DEFAULT_LTR, null); 173 } catch (IllegalArgumentException e) { 174 errln("Bidi.setPara failed, paraLevel = " + Bidi.LEVEL_DEFAULT_LTR); 175 } 176 gotLevel = bidi.getParaLevel(); 177 if (gotLevel != Bidi.RTL) { 178 errln("#4 For paraLevel = Bidi.LEVEL_DEFAULT_LTR getParaLevel = " + 179 gotLevel + ", expected = " + Bidi.RTL); 180 } 181 182 /* check that line cannot overlap paragraph boundaries */ 183 bidiLine = new Bidi(); 184 i = paraBounds[1]; 185 k = paraBounds[2] + 1; 186 try { 187 bidiLine = bidi.setLine(i, k); 188 errln("For line limits " + i + "-" + k 189 + " got success, while expected failure"); 190 } catch (Exception e) {} 191 192 i = paraBounds[1]; 193 k = paraBounds[2]; 194 try { 195 bidiLine = bidi.setLine(i, k); 196 } catch (Exception e) { 197 errln("For line limits " + i + "-" + k + " got failure"); 198 } 199 200 /* check level of block separator at end of paragraph when orderParagraphsLTR==FALSE */ 201 try { 202 bidi.setPara(src, Bidi.RTL, null); 203 } catch (IllegalArgumentException e) { 204 errln("Bidi.setPara failed, paraLevel = " + Bidi.RTL); 205 } 206 /* get levels through para Bidi block */ 207 try { 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); 213 } 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); 218 } 219 } 220 /* get levels through para Line block */ 221 i = paraBounds[1]; 222 k = paraBounds[2]; 223 try { 224 bidiLine = bidi.setLine(i, k); 225 } catch (Exception e) { 226 errln("For line limits " + i + "-" + k + " got failure"); 227 return; 228 } 229 paraIndex = bidiLine.getParagraphIndex(i); 230 run = bidiLine.getParagraph(i); 231 try { 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); 237 } 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); 247 } 248 orderParagraphsLTR = bidi.isOrderParagraphsLTR(); 249 assertFalse("orderParagraphsLTR is true", orderParagraphsLTR); 250 bidi.orderParagraphsLTR(true); 251 orderParagraphsLTR = bidi.isOrderParagraphsLTR(); 252 assertTrue("orderParagraphsLTR is false", orderParagraphsLTR); 253 254 /* check level of block separator at end of paragraph when orderParagraphsLTR==TRUE */ 255 try { 256 bidi.setPara(src, Bidi.RTL, null); 257 } catch (IllegalArgumentException e) { 258 errln("Bidi.setPara failed, paraLevel = " + Bidi.RTL); 259 } 260 /* get levels through para Bidi block */ 261 try { 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); 267 } 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"); 272 } 273 } 274 /* get levels through para Line block */ 275 i = paraBounds[1]; 276 k = paraBounds[2]; 277 paraStart = run.getStart(); 278 paraLimit = run.getLimit(); 279 try { 280 bidiLine = bidi.setLine(paraStart, paraLimit); 281 } catch (Exception e) { 282 errln("For line limits " + paraStart + "-" + paraLimit + 283 " got failure"); 284 } 285 paraIndex = bidiLine.getParagraphIndex(i); 286 run = bidiLine.getParagraph(i); 287 try { 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); 293 } 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] + " "); 304 } 305 errcont("\n"); 306 } 307 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) 312 */ 313 src = text; /* restore original content */ 314 bidi.orderParagraphsLTR(false); 315 try { 316 bidi.setPara(src, Bidi.LEVEL_DEFAULT_RTL, null); 317 } catch (IllegalArgumentException e) { 318 errln("Bidi.setPara failed, paraLevel = " + Bidi.LEVEL_DEFAULT_RTL); 319 } 320 try { 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); 326 } 327 for (i = 0; i < paraCount; i++) { 328 /* use pLine for individual paragraphs */ 329 paraStart = paraBounds[i]; 330 length = paraBounds[i + 1] - paraStart; 331 try { 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); 336 } 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); 344 } 345 } 346 } 347 348 /* ensure that leading numerics in a paragraph are not treated as arabic 349 numerals because of arabic text in a preceding paragraph 350 */ 351 src = text2; 352 bidi.orderParagraphsLTR(true); 353 try { 354 bidi.setPara(src, Bidi.RTL, null); 355 } catch (IllegalArgumentException e) { 356 errln("Bidi.setPara failed, paraLevel = " + Bidi.RTL); 357 } 358 try { 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); 364 } 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]); 370 } 371 } 372 373 /* check handling of whitespace before end of paragraph separator when 374 * orderParagraphsLTR==TRUE, when last paragraph has, and lacks, a terminating B 375 */ 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 */ 386 try { 387 bidi.setPara(src, gotLevel, null); 388 } catch (IllegalArgumentException e) { 389 errln("Bidi.setPara failed, paraLevel = " + gotLevel); 390 } 391 try { 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); 397 } 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); 405 } 406 } 407 } 408 } 409 } 410 411 /* check default orientation when inverse bidi and paragraph starts 412 * with LTR strong char and ends with RTL strong char, with and without 413 * a terminating B 414 */ 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); 422 423 /* check multiple paragraphs together with explicit levels 424 */ 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()); 431 432 logln("\nExiting TestMultipleParagraphs\n"); 433 434 /* check levels in multiple paragraphs with default para level 435 */ 436 bidi = new Bidi(); 437 bidi.setPara(multiparaTestString, Bidi.LEVEL_DEFAULT_LTR, null); 438 try { 439 gotLevels = bidi.getLevels(); 440 } catch (Exception e) { 441 errln("Error on Bidi.getLevels for multiparaTestString"); 442 return; 443 } 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]); 449 } 450 } 451 } 452 453 454 public static void main(String[] args) { 455 try { 456 new TestMultipleParagraphs().run(args); 457 } 458 catch (Exception e) { 459 System.out.println(e); 460 } 461 } 462 } 463