• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "base/i18n/bidi_line_iterator.h"
6 
7 #include "base/macros.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "testing/gtest/include/gtest/gtest.h"
10 
11 namespace base {
12 namespace i18n {
13 namespace {
14 
15 class BiDiLineIteratorTest : public testing::TestWithParam<TextDirection> {
16  public:
17   BiDiLineIteratorTest() = default;
18 
iterator()19   BiDiLineIterator* iterator() { return &iterator_; }
20 
21  private:
22   BiDiLineIterator iterator_;
23 
24   DISALLOW_COPY_AND_ASSIGN(BiDiLineIteratorTest);
25 };
26 
TEST_P(BiDiLineIteratorTest,OnlyLTR)27 TEST_P(BiDiLineIteratorTest, OnlyLTR) {
28   iterator()->Open(UTF8ToUTF16("abc �� 测试"), GetParam(),
29                    BiDiLineIterator::CustomBehavior::NONE);
30   ASSERT_EQ(1, iterator()->CountRuns());
31 
32   int start, length;
33   EXPECT_EQ(UBIDI_LTR, iterator()->GetVisualRun(0, &start, &length));
34   EXPECT_EQ(0, start);
35   EXPECT_EQ(9, length);
36 
37   int end;
38   UBiDiLevel level;
39   iterator()->GetLogicalRun(0, &end, &level);
40   EXPECT_EQ(9, end);
41   if (GetParam() == TextDirection::RIGHT_TO_LEFT)
42     EXPECT_EQ(2, level);
43   else
44     EXPECT_EQ(0, level);
45 }
46 
TEST_P(BiDiLineIteratorTest,OnlyRTL)47 TEST_P(BiDiLineIteratorTest, OnlyRTL) {
48   iterator()->Open(UTF8ToUTF16("מה השעה"), GetParam(),
49                    BiDiLineIterator::CustomBehavior::NONE);
50   ASSERT_EQ(1, iterator()->CountRuns());
51 
52   int start, length;
53   EXPECT_EQ(UBIDI_RTL, iterator()->GetVisualRun(0, &start, &length));
54   EXPECT_EQ(0, start);
55   EXPECT_EQ(7, length);
56 
57   int end;
58   UBiDiLevel level;
59   iterator()->GetLogicalRun(0, &end, &level);
60   EXPECT_EQ(7, end);
61   EXPECT_EQ(1, level);
62 }
63 
TEST_P(BiDiLineIteratorTest,Mixed)64 TEST_P(BiDiLineIteratorTest, Mixed) {
65   iterator()->Open(UTF8ToUTF16("אני משתמש ב- Chrome כדפדפן האינטרנט שלי"),
66                    GetParam(), BiDiLineIterator::CustomBehavior::NONE);
67   ASSERT_EQ(3, iterator()->CountRuns());
68 
69   // We'll get completely different results depending on the top-level paragraph
70   // direction.
71   if (GetParam() == TextDirection::RIGHT_TO_LEFT) {
72     // If para direction is RTL, expect the LTR substring "Chrome" to be nested
73     // within the surrounding RTL text.
74     int start, length;
75     EXPECT_EQ(UBIDI_RTL, iterator()->GetVisualRun(0, &start, &length));
76     EXPECT_EQ(19, start);
77     EXPECT_EQ(20, length);
78     EXPECT_EQ(UBIDI_LTR, iterator()->GetVisualRun(1, &start, &length));
79     EXPECT_EQ(13, start);
80     EXPECT_EQ(6, length);
81     EXPECT_EQ(UBIDI_RTL, iterator()->GetVisualRun(2, &start, &length));
82     EXPECT_EQ(0, start);
83     EXPECT_EQ(13, length);
84 
85     int end;
86     UBiDiLevel level;
87     iterator()->GetLogicalRun(0, &end, &level);
88     EXPECT_EQ(13, end);
89     EXPECT_EQ(1, level);
90     iterator()->GetLogicalRun(13, &end, &level);
91     EXPECT_EQ(19, end);
92     EXPECT_EQ(2, level);
93     iterator()->GetLogicalRun(19, &end, &level);
94     EXPECT_EQ(39, end);
95     EXPECT_EQ(1, level);
96   } else {
97     // If the para direction is LTR, expect the LTR substring "- Chrome " to be
98     // at the top level, with two nested RTL runs on either side.
99     int start, length;
100     EXPECT_EQ(UBIDI_RTL, iterator()->GetVisualRun(0, &start, &length));
101     EXPECT_EQ(0, start);
102     EXPECT_EQ(11, length);
103     EXPECT_EQ(UBIDI_LTR, iterator()->GetVisualRun(1, &start, &length));
104     EXPECT_EQ(11, start);
105     EXPECT_EQ(9, length);
106     EXPECT_EQ(UBIDI_RTL, iterator()->GetVisualRun(2, &start, &length));
107     EXPECT_EQ(20, start);
108     EXPECT_EQ(19, length);
109 
110     int end;
111     UBiDiLevel level;
112     iterator()->GetLogicalRun(0, &end, &level);
113     EXPECT_EQ(11, end);
114     EXPECT_EQ(1, level);
115     iterator()->GetLogicalRun(11, &end, &level);
116     EXPECT_EQ(20, end);
117     EXPECT_EQ(0, level);
118     iterator()->GetLogicalRun(20, &end, &level);
119     EXPECT_EQ(39, end);
120     EXPECT_EQ(1, level);
121   }
122 }
123 
TEST_P(BiDiLineIteratorTest,RTLPunctuationNoCustomBehavior)124 TEST_P(BiDiLineIteratorTest, RTLPunctuationNoCustomBehavior) {
125   // This string features Hebrew characters interleaved with ASCII punctuation.
126   iterator()->Open(UTF8ToUTF16("א!ב\"ג#ד$ה%ו&ז'ח(ט)י*ך+כ,ל-ם.מ/"
127                                "ן:נ;ס<ע=ף>פ?ץ@צ[ק\\ר]ש^ת_א`ב{ג|ד}ה~ו"),
128                    GetParam(), BiDiLineIterator::CustomBehavior::NONE);
129 
130   // Expect a single RTL run.
131   ASSERT_EQ(1, iterator()->CountRuns());
132 
133   int start, length;
134   EXPECT_EQ(UBIDI_RTL, iterator()->GetVisualRun(0, &start, &length));
135   EXPECT_EQ(0, start);
136   EXPECT_EQ(65, length);
137 
138   int end;
139   UBiDiLevel level;
140   iterator()->GetLogicalRun(0, &end, &level);
141   EXPECT_EQ(65, end);
142   EXPECT_EQ(1, level);
143 }
144 
TEST_P(BiDiLineIteratorTest,RTLPunctuationAsURL)145 TEST_P(BiDiLineIteratorTest, RTLPunctuationAsURL) {
146   // This string features Hebrew characters interleaved with ASCII punctuation.
147   iterator()->Open(UTF8ToUTF16("א!ב\"ג#ד$ה%ו&ז'ח(ט)י*ך+כ,ל-ם.מ/"
148                                "ן:נ;ס<ע=ף>פ?ץ@צ[ק\\ר]ש^ת_א`ב{ג|ד}ה~ו"),
149                    GetParam(), BiDiLineIterator::CustomBehavior::AS_URL);
150 
151   const int kStringSize = 65;
152 
153   // Expect a primary RTL run, broken up by each of the 8 punctuation marks that
154   // are considered strong LTR (17 runs total).
155   struct {
156     int start;
157     UBiDiDirection dir;
158   } expected_runs[] = {
159       {0, UBIDI_RTL},  {5, UBIDI_LTR},   // '#'
160       {6, UBIDI_RTL},  {11, UBIDI_LTR},  // '&'
161       {12, UBIDI_RTL}, {27, UBIDI_LTR},  // '.'
162       {28, UBIDI_RTL}, {29, UBIDI_LTR},  // '/'
163       {30, UBIDI_RTL}, {31, UBIDI_LTR},  // ':'
164       {32, UBIDI_RTL}, {37, UBIDI_LTR},  // '='
165       {38, UBIDI_RTL}, {41, UBIDI_LTR},  // '?'
166       {42, UBIDI_RTL}, {43, UBIDI_LTR},  // '@'
167       {44, UBIDI_RTL},
168   };
169 
170   ASSERT_EQ(arraysize(expected_runs),
171             static_cast<size_t>(iterator()->CountRuns()));
172 
173   for (size_t i = 0; i < arraysize(expected_runs); ++i) {
174     const auto& expected_run = expected_runs[i];
175     int expected_run_end = i >= arraysize(expected_runs) - 1
176                                ? kStringSize
177                                : expected_runs[i + 1].start;
178 
179     size_t visual_index = GetParam() == TextDirection::RIGHT_TO_LEFT
180                               ? arraysize(expected_runs) - 1 - i
181                               : i;
182     int start, length;
183     EXPECT_EQ(expected_run.dir,
184               iterator()->GetVisualRun(visual_index, &start, &length))
185         << "(i = " << i << ")";
186     EXPECT_EQ(expected_run.start, start) << "(i = " << i << ")";
187     EXPECT_EQ(expected_run_end - expected_run.start, length)
188         << "(i = " << i << ")";
189 
190     int expected_level =
191         expected_run.dir == UBIDI_RTL
192             ? 1
193             : (GetParam() == TextDirection::RIGHT_TO_LEFT ? 2 : 0);
194     int end;
195     UBiDiLevel level;
196     iterator()->GetLogicalRun(expected_run.start, &end, &level);
197     EXPECT_EQ(expected_run_end, end) << "(i = " << i << ")";
198     EXPECT_EQ(expected_level, level) << "(i = " << i << ")";
199   }
200 }
201 
202 INSTANTIATE_TEST_CASE_P(,
203                         BiDiLineIteratorTest,
204                         ::testing::Values(TextDirection::LEFT_TO_RIGHT,
205                                           TextDirection::RIGHT_TO_LEFT));
206 
207 }  // namespace
208 }  // namespace i18n
209 }  // namespace base
210