Home | History | Annotate | Download | only in bidi
      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