// 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 { 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(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