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
17package android.support.v4.text;
18
19import android.test.AndroidTestCase;
20
21import java.util.Locale;
22
23/** @hide */
24public class BidiFormatterTest extends AndroidTestCase {
25
26    private static final BidiFormatter LTR_FMT = BidiFormatter.getInstance(false /* LTR context */);
27    private static final BidiFormatter RTL_FMT = BidiFormatter.getInstance(true /* RTL context */);
28
29    private static final BidiFormatter LTR_FMT_EXIT_RESET =
30            new BidiFormatter.Builder(false /* LTR context */).stereoReset(false).build();
31    private static final BidiFormatter RTL_FMT_EXIT_RESET =
32            new BidiFormatter.Builder(true /* RTL context */).stereoReset(false).build();
33
34    private static final String EN = "abba";
35    private static final String HE = "\u05e0\u05e1";
36
37    private static final String LRM = "\u200E";
38    private static final String RLM = "\u200F";
39    private static final String LRE = "\u202A";
40    private static final String RLE = "\u202B";
41    private static final String PDF = "\u202C";
42
43    public void testIsRtlContext() {
44        assertEquals(false, LTR_FMT.isRtlContext());
45        assertEquals(true, RTL_FMT.isRtlContext());
46
47        assertEquals(false, BidiFormatter.getInstance(Locale.ENGLISH).isRtlContext());
48        assertEquals(true, BidiFormatter.getInstance(true).isRtlContext());
49    }
50
51    public void testBuilderIsRtlContext() {
52        assertEquals(false, new BidiFormatter.Builder(false).build().isRtlContext());
53        assertEquals(true, new BidiFormatter.Builder(true).build().isRtlContext());
54    }
55
56    public void testIsRtl() {
57        assertEquals(true, BidiFormatter.getInstance(true).isRtl(HE));
58        assertEquals(true, BidiFormatter.getInstance(false).isRtl(HE));
59
60        assertEquals(false, BidiFormatter.getInstance(true).isRtl(EN));
61        assertEquals(false, BidiFormatter.getInstance(false).isRtl(EN));
62    }
63
64    public void testUnicodeWrap() {
65        // Uniform directionality in opposite context.
66        assertEquals("uniform dir opposite to LTR context",
67                RLE + "." + HE + "." + PDF + LRM,
68                LTR_FMT_EXIT_RESET.unicodeWrap("." + HE + "."));
69        assertEquals("uniform dir opposite to LTR context, stereo reset",
70                LRM + RLE + "." + HE + "." + PDF + LRM,
71                LTR_FMT.unicodeWrap("." + HE + "."));
72        assertEquals("uniform dir opposite to LTR context, stereo reset, no isolation",
73                RLE + "." + HE + "." + PDF,
74                LTR_FMT.unicodeWrap("." + HE + ".", false));
75        assertEquals("neutral treated as opposite to LTR context",
76                RLE + "." + PDF + LRM,
77                LTR_FMT_EXIT_RESET.unicodeWrap(".", TextDirectionHeuristicsCompat.RTL));
78        assertEquals("uniform dir opposite to RTL context",
79                LRE + "." + EN + "." + PDF + RLM,
80                RTL_FMT_EXIT_RESET.unicodeWrap("." + EN + "."));
81        assertEquals("uniform dir opposite to RTL context, stereo reset",
82                RLM + LRE + "." + EN + "." + PDF + RLM,
83                RTL_FMT.unicodeWrap("." + EN + "."));
84        assertEquals("uniform dir opposite to RTL context, stereo reset, no isolation",
85                LRE + "." + EN + "." + PDF,
86                RTL_FMT.unicodeWrap("." + EN + ".", false));
87        assertEquals("neutral treated as opposite to RTL context",
88                LRE + "." + PDF + RLM,
89                RTL_FMT_EXIT_RESET.unicodeWrap(".", TextDirectionHeuristicsCompat.LTR));
90
91        // We test mixed-directionality cases only with an explicit overall directionality parameter
92        // because the estimation logic is outside the sphere of BidiFormatter, and different
93        // estimators will treat them differently.
94
95        // Overall directionality matching context, but with opposite exit directionality.
96        assertEquals("exit dir opposite to LTR context",
97                EN + HE + LRM,
98                LTR_FMT_EXIT_RESET.unicodeWrap(EN + HE, TextDirectionHeuristicsCompat.LTR));
99        assertEquals("exit dir opposite to LTR context, stereo reset",
100                EN + HE + LRM,
101                LTR_FMT.unicodeWrap(EN + HE, TextDirectionHeuristicsCompat.LTR));
102        assertEquals("exit dir opposite to LTR context, stereo reset, no isolation",
103                EN + HE,
104                LTR_FMT.unicodeWrap(EN + HE, TextDirectionHeuristicsCompat.LTR, false));
105
106        assertEquals("exit dir opposite to RTL context",
107                HE + EN + RLM,
108                RTL_FMT_EXIT_RESET.unicodeWrap(HE + EN, TextDirectionHeuristicsCompat.RTL));
109        assertEquals("exit dir opposite to RTL context, stereo reset",
110                HE + EN + RLM,
111                RTL_FMT.unicodeWrap(HE + EN, TextDirectionHeuristicsCompat.RTL));
112        assertEquals("exit dir opposite to RTL context, stereo reset, no isolation",
113                HE + EN,
114                RTL_FMT.unicodeWrap(HE + EN, TextDirectionHeuristicsCompat.RTL, false));
115
116        // Overall directionality matching context, but with opposite entry directionality.
117        assertEquals("entry dir opposite to LTR context",
118                HE + EN,
119                LTR_FMT_EXIT_RESET.unicodeWrap(HE + EN, TextDirectionHeuristicsCompat.LTR));
120        assertEquals("entry dir opposite to LTR context, stereo reset",
121                LRM + HE + EN,
122                LTR_FMT.unicodeWrap(HE + EN, TextDirectionHeuristicsCompat.LTR));
123        assertEquals("entry dir opposite to LTR context, stereo reset, no isolation",
124                HE + EN,
125                LTR_FMT.unicodeWrap(HE + EN, TextDirectionHeuristicsCompat.LTR, false));
126
127        assertEquals("entry dir opposite to RTL context",
128                EN + HE,
129                RTL_FMT_EXIT_RESET.unicodeWrap(EN + HE, TextDirectionHeuristicsCompat.RTL));
130        assertEquals("entry dir opposite to RTL context, stereo reset",
131                RLM + EN + HE,
132                RTL_FMT.unicodeWrap(EN + HE, TextDirectionHeuristicsCompat.RTL));
133        assertEquals("entry dir opposite to RTL context, stereo reset, no isolation",
134                EN + HE,
135                RTL_FMT.unicodeWrap(EN + HE, TextDirectionHeuristicsCompat.RTL, false));
136
137        // Overall directionality matching context, but with opposite entry and exit directionality.
138        assertEquals("entry and exit dir opposite to LTR context",
139                HE + EN + HE + LRM,
140                LTR_FMT_EXIT_RESET.unicodeWrap(HE + EN + HE, TextDirectionHeuristicsCompat.LTR));
141        assertEquals("entry and exit dir opposite to LTR context, stereo reset",
142                LRM + HE + EN + HE + LRM,
143                LTR_FMT.unicodeWrap(HE + EN + HE, TextDirectionHeuristicsCompat.LTR));
144        assertEquals("entry and exit dir opposite to LTR context, no isolation",
145                HE + EN + HE,
146                LTR_FMT_EXIT_RESET.unicodeWrap(HE + EN + HE, TextDirectionHeuristicsCompat.LTR, false));
147
148        assertEquals("entry and exit dir opposite to RTL context",
149                EN + HE + EN + RLM,
150                RTL_FMT_EXIT_RESET.unicodeWrap(EN + HE + EN, TextDirectionHeuristicsCompat.RTL));
151        assertEquals("entry and exit dir opposite to RTL context, no isolation",
152                EN + HE + EN,
153                RTL_FMT_EXIT_RESET.unicodeWrap(EN + HE + EN, TextDirectionHeuristicsCompat.RTL, false));
154
155        // Entry and exit directionality matching context, but with opposite overall directionality.
156        assertEquals("overall dir (but not entry or exit dir) opposite to LTR context",
157                RLE + EN + HE + EN + PDF + LRM,
158                LTR_FMT_EXIT_RESET.unicodeWrap(EN + HE + EN, TextDirectionHeuristicsCompat.RTL));
159        assertEquals("overall dir (but not entry or exit dir) opposite to LTR context, stereo reset",
160                LRM + RLE + EN + HE + EN + PDF + LRM,
161                LTR_FMT.unicodeWrap(EN + HE + EN, TextDirectionHeuristicsCompat.RTL));
162        assertEquals("overall dir (but not entry or exit dir) opposite to LTR context, no isolation",
163                RLE + EN + HE + EN + PDF,
164                LTR_FMT_EXIT_RESET.unicodeWrap(EN + HE + EN, TextDirectionHeuristicsCompat.RTL, false));
165
166        assertEquals("overall dir (but not entry or exit dir) opposite to RTL context",
167                LRE + HE + EN + HE + PDF + RLM,
168                RTL_FMT_EXIT_RESET.unicodeWrap(HE + EN + HE, TextDirectionHeuristicsCompat.LTR));
169        assertEquals("overall dir (but not entry or exit dir) opposite to RTL context, stereo reset",
170                RLM + LRE + HE + EN + HE + PDF + RLM,
171                RTL_FMT.unicodeWrap(HE + EN + HE, TextDirectionHeuristicsCompat.LTR));
172        assertEquals("overall dir (but not entry or exit dir) opposite to RTL context, no isolation",
173                LRE + HE + EN + HE + PDF,
174                RTL_FMT_EXIT_RESET.unicodeWrap(HE + EN + HE, TextDirectionHeuristicsCompat.LTR, false));
175    }
176}
177