1 // Copyright (c) 2006-2008 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/rtl.h" 6 7 #include <algorithm> 8 9 #include "base/file_path.h" 10 #include "base/string_util.h" 11 #include "base/utf_string_conversions.h" 12 #include "base/sys_string_conversions.h" 13 #include "testing/gtest/include/gtest/gtest.h" 14 #include "testing/platform_test.h" 15 16 namespace { 17 base::i18n::TextDirection GetTextDirection(const char* locale_name) { 18 return base::i18n::GetTextDirectionForLocale(locale_name); 19 } 20 } 21 22 class RTLTest : public PlatformTest { 23 }; 24 25 TEST_F(RTLTest, GetFirstStrongCharacterDirection) { 26 // Test pure LTR string. 27 std::wstring string(L"foo bar"); 28 EXPECT_EQ(base::i18n::LEFT_TO_RIGHT, 29 base::i18n::GetFirstStrongCharacterDirection(string)); 30 31 // Test bidi string in which the first character with strong directionality 32 // is a character with type L. 33 string.assign(L"foo \x05d0 bar"); 34 EXPECT_EQ(base::i18n::LEFT_TO_RIGHT, 35 base::i18n::GetFirstStrongCharacterDirection(string)); 36 37 // Test bidi string in which the first character with strong directionality 38 // is a character with type R. 39 string.assign(L"\x05d0 foo bar"); 40 EXPECT_EQ(base::i18n::RIGHT_TO_LEFT, 41 base::i18n::GetFirstStrongCharacterDirection(string)); 42 43 // Test bidi string which starts with a character with weak directionality 44 // and in which the first character with strong directionality is a character 45 // with type L. 46 string.assign(L"!foo \x05d0 bar"); 47 EXPECT_EQ(base::i18n::LEFT_TO_RIGHT, 48 base::i18n::GetFirstStrongCharacterDirection(string)); 49 50 // Test bidi string which starts with a character with weak directionality 51 // and in which the first character with strong directionality is a character 52 // with type R. 53 string.assign(L",\x05d0 foo bar"); 54 EXPECT_EQ(base::i18n::RIGHT_TO_LEFT, 55 base::i18n::GetFirstStrongCharacterDirection(string)); 56 57 // Test bidi string in which the first character with strong directionality 58 // is a character with type LRE. 59 string.assign(L"\x202a \x05d0 foo bar"); 60 EXPECT_EQ(base::i18n::LEFT_TO_RIGHT, 61 base::i18n::GetFirstStrongCharacterDirection(string)); 62 63 // Test bidi string in which the first character with strong directionality 64 // is a character with type LRO. 65 string.assign(L"\x202d \x05d0 foo bar"); 66 EXPECT_EQ(base::i18n::LEFT_TO_RIGHT, 67 base::i18n::GetFirstStrongCharacterDirection(string)); 68 69 // Test bidi string in which the first character with strong directionality 70 // is a character with type RLE. 71 string.assign(L"\x202b foo \x05d0 bar"); 72 EXPECT_EQ(base::i18n::RIGHT_TO_LEFT, 73 base::i18n::GetFirstStrongCharacterDirection(string)); 74 75 // Test bidi string in which the first character with strong directionality 76 // is a character with type RLO. 77 string.assign(L"\x202e foo \x05d0 bar"); 78 EXPECT_EQ(base::i18n::RIGHT_TO_LEFT, 79 base::i18n::GetFirstStrongCharacterDirection(string)); 80 81 // Test bidi string in which the first character with strong directionality 82 // is a character with type AL. 83 string.assign(L"\x0622 foo \x05d0 bar"); 84 EXPECT_EQ(base::i18n::RIGHT_TO_LEFT, 85 base::i18n::GetFirstStrongCharacterDirection(string)); 86 87 // Test a string without strong directionality characters. 88 string.assign(L",!.{}"); 89 EXPECT_EQ(base::i18n::LEFT_TO_RIGHT, 90 base::i18n::GetFirstStrongCharacterDirection(string)); 91 92 // Test empty string. 93 string.assign(L""); 94 EXPECT_EQ(base::i18n::LEFT_TO_RIGHT, 95 base::i18n::GetFirstStrongCharacterDirection(string)); 96 97 // Test characters in non-BMP (e.g. Phoenician letters. Please refer to 98 // http://demo.icu-project.org/icu-bin/ubrowse?scr=151&b=10910 for more 99 // information). 100 #if defined(WCHAR_T_IS_UTF32) 101 string.assign(L" ! \x10910" L"abc 123"); 102 #elif defined(WCHAR_T_IS_UTF16) 103 string.assign(L" ! \xd802\xdd10" L"abc 123"); 104 #else 105 #error wchar_t should be either UTF-16 or UTF-32 106 #endif 107 EXPECT_EQ(base::i18n::RIGHT_TO_LEFT, 108 base::i18n::GetFirstStrongCharacterDirection(string)); 109 110 #if defined(WCHAR_T_IS_UTF32) 111 string.assign(L" ! \x10401" L"abc 123"); 112 #elif defined(WCHAR_T_IS_UTF16) 113 string.assign(L" ! \xd801\xdc01" L"abc 123"); 114 #else 115 #error wchar_t should be either UTF-16 or UTF-32 116 #endif 117 EXPECT_EQ(base::i18n::LEFT_TO_RIGHT, 118 base::i18n::GetFirstStrongCharacterDirection(string)); 119 } 120 121 TEST_F(RTLTest, WrapPathWithLTRFormatting) { 122 const wchar_t* kTestData[] = { 123 // Test common path, such as "c:\foo\bar". 124 L"c:/foo/bar", 125 // Test path with file name, such as "c:\foo\bar\test.jpg". 126 L"c:/foo/bar/test.jpg", 127 // Test path ending with punctuation, such as "c:\(foo)\bar.". 128 L"c:/(foo)/bar.", 129 // Test path ending with separator, such as "c:\foo\bar\". 130 L"c:/foo/bar/", 131 // Test path with RTL character. 132 L"c:/\x05d0", 133 // Test path with 2 level RTL directory names. 134 L"c:/\x05d0/\x0622", 135 // Test path with mixed RTL/LTR directory names and ending with punctuation. 136 L"c:/\x05d0/\x0622/(foo)/b.a.r.", 137 // Test path without driver name, such as "/foo/bar/test/jpg". 138 L"/foo/bar/test.jpg", 139 // Test path start with current directory, such as "./foo". 140 L"./foo", 141 // Test path start with parent directory, such as "../foo/bar.jpg". 142 L"../foo/bar.jpg", 143 // Test absolute path, such as "//foo/bar.jpg". 144 L"//foo/bar.jpg", 145 // Test path with mixed RTL/LTR directory names. 146 L"c:/foo/\x05d0/\x0622/\x05d1.jpg", 147 // Test empty path. 148 L"" 149 }; 150 for (unsigned int i = 0; i < arraysize(kTestData); ++i) { 151 FilePath path; 152 #if defined(OS_WIN) 153 std::wstring win_path(kTestData[i]); 154 std::replace(win_path.begin(), win_path.end(), '/', '\\'); 155 path = FilePath(win_path); 156 std::wstring wrapped_expected = 157 std::wstring(L"\x202a") + win_path + L"\x202c"; 158 #else 159 path = FilePath(base::SysWideToNativeMB(kTestData[i])); 160 std::wstring wrapped_expected = 161 std::wstring(L"\x202a") + kTestData[i] + L"\x202c"; 162 #endif 163 string16 localized_file_path_string; 164 base::i18n::WrapPathWithLTRFormatting(path, &localized_file_path_string); 165 166 std::wstring wrapped_actual = UTF16ToWide(localized_file_path_string); 167 EXPECT_EQ(wrapped_expected, wrapped_actual); 168 } 169 } 170 171 typedef struct { 172 std::wstring raw_filename; 173 std::wstring display_string; 174 } StringAndLTRString; 175 176 TEST_F(RTLTest, GetDisplayStringInLTRDirectionality) { 177 const StringAndLTRString test_data[] = { 178 { L"test", L"\x202atest\x202c" }, 179 { L"test.html", L"\x202atest.html\x202c" }, 180 { L"\x05d0\x05d1\x05d2", L"\x202a\x05d0\x05d1\x05d2\x202c" }, 181 { L"\x05d0\x05d1\x05d2.txt", L"\x202a\x05d0\x05d1\x05d2.txt\x202c" }, 182 { L"\x05d0"L"abc", L"\x202a\x05d0"L"abc\x202c" }, 183 { L"\x05d0"L"abc.txt", L"\x202a\x05d0"L"abc.txt\x202c" }, 184 { L"abc\x05d0\x05d1", L"\x202a"L"abc\x05d0\x05d1\x202c" }, 185 { L"abc\x05d0\x05d1.jpg", L"\x202a"L"abc\x05d0\x05d1.jpg\x202c" }, 186 }; 187 for (unsigned int i = 0; i < arraysize(test_data); ++i) { 188 string16 input = WideToUTF16(test_data[i].raw_filename); 189 string16 expected = base::i18n::GetDisplayStringInLTRDirectionality(input); 190 if (base::i18n::IsRTL()) 191 EXPECT_EQ(expected, WideToUTF16(test_data[i].display_string)); 192 else 193 EXPECT_EQ(expected, input); 194 } 195 } 196 197 TEST_F(RTLTest, GetTextDirection) { 198 EXPECT_EQ(base::i18n::RIGHT_TO_LEFT, GetTextDirection("ar")); 199 EXPECT_EQ(base::i18n::RIGHT_TO_LEFT, GetTextDirection("ar_EG")); 200 EXPECT_EQ(base::i18n::RIGHT_TO_LEFT, GetTextDirection("he")); 201 EXPECT_EQ(base::i18n::RIGHT_TO_LEFT, GetTextDirection("he_IL")); 202 // iw is an obsolete code for Hebrew. 203 EXPECT_EQ(base::i18n::RIGHT_TO_LEFT, GetTextDirection("iw")); 204 // Although we're not yet localized to Farsi and Urdu, we 205 // do have the text layout direction information for them. 206 EXPECT_EQ(base::i18n::RIGHT_TO_LEFT, GetTextDirection("fa")); 207 EXPECT_EQ(base::i18n::RIGHT_TO_LEFT, GetTextDirection("ur")); 208 #if 0 209 // Enable these when we include the minimal locale data for Azerbaijani 210 // written in Arabic and Dhivehi. At the moment, our copy of 211 // ICU data does not have entries for them. 212 EXPECT_EQ(base::i18n::RIGHT_TO_LEFT, GetTextDirection("az_Arab")); 213 // Dhivehi that uses Thaana script. 214 EXPECT_EQ(base::i18n::RIGHT_TO_LEFT, GetTextDirection("dv")); 215 #endif 216 EXPECT_EQ(base::i18n::LEFT_TO_RIGHT, GetTextDirection("en")); 217 // Chinese in China with '-'. 218 EXPECT_EQ(base::i18n::LEFT_TO_RIGHT, GetTextDirection("zh-CN")); 219 // Filipino : 3-letter code 220 EXPECT_EQ(base::i18n::LEFT_TO_RIGHT, GetTextDirection("fil")); 221 // Russian 222 EXPECT_EQ(base::i18n::LEFT_TO_RIGHT, GetTextDirection("ru")); 223 // Japanese that uses multiple scripts 224 EXPECT_EQ(base::i18n::LEFT_TO_RIGHT, GetTextDirection("ja")); 225 } 226 227