|  | // Copyright 2017 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "base/i18n/bidi_line_iterator.h" | 
|  |  | 
|  | #include "base/macros.h" | 
|  | #include "base/strings/utf_string_conversions.h" | 
|  | #include "testing/gtest/include/gtest/gtest.h" | 
|  |  | 
|  | namespace base { | 
|  | namespace i18n { | 
|  | namespace { | 
|  |  | 
|  | class BiDiLineIteratorTest : public testing::TestWithParam<TextDirection> { | 
|  | public: | 
|  | BiDiLineIteratorTest() = default; | 
|  |  | 
|  | BiDiLineIterator* iterator() { return &iterator_; } | 
|  |  | 
|  | private: | 
|  | BiDiLineIterator iterator_; | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(BiDiLineIteratorTest); | 
|  | }; | 
|  |  | 
|  | TEST_P(BiDiLineIteratorTest, OnlyLTR) { | 
|  | iterator()->Open(UTF8ToUTF16("abc 馃榿 娴嬭瘯"), GetParam(), | 
|  | BiDiLineIterator::CustomBehavior::NONE); | 
|  | ASSERT_EQ(1, iterator()->CountRuns()); | 
|  |  | 
|  | int start, length; | 
|  | EXPECT_EQ(UBIDI_LTR, iterator()->GetVisualRun(0, &start, &length)); | 
|  | EXPECT_EQ(0, start); | 
|  | EXPECT_EQ(9, length); | 
|  |  | 
|  | int end; | 
|  | UBiDiLevel level; | 
|  | iterator()->GetLogicalRun(0, &end, &level); | 
|  | EXPECT_EQ(9, end); | 
|  | if (GetParam() == TextDirection::RIGHT_TO_LEFT) | 
|  | EXPECT_EQ(2, level); | 
|  | else | 
|  | EXPECT_EQ(0, level); | 
|  | } | 
|  |  | 
|  | TEST_P(BiDiLineIteratorTest, OnlyRTL) { | 
|  | iterator()->Open(UTF8ToUTF16("诪讛 讛砖注讛"), GetParam(), | 
|  | BiDiLineIterator::CustomBehavior::NONE); | 
|  | ASSERT_EQ(1, iterator()->CountRuns()); | 
|  |  | 
|  | int start, length; | 
|  | EXPECT_EQ(UBIDI_RTL, iterator()->GetVisualRun(0, &start, &length)); | 
|  | EXPECT_EQ(0, start); | 
|  | EXPECT_EQ(7, length); | 
|  |  | 
|  | int end; | 
|  | UBiDiLevel level; | 
|  | iterator()->GetLogicalRun(0, &end, &level); | 
|  | EXPECT_EQ(7, end); | 
|  | EXPECT_EQ(1, level); | 
|  | } | 
|  |  | 
|  | TEST_P(BiDiLineIteratorTest, Mixed) { | 
|  | iterator()->Open(UTF8ToUTF16("讗谞讬 诪砖转诪砖 讘- Chrome 讻讚驻讚驻谉 讛讗讬谞讟专谞讟 砖诇讬"), | 
|  | GetParam(), BiDiLineIterator::CustomBehavior::NONE); | 
|  | ASSERT_EQ(3, iterator()->CountRuns()); | 
|  |  | 
|  | // We'll get completely different results depending on the top-level paragraph | 
|  | // direction. | 
|  | if (GetParam() == TextDirection::RIGHT_TO_LEFT) { | 
|  | // If para direction is RTL, expect the LTR substring "Chrome" to be nested | 
|  | // within the surrounding RTL text. | 
|  | int start, length; | 
|  | EXPECT_EQ(UBIDI_RTL, iterator()->GetVisualRun(0, &start, &length)); | 
|  | EXPECT_EQ(19, start); | 
|  | EXPECT_EQ(20, length); | 
|  | EXPECT_EQ(UBIDI_LTR, iterator()->GetVisualRun(1, &start, &length)); | 
|  | EXPECT_EQ(13, start); | 
|  | EXPECT_EQ(6, length); | 
|  | EXPECT_EQ(UBIDI_RTL, iterator()->GetVisualRun(2, &start, &length)); | 
|  | EXPECT_EQ(0, start); | 
|  | EXPECT_EQ(13, length); | 
|  |  | 
|  | int end; | 
|  | UBiDiLevel level; | 
|  | iterator()->GetLogicalRun(0, &end, &level); | 
|  | EXPECT_EQ(13, end); | 
|  | EXPECT_EQ(1, level); | 
|  | iterator()->GetLogicalRun(13, &end, &level); | 
|  | EXPECT_EQ(19, end); | 
|  | EXPECT_EQ(2, level); | 
|  | iterator()->GetLogicalRun(19, &end, &level); | 
|  | EXPECT_EQ(39, end); | 
|  | EXPECT_EQ(1, level); | 
|  | } else { | 
|  | // If the para direction is LTR, expect the LTR substring "- Chrome " to be | 
|  | // at the top level, with two nested RTL runs on either side. | 
|  | int start, length; | 
|  | EXPECT_EQ(UBIDI_RTL, iterator()->GetVisualRun(0, &start, &length)); | 
|  | EXPECT_EQ(0, start); | 
|  | EXPECT_EQ(11, length); | 
|  | EXPECT_EQ(UBIDI_LTR, iterator()->GetVisualRun(1, &start, &length)); | 
|  | EXPECT_EQ(11, start); | 
|  | EXPECT_EQ(9, length); | 
|  | EXPECT_EQ(UBIDI_RTL, iterator()->GetVisualRun(2, &start, &length)); | 
|  | EXPECT_EQ(20, start); | 
|  | EXPECT_EQ(19, length); | 
|  |  | 
|  | int end; | 
|  | UBiDiLevel level; | 
|  | iterator()->GetLogicalRun(0, &end, &level); | 
|  | EXPECT_EQ(11, end); | 
|  | EXPECT_EQ(1, level); | 
|  | iterator()->GetLogicalRun(11, &end, &level); | 
|  | EXPECT_EQ(20, end); | 
|  | EXPECT_EQ(0, level); | 
|  | iterator()->GetLogicalRun(20, &end, &level); | 
|  | EXPECT_EQ(39, end); | 
|  | EXPECT_EQ(1, level); | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_P(BiDiLineIteratorTest, RTLPunctuationNoCustomBehavior) { | 
|  | // This string features Hebrew characters interleaved with ASCII punctuation. | 
|  | iterator()->Open(UTF8ToUTF16("讗!讘\"讙#讚$讛%讜&讝'讞(讟)讬*讱+讻,诇-诐.诪/" | 
|  | "谉:谞;住<注=祝>驻?抓@爪[拽\\专]砖^转_讗`讘{讙|讚}讛~讜"), | 
|  | GetParam(), BiDiLineIterator::CustomBehavior::NONE); | 
|  |  | 
|  | // Expect a single RTL run. | 
|  | ASSERT_EQ(1, iterator()->CountRuns()); | 
|  |  | 
|  | int start, length; | 
|  | EXPECT_EQ(UBIDI_RTL, iterator()->GetVisualRun(0, &start, &length)); | 
|  | EXPECT_EQ(0, start); | 
|  | EXPECT_EQ(65, length); | 
|  |  | 
|  | int end; | 
|  | UBiDiLevel level; | 
|  | iterator()->GetLogicalRun(0, &end, &level); | 
|  | EXPECT_EQ(65, end); | 
|  | EXPECT_EQ(1, level); | 
|  | } | 
|  |  | 
|  | TEST_P(BiDiLineIteratorTest, RTLPunctuationAsURL) { | 
|  | // This string features Hebrew characters interleaved with ASCII punctuation. | 
|  | iterator()->Open(UTF8ToUTF16("讗!讘\"讙#讚$讛%讜&讝'讞(讟)讬*讱+讻,诇-诐.诪/" | 
|  | "谉:谞;住<注=祝>驻?抓@爪[拽\\专]砖^转_讗`讘{讙|讚}讛~讜"), | 
|  | GetParam(), BiDiLineIterator::CustomBehavior::AS_URL); | 
|  |  | 
|  | const int kStringSize = 65; | 
|  |  | 
|  | // Expect a primary RTL run, broken up by each of the 8 punctuation marks that | 
|  | // are considered strong LTR (17 runs total). | 
|  | struct { | 
|  | int start; | 
|  | UBiDiDirection dir; | 
|  | } expected_runs[] = { | 
|  | {0, UBIDI_RTL},  {5, UBIDI_LTR},   // '#' | 
|  | {6, UBIDI_RTL},  {11, UBIDI_LTR},  // '&' | 
|  | {12, UBIDI_RTL}, {27, UBIDI_LTR},  // '.' | 
|  | {28, UBIDI_RTL}, {29, UBIDI_LTR},  // '/' | 
|  | {30, UBIDI_RTL}, {31, UBIDI_LTR},  // ':' | 
|  | {32, UBIDI_RTL}, {37, UBIDI_LTR},  // '=' | 
|  | {38, UBIDI_RTL}, {41, UBIDI_LTR},  // '?' | 
|  | {42, UBIDI_RTL}, {43, UBIDI_LTR},  // '@' | 
|  | {44, UBIDI_RTL}, | 
|  | }; | 
|  |  | 
|  | ASSERT_EQ(arraysize(expected_runs), | 
|  | static_cast<size_t>(iterator()->CountRuns())); | 
|  |  | 
|  | for (size_t i = 0; i < arraysize(expected_runs); ++i) { | 
|  | const auto& expected_run = expected_runs[i]; | 
|  | int expected_run_end = i >= arraysize(expected_runs) - 1 | 
|  | ? kStringSize | 
|  | : expected_runs[i + 1].start; | 
|  |  | 
|  | size_t visual_index = GetParam() == TextDirection::RIGHT_TO_LEFT | 
|  | ? arraysize(expected_runs) - 1 - i | 
|  | : i; | 
|  | int start, length; | 
|  | EXPECT_EQ(expected_run.dir, | 
|  | iterator()->GetVisualRun(visual_index, &start, &length)) | 
|  | << "(i = " << i << ")"; | 
|  | EXPECT_EQ(expected_run.start, start) << "(i = " << i << ")"; | 
|  | EXPECT_EQ(expected_run_end - expected_run.start, length) | 
|  | << "(i = " << i << ")"; | 
|  |  | 
|  | int expected_level = | 
|  | expected_run.dir == UBIDI_RTL | 
|  | ? 1 | 
|  | : (GetParam() == TextDirection::RIGHT_TO_LEFT ? 2 : 0); | 
|  | int end; | 
|  | UBiDiLevel level; | 
|  | iterator()->GetLogicalRun(expected_run.start, &end, &level); | 
|  | EXPECT_EQ(expected_run_end, end) << "(i = " << i << ")"; | 
|  | EXPECT_EQ(expected_level, level) << "(i = " << i << ")"; | 
|  | } | 
|  | } | 
|  |  | 
|  | INSTANTIATE_TEST_CASE_P(, | 
|  | BiDiLineIteratorTest, | 
|  | ::testing::Values(TextDirection::LEFT_TO_RIGHT, | 
|  | TextDirection::RIGHT_TO_LEFT)); | 
|  |  | 
|  | }  // namespace | 
|  | }  // namespace i18n | 
|  | }  // namespace base |