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.
5 #include "base/i18n/bidi_line_iterator.h"
7 #include "base/macros.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "testing/gtest/include/gtest/gtest.h"
15 class BiDiLineIteratorTest : public testing::TestWithParam<TextDirection> {
17 BiDiLineIteratorTest() = default;
19 BiDiLineIterator* iterator() { return &iterator_; }
22 BiDiLineIterator iterator_;
24 DISALLOW_COPY_AND_ASSIGN(BiDiLineIteratorTest);
27 TEST_P(BiDiLineIteratorTest, OnlyLTR) {
28 iterator()->Open(UTF8ToUTF16("abc 馃榿 娴嬭瘯"), GetParam(),
29 BiDiLineIterator::CustomBehavior::NONE);
30 ASSERT_EQ(1, iterator()->CountRuns());
33 EXPECT_EQ(UBIDI_LTR, iterator()->GetVisualRun(0, &start, &length));
39 iterator()->GetLogicalRun(0, &end, &level);
41 if (GetParam() == TextDirection::RIGHT_TO_LEFT)
47 TEST_P(BiDiLineIteratorTest, OnlyRTL) {
48 iterator()->Open(UTF8ToUTF16("诪讛 讛砖注讛"), GetParam(),
49 BiDiLineIterator::CustomBehavior::NONE);
50 ASSERT_EQ(1, iterator()->CountRuns());
53 EXPECT_EQ(UBIDI_RTL, iterator()->GetVisualRun(0, &start, &length));
59 iterator()->GetLogicalRun(0, &end, &level);
64 TEST_P(BiDiLineIteratorTest, Mixed) {
65 iterator()->Open(UTF8ToUTF16("讗谞讬 诪砖转诪砖 讘- Chrome 讻讚驻讚驻谉 讛讗讬谞讟专谞讟 砖诇讬"),
66 GetParam(), BiDiLineIterator::CustomBehavior::NONE);
67 ASSERT_EQ(3, iterator()->CountRuns());
69 // We'll get completely different results depending on the top-level paragraph
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.
75 EXPECT_EQ(UBIDI_RTL, iterator()->GetVisualRun(0, &start, &length));
77 EXPECT_EQ(20, length);
78 EXPECT_EQ(UBIDI_LTR, iterator()->GetVisualRun(1, &start, &length));
81 EXPECT_EQ(UBIDI_RTL, iterator()->GetVisualRun(2, &start, &length));
83 EXPECT_EQ(13, length);
87 iterator()->GetLogicalRun(0, &end, &level);
90 iterator()->GetLogicalRun(13, &end, &level);
93 iterator()->GetLogicalRun(19, &end, &level);
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.
100 EXPECT_EQ(UBIDI_RTL, iterator()->GetVisualRun(0, &start, &length));
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);
112 iterator()->GetLogicalRun(0, &end, &level);
115 iterator()->GetLogicalRun(11, &end, &level);
118 iterator()->GetLogicalRun(20, &end, &level);
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);
130 // Expect a single RTL run.
131 ASSERT_EQ(1, iterator()->CountRuns());
134 EXPECT_EQ(UBIDI_RTL, iterator()->GetVisualRun(0, &start, &length));
136 EXPECT_EQ(65, length);
140 iterator()->GetLogicalRun(0, &end, &level);
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);
151 const int kStringSize = 65;
153 // Expect a primary RTL run, broken up by each of the 8 punctuation marks that
154 // are considered strong LTR (17 runs total).
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}, // '@'
170 ASSERT_EQ(arraysize(expected_runs),
171 static_cast<size_t>(iterator()->CountRuns()));
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
177 : expected_runs[i + 1].start;
179 size_t visual_index = GetParam() == TextDirection::RIGHT_TO_LEFT
180 ? arraysize(expected_runs) - 1 - i
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 << ")";
191 expected_run.dir == UBIDI_RTL
193 : (GetParam() == TextDirection::RIGHT_TO_LEFT ? 2 : 0);
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 << ")";
202 INSTANTIATE_TEST_CASE_P(,
203 BiDiLineIteratorTest,
204 ::testing::Values(TextDirection::LEFT_TO_RIGHT,
205 TextDirection::RIGHT_TO_LEFT));