Home | History | Annotate | Download | only in cts
      1 /*
      2  * Copyright (C) 2013 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.text.cts;
     18 
     19 import static org.junit.Assert.assertEquals;
     20 import static org.junit.Assert.assertFalse;
     21 import static org.junit.Assert.assertNull;
     22 import static org.junit.Assert.assertTrue;
     23 
     24 import android.icu.util.ULocale;
     25 import android.support.test.filters.SmallTest;
     26 import android.support.test.runner.AndroidJUnit4;
     27 import android.text.BidiFormatter;
     28 import android.text.SpannableString;
     29 import android.text.Spanned;
     30 import android.text.TextDirectionHeuristics;
     31 import android.text.style.RelativeSizeSpan;
     32 
     33 import org.junit.Test;
     34 import org.junit.runner.RunWith;
     35 
     36 import java.util.Locale;
     37 
     38 @SmallTest
     39 @RunWith(AndroidJUnit4.class)
     40 public class BidiFormatterTest {
     41 
     42     private static final BidiFormatter LTR_FMT = BidiFormatter.getInstance(false /* LTR context */);
     43     private static final BidiFormatter RTL_FMT = BidiFormatter.getInstance(true /* RTL context */);
     44 
     45     private static final BidiFormatter LTR_FMT_EXIT_RESET =
     46             new BidiFormatter.Builder(false /* LTR context */).stereoReset(false).build();
     47     private static final BidiFormatter RTL_FMT_EXIT_RESET =
     48             new BidiFormatter.Builder(true /* RTL context */).stereoReset(false).build();
     49 
     50     private static final String EN = "abba";
     51     private static final String HE = "\u05E0\u05E1";
     52 
     53     private static final String LRM = "\u200E";
     54     private static final String RLM = "\u200F";
     55     private static final String LRE = "\u202A";
     56     private static final String RLE = "\u202B";
     57     private static final String PDF = "\u202C";
     58 
     59     @Test
     60     public void testIsRtlContext() {
     61         assertEquals(false, LTR_FMT.isRtlContext());
     62         assertEquals(true, RTL_FMT.isRtlContext());
     63 
     64         assertEquals(false, BidiFormatter.getInstance(Locale.ENGLISH).isRtlContext());
     65         assertEquals(true, BidiFormatter.getInstance(true).isRtlContext());
     66     }
     67 
     68     @Test
     69     public void testCachedInstances() {
     70         // Test that we get the same cached static instances for simple cases
     71         BidiFormatter defaultFormatterInstance = BidiFormatter.getInstance();
     72         assertTrue(defaultFormatterInstance == LTR_FMT || defaultFormatterInstance == RTL_FMT);
     73 
     74         assertEquals(LTR_FMT, BidiFormatter.getInstance(false));
     75         assertEquals(RTL_FMT, BidiFormatter.getInstance(true));
     76 
     77         assertEquals(LTR_FMT, BidiFormatter.getInstance(false));
     78         assertEquals(RTL_FMT, BidiFormatter.getInstance(Locale.forLanguageTag("ar")));
     79     }
     80 
     81     @Test
     82     public void testBuilderIsRtlContext() {
     83         assertEquals(false, new BidiFormatter.Builder(false).build().isRtlContext());
     84         assertEquals(true, new BidiFormatter.Builder(true).build().isRtlContext());
     85     }
     86 
     87     @Test
     88     public void testIsRtl() {
     89         assertEquals(true, BidiFormatter.getInstance(true).isRtl(HE));
     90         assertEquals(true, BidiFormatter.getInstance(false).isRtl(HE));
     91 
     92         assertEquals(false, BidiFormatter.getInstance(true).isRtl(EN));
     93         assertEquals(false, BidiFormatter.getInstance(false).isRtl(EN));
     94     }
     95 
     96     @Test
     97     public void testUnicodeWrap() {
     98         // Make sure an input of null doesn't crash anything.
     99         assertNull(LTR_FMT.unicodeWrap(null));
    100 
    101         // Uniform directionality in opposite context.
    102         assertEquals("uniform dir opposite to LTR context",
    103                 RLE + "." + HE + "." + PDF + LRM,
    104                 LTR_FMT_EXIT_RESET.unicodeWrap("." + HE + "."));
    105         assertEquals("uniform dir opposite to LTR context, stereo reset",
    106                 LRM + RLE + "." + HE + "." + PDF + LRM,
    107                 LTR_FMT.unicodeWrap("." + HE + "."));
    108         assertEquals("uniform dir opposite to LTR context, stereo reset, no isolation",
    109                 RLE + "." + HE + "." + PDF,
    110                 LTR_FMT.unicodeWrap("." + HE + ".", false));
    111         assertEquals("neutral treated as opposite to LTR context",
    112                 RLE + "." + PDF + LRM,
    113                 LTR_FMT_EXIT_RESET.unicodeWrap(".", TextDirectionHeuristics.RTL));
    114         assertEquals("uniform dir opposite to RTL context",
    115                 LRE + "." + EN + "." + PDF + RLM,
    116                 RTL_FMT_EXIT_RESET.unicodeWrap("." + EN + "."));
    117         assertEquals("uniform dir opposite to RTL context, stereo reset",
    118                 RLM + LRE + "." + EN + "." + PDF + RLM,
    119                 RTL_FMT.unicodeWrap("." + EN + "."));
    120         assertEquals("uniform dir opposite to RTL context, stereo reset, no isolation",
    121                 LRE + "." + EN + "." + PDF,
    122                 RTL_FMT.unicodeWrap("." + EN + ".", false));
    123         assertEquals("neutral treated as opposite to RTL context",
    124                 LRE + "." + PDF + RLM,
    125                 RTL_FMT_EXIT_RESET.unicodeWrap(".", TextDirectionHeuristics.LTR));
    126 
    127         // We test mixed-directionality cases only with an explicit overall directionality parameter
    128         // because the estimation logic is outside the sphere of BidiFormatter, and different
    129         // estimators will treat them differently.
    130 
    131         // Overall directionality matching context, but with opposite exit directionality.
    132         assertEquals("exit dir opposite to LTR context",
    133                 EN + HE + LRM,
    134                 LTR_FMT_EXIT_RESET.unicodeWrap(EN + HE, TextDirectionHeuristics.LTR));
    135         assertEquals("exit dir opposite to LTR context, stereo reset",
    136                 EN + HE + LRM,
    137                 LTR_FMT.unicodeWrap(EN + HE, TextDirectionHeuristics.LTR));
    138         assertEquals("exit dir opposite to LTR context, stereo reset, no isolation",
    139                 EN + HE,
    140                 LTR_FMT.unicodeWrap(EN + HE, TextDirectionHeuristics.LTR, false));
    141 
    142         assertEquals("exit dir opposite to RTL context",
    143                 HE + EN + RLM,
    144                 RTL_FMT_EXIT_RESET.unicodeWrap(HE + EN, TextDirectionHeuristics.RTL));
    145         assertEquals("exit dir opposite to RTL context, stereo reset",
    146                 HE + EN + RLM,
    147                 RTL_FMT.unicodeWrap(HE + EN, TextDirectionHeuristics.RTL));
    148         assertEquals("exit dir opposite to RTL context, stereo reset, no isolation",
    149                 HE + EN,
    150                 RTL_FMT.unicodeWrap(HE + EN, TextDirectionHeuristics.RTL, false));
    151 
    152         // Overall directionality matching context, but with opposite entry directionality.
    153         assertEquals("entry dir opposite to LTR context",
    154                 HE + EN,
    155                 LTR_FMT_EXIT_RESET.unicodeWrap(HE + EN, TextDirectionHeuristics.LTR));
    156         assertEquals("entry dir opposite to LTR context, stereo reset",
    157                 LRM + HE + EN,
    158                 LTR_FMT.unicodeWrap(HE + EN, TextDirectionHeuristics.LTR));
    159         assertEquals("entry dir opposite to LTR context, stereo reset, no isolation",
    160                 HE + EN,
    161                 LTR_FMT.unicodeWrap(HE + EN, TextDirectionHeuristics.LTR, false));
    162 
    163         assertEquals("entry dir opposite to RTL context",
    164                 EN + HE,
    165                 RTL_FMT_EXIT_RESET.unicodeWrap(EN + HE, TextDirectionHeuristics.RTL));
    166         assertEquals("entry dir opposite to RTL context, stereo reset",
    167                 RLM + EN + HE,
    168                 RTL_FMT.unicodeWrap(EN + HE, TextDirectionHeuristics.RTL));
    169         assertEquals("entry dir opposite to RTL context, stereo reset, no isolation",
    170                 EN + HE,
    171                 RTL_FMT.unicodeWrap(EN + HE, TextDirectionHeuristics.RTL, false));
    172 
    173         // Overall directionality matching context, but with opposite entry and exit directionality.
    174         assertEquals("entry and exit dir opposite to LTR context",
    175                 HE + EN + HE + LRM,
    176                 LTR_FMT_EXIT_RESET.unicodeWrap(HE + EN + HE, TextDirectionHeuristics.LTR));
    177         assertEquals("entry and exit dir opposite to LTR context, stereo reset",
    178                 LRM + HE + EN + HE + LRM,
    179                 LTR_FMT.unicodeWrap(HE + EN + HE, TextDirectionHeuristics.LTR));
    180         assertEquals("entry and exit dir opposite to LTR context, no isolation",
    181                 HE + EN + HE,
    182                 LTR_FMT_EXIT_RESET.unicodeWrap(HE + EN + HE, TextDirectionHeuristics.LTR, false));
    183 
    184         assertEquals("entry and exit dir opposite to RTL context",
    185                 EN + HE + EN + RLM,
    186                 RTL_FMT_EXIT_RESET.unicodeWrap(EN + HE + EN, TextDirectionHeuristics.RTL));
    187         assertEquals("entry and exit dir opposite to RTL context, no isolation",
    188                 EN + HE + EN,
    189                 RTL_FMT_EXIT_RESET.unicodeWrap(EN + HE + EN, TextDirectionHeuristics.RTL, false));
    190 
    191         // Entry and exit directionality matching context, but with opposite overall directionality.
    192         assertEquals("overall dir (but not entry or exit dir) opposite to LTR context",
    193                 RLE + EN + HE + EN + PDF + LRM,
    194                 LTR_FMT_EXIT_RESET.unicodeWrap(EN + HE + EN, TextDirectionHeuristics.RTL));
    195         assertEquals("overall dir (but not entry or exit dir) opposite to LTR context, stereo reset",
    196                 LRM + RLE + EN + HE + EN + PDF + LRM,
    197                 LTR_FMT.unicodeWrap(EN + HE + EN, TextDirectionHeuristics.RTL));
    198         assertEquals("overall dir (but not entry or exit dir) opposite to LTR context, no isolation",
    199                 RLE + EN + HE + EN + PDF,
    200                 LTR_FMT_EXIT_RESET.unicodeWrap(EN + HE + EN, TextDirectionHeuristics.RTL, false));
    201 
    202         assertEquals("overall dir (but not entry or exit dir) opposite to RTL context",
    203                 LRE + HE + EN + HE + PDF + RLM,
    204                 RTL_FMT_EXIT_RESET.unicodeWrap(HE + EN + HE, TextDirectionHeuristics.LTR));
    205         assertEquals("overall dir (but not entry or exit dir) opposite to RTL context, stereo reset",
    206                 RLM + LRE + HE + EN + HE + PDF + RLM,
    207                 RTL_FMT.unicodeWrap(HE + EN + HE, TextDirectionHeuristics.LTR));
    208         assertEquals("overall dir (but not entry or exit dir) opposite to RTL context, no isolation",
    209                 LRE + HE + EN + HE + PDF,
    210                 RTL_FMT_EXIT_RESET.unicodeWrap(HE + EN + HE, TextDirectionHeuristics.LTR, false));
    211     }
    212 
    213     @Test
    214     public void testGetStereoReset() {
    215         assertTrue(LTR_FMT.getStereoReset());
    216         assertTrue(RTL_FMT.getStereoReset());
    217         assertFalse(LTR_FMT_EXIT_RESET.getStereoReset());
    218         assertFalse(RTL_FMT_EXIT_RESET.getStereoReset());
    219     }
    220 
    221     @Test
    222     public void testBuilder_construction() {
    223         final BidiFormatter defaultFmt = new BidiFormatter.Builder().build();
    224         // Test that the default locale and the BidiFormatter's locale have the same direction.
    225         assertEquals(ULocale.getDefault().isRightToLeft(), defaultFmt.isRtlContext());
    226 
    227         final BidiFormatter ltrFmt = new BidiFormatter.Builder(false).build();
    228         assertFalse(ltrFmt.isRtlContext());
    229 
    230         final BidiFormatter rtlFmt = new BidiFormatter.Builder(true).build();
    231         assertTrue(rtlFmt.isRtlContext());
    232 
    233         final BidiFormatter englishFmt = new BidiFormatter.Builder(Locale.ENGLISH).build();
    234         assertFalse(englishFmt.isRtlContext());
    235 
    236         final BidiFormatter arabicFmt =
    237                 new BidiFormatter.Builder(Locale.forLanguageTag("ar")).build();
    238         assertTrue(arabicFmt.isRtlContext());
    239     }
    240 
    241     @Test
    242     public void testBuilder_setTextDirectionHeuristic() {
    243         final BidiFormatter defaultFmt = new BidiFormatter.Builder().build();
    244         assertFalse(defaultFmt.isRtl(EN + HE + EN));
    245 
    246         final BidiFormatter modifiedFmt = new BidiFormatter.Builder().setTextDirectionHeuristic(
    247                 TextDirectionHeuristics.ANYRTL_LTR).build();
    248         assertTrue(modifiedFmt.isRtl(EN + HE + EN));
    249     }
    250 
    251     @Test
    252     public void testCharSequenceApis() {
    253         final CharSequence CS_HE = new SpannableString(HE);
    254         assertEquals(true, BidiFormatter.getInstance(true).isRtl(CS_HE));
    255 
    256         final SpannableString CS_EN_HE = new SpannableString(EN + HE);
    257         final Object RELATIVE_SIZE_SPAN = new RelativeSizeSpan(1.2f);
    258         CS_EN_HE.setSpan(RELATIVE_SIZE_SPAN, 0, EN.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
    259 
    260         Spanned wrapped;
    261         Object[] spans;
    262 
    263         wrapped = (Spanned) LTR_FMT.unicodeWrap(CS_EN_HE);
    264         assertEquals(EN + HE + LRM, wrapped.toString());
    265         spans = wrapped.getSpans(0, wrapped.length(), Object.class);
    266         assertEquals(1, spans.length);
    267         assertEquals(RELATIVE_SIZE_SPAN, spans[0]);
    268         assertEquals(0, wrapped.getSpanStart(RELATIVE_SIZE_SPAN));
    269         assertEquals(EN.length(), wrapped.getSpanEnd(RELATIVE_SIZE_SPAN));
    270 
    271         wrapped = (Spanned) LTR_FMT.unicodeWrap(CS_EN_HE, TextDirectionHeuristics.LTR);
    272         assertEquals(EN + HE + LRM, wrapped.toString());
    273         spans = wrapped.getSpans(0, wrapped.length(), Object.class);
    274         assertEquals(1, spans.length);
    275         assertEquals(RELATIVE_SIZE_SPAN, spans[0]);
    276         assertEquals(0, wrapped.getSpanStart(RELATIVE_SIZE_SPAN));
    277         assertEquals(EN.length(), wrapped.getSpanEnd(RELATIVE_SIZE_SPAN));
    278 
    279         wrapped = (Spanned) LTR_FMT.unicodeWrap(CS_EN_HE, false);
    280         assertEquals(EN + HE, wrapped.toString());
    281         spans = wrapped.getSpans(0, wrapped.length(), Object.class);
    282         assertEquals(1, spans.length);
    283         assertEquals(RELATIVE_SIZE_SPAN, spans[0]);
    284         assertEquals(0, wrapped.getSpanStart(RELATIVE_SIZE_SPAN));
    285         assertEquals(EN.length(), wrapped.getSpanEnd(RELATIVE_SIZE_SPAN));
    286 
    287         wrapped = (Spanned) LTR_FMT.unicodeWrap(CS_EN_HE, TextDirectionHeuristics.LTR, false);
    288         assertEquals(EN + HE, wrapped.toString());
    289         spans = wrapped.getSpans(0, wrapped.length(), Object.class);
    290         assertEquals(1, spans.length);
    291         assertEquals(RELATIVE_SIZE_SPAN, spans[0]);
    292         assertEquals(0, wrapped.getSpanStart(RELATIVE_SIZE_SPAN));
    293         assertEquals(EN.length(), wrapped.getSpanEnd(RELATIVE_SIZE_SPAN));
    294     }
    295 }
    296