rtl_unittest.cc 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560
  1. // Copyright (c) 2011 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. #include "base/i18n/rtl.h"
  5. #include <stddef.h>
  6. #include <algorithm>
  7. #include "base/files/file_path.h"
  8. #include "base/logging.h"
  9. #include "base/strings/string_util.h"
  10. #include "base/strings/sys_string_conversions.h"
  11. #include "base/strings/utf_string_conversions.h"
  12. #include "base/test/icu_test_util.h"
  13. #include "build/build_config.h"
  14. #include "testing/gtest/include/gtest/gtest.h"
  15. #include "testing/platform_test.h"
  16. #include "third_party/icu/source/common/unicode/locid.h"
  17. #include "third_party/icu/source/i18n/unicode/usearch.h"
  18. namespace base {
  19. namespace i18n {
  20. class RTLTest : public PlatformTest {
  21. };
  22. TEST_F(RTLTest, GetFirstStrongCharacterDirection) {
  23. struct {
  24. const wchar_t* text;
  25. TextDirection direction;
  26. } cases[] = {
  27. // Test pure LTR string.
  28. { L"foo bar", LEFT_TO_RIGHT },
  29. // Test pure RTL string.
  30. { L"\x05d0\x05d1\x05d2 \x05d3\x0d4\x05d5", RIGHT_TO_LEFT},
  31. // Test bidi string in which the first character with strong directionality
  32. // is a character with type L.
  33. { L"foo \x05d0 bar", LEFT_TO_RIGHT },
  34. // Test bidi string in which the first character with strong directionality
  35. // is a character with type R.
  36. { L"\x05d0 foo bar", RIGHT_TO_LEFT },
  37. // Test bidi string which starts with a character with weak directionality
  38. // and in which the first character with strong directionality is a
  39. // character with type L.
  40. { L"!foo \x05d0 bar", LEFT_TO_RIGHT },
  41. // Test bidi string which starts with a character with weak directionality
  42. // and in which the first character with strong directionality is a
  43. // character with type R.
  44. { L",\x05d0 foo bar", RIGHT_TO_LEFT },
  45. // Test bidi string in which the first character with strong directionality
  46. // is a character with type LRE.
  47. { L"\x202a \x05d0 foo bar", LEFT_TO_RIGHT },
  48. // Test bidi string in which the first character with strong directionality
  49. // is a character with type LRO.
  50. { L"\x202d \x05d0 foo bar", LEFT_TO_RIGHT },
  51. // Test bidi string in which the first character with strong directionality
  52. // is a character with type RLE.
  53. { L"\x202b foo \x05d0 bar", RIGHT_TO_LEFT },
  54. // Test bidi string in which the first character with strong directionality
  55. // is a character with type RLO.
  56. { L"\x202e foo \x05d0 bar", RIGHT_TO_LEFT },
  57. // Test bidi string in which the first character with strong directionality
  58. // is a character with type AL.
  59. { L"\x0622 foo \x05d0 bar", RIGHT_TO_LEFT },
  60. // Test a string without strong directionality characters.
  61. { L",!.{}", LEFT_TO_RIGHT },
  62. // Test empty string.
  63. { L"", LEFT_TO_RIGHT },
  64. // Test characters in non-BMP (e.g. Phoenician letters. Please refer to
  65. // http://demo.icu-project.org/icu-bin/ubrowse?scr=151&b=10910 for more
  66. // information).
  67. {
  68. #if defined(WCHAR_T_IS_UTF32)
  69. L" ! \x10910" L"abc 123",
  70. #elif defined(WCHAR_T_IS_UTF16)
  71. L" ! \xd802\xdd10" L"abc 123",
  72. #else
  73. #error wchar_t should be either UTF-16 or UTF-32
  74. #endif
  75. RIGHT_TO_LEFT },
  76. {
  77. #if defined(WCHAR_T_IS_UTF32)
  78. L" ! \x10401" L"abc 123",
  79. #elif defined(WCHAR_T_IS_UTF16)
  80. L" ! \xd801\xdc01" L"abc 123",
  81. #else
  82. #error wchar_t should be either UTF-16 or UTF-32
  83. #endif
  84. LEFT_TO_RIGHT },
  85. };
  86. for (auto& i : cases)
  87. EXPECT_EQ(i.direction,
  88. GetFirstStrongCharacterDirection(WideToUTF16(i.text)));
  89. }
  90. // Note that the cases with LRE, LRO, RLE and RLO are invalid for
  91. // GetLastStrongCharacterDirection because they should be followed by PDF
  92. // character.
  93. TEST_F(RTLTest, GetLastStrongCharacterDirection) {
  94. struct {
  95. const wchar_t* text;
  96. TextDirection direction;
  97. } cases[] = {
  98. // Test pure LTR string.
  99. { L"foo bar", LEFT_TO_RIGHT },
  100. // Test pure RTL string.
  101. { L"\x05d0\x05d1\x05d2 \x05d3\x0d4\x05d5", RIGHT_TO_LEFT},
  102. // Test bidi string in which the last character with strong directionality
  103. // is a character with type L.
  104. { L"foo \x05d0 bar", LEFT_TO_RIGHT },
  105. // Test bidi string in which the last character with strong directionality
  106. // is a character with type R.
  107. { L"\x05d0 foo bar \x05d3", RIGHT_TO_LEFT },
  108. // Test bidi string which ends with a character with weak directionality
  109. // and in which the last character with strong directionality is a
  110. // character with type L.
  111. { L"!foo \x05d0 bar!", LEFT_TO_RIGHT },
  112. // Test bidi string which ends with a character with weak directionality
  113. // and in which the last character with strong directionality is a
  114. // character with type R.
  115. { L",\x05d0 foo bar \x05d1,", RIGHT_TO_LEFT },
  116. // Test bidi string in which the last character with strong directionality
  117. // is a character with type AL.
  118. { L"\x0622 foo \x05d0 bar \x0622", RIGHT_TO_LEFT },
  119. // Test a string without strong directionality characters.
  120. { L",!.{}", LEFT_TO_RIGHT },
  121. // Test empty string.
  122. { L"", LEFT_TO_RIGHT },
  123. // Test characters in non-BMP (e.g. Phoenician letters. Please refer to
  124. // http://demo.icu-project.org/icu-bin/ubrowse?scr=151&b=10910 for more
  125. // information).
  126. {
  127. #if defined(WCHAR_T_IS_UTF32)
  128. L"abc 123" L" ! \x10910 !",
  129. #elif defined(WCHAR_T_IS_UTF16)
  130. L"abc 123" L" ! \xd802\xdd10 !",
  131. #else
  132. #error wchar_t should be either UTF-16 or UTF-32
  133. #endif
  134. RIGHT_TO_LEFT },
  135. {
  136. #if defined(WCHAR_T_IS_UTF32)
  137. L"abc 123" L" ! \x10401 !",
  138. #elif defined(WCHAR_T_IS_UTF16)
  139. L"abc 123" L" ! \xd801\xdc01 !",
  140. #else
  141. #error wchar_t should be either UTF-16 or UTF-32
  142. #endif
  143. LEFT_TO_RIGHT },
  144. };
  145. for (auto& i : cases)
  146. EXPECT_EQ(i.direction,
  147. GetLastStrongCharacterDirection(WideToUTF16(i.text)));
  148. }
  149. TEST_F(RTLTest, GetStringDirection) {
  150. struct {
  151. const wchar_t* text;
  152. TextDirection direction;
  153. } cases[] = {
  154. // Test pure LTR string.
  155. { L"foobar", LEFT_TO_RIGHT },
  156. { L".foobar", LEFT_TO_RIGHT },
  157. { L"foo, bar", LEFT_TO_RIGHT },
  158. // Test pure LTR with strong directionality characters of type LRE.
  159. { L"\x202a\x202a", LEFT_TO_RIGHT },
  160. { L".\x202a\x202a", LEFT_TO_RIGHT },
  161. { L"\x202a, \x202a", LEFT_TO_RIGHT },
  162. // Test pure LTR with strong directionality characters of type LRO.
  163. { L"\x202d\x202d", LEFT_TO_RIGHT },
  164. { L".\x202d\x202d", LEFT_TO_RIGHT },
  165. { L"\x202d, \x202d", LEFT_TO_RIGHT },
  166. // Test pure LTR with various types of strong directionality characters.
  167. { L"foo \x202a\x202d", LEFT_TO_RIGHT },
  168. { L".\x202d foo \x202a", LEFT_TO_RIGHT },
  169. { L"\x202a, \x202d foo", LEFT_TO_RIGHT },
  170. // Test pure RTL with strong directionality characters of type R.
  171. { L"\x05d0\x05d0", RIGHT_TO_LEFT },
  172. { L".\x05d0\x05d0", RIGHT_TO_LEFT },
  173. { L"\x05d0, \x05d0", RIGHT_TO_LEFT },
  174. // Test pure RTL with strong directionality characters of type RLE.
  175. { L"\x202b\x202b", RIGHT_TO_LEFT },
  176. { L".\x202b\x202b", RIGHT_TO_LEFT },
  177. { L"\x202b, \x202b", RIGHT_TO_LEFT },
  178. // Test pure RTL with strong directionality characters of type RLO.
  179. { L"\x202e\x202e", RIGHT_TO_LEFT },
  180. { L".\x202e\x202e", RIGHT_TO_LEFT },
  181. { L"\x202e, \x202e", RIGHT_TO_LEFT },
  182. // Test pure RTL with strong directionality characters of type AL.
  183. { L"\x0622\x0622", RIGHT_TO_LEFT },
  184. { L".\x0622\x0622", RIGHT_TO_LEFT },
  185. { L"\x0622, \x0622", RIGHT_TO_LEFT },
  186. // Test pure RTL with various types of strong directionality characters.
  187. { L"\x05d0\x202b\x202e\x0622", RIGHT_TO_LEFT },
  188. { L".\x202b\x202e\x0622\x05d0", RIGHT_TO_LEFT },
  189. { L"\x0622\x202e, \x202b\x05d0", RIGHT_TO_LEFT },
  190. // Test bidi strings.
  191. { L"foo \x05d0 bar", UNKNOWN_DIRECTION },
  192. { L"\x202b foo bar", UNKNOWN_DIRECTION },
  193. { L"!foo \x0622 bar", UNKNOWN_DIRECTION },
  194. { L"\x202a\x202b", UNKNOWN_DIRECTION },
  195. { L"\x202e\x202d", UNKNOWN_DIRECTION },
  196. { L"\x0622\x202a", UNKNOWN_DIRECTION },
  197. { L"\x202d\x05d0", UNKNOWN_DIRECTION },
  198. // Test a string without strong directionality characters.
  199. { L",!.{}", LEFT_TO_RIGHT },
  200. // Test empty string.
  201. { L"", LEFT_TO_RIGHT },
  202. {
  203. #if defined(WCHAR_T_IS_UTF32)
  204. L" ! \x10910" L"abc 123",
  205. #elif defined(WCHAR_T_IS_UTF16)
  206. L" ! \xd802\xdd10" L"abc 123",
  207. #else
  208. #error wchar_t should be either UTF-16 or UTF-32
  209. #endif
  210. UNKNOWN_DIRECTION },
  211. {
  212. #if defined(WCHAR_T_IS_UTF32)
  213. L" ! \x10401" L"abc 123",
  214. #elif defined(WCHAR_T_IS_UTF16)
  215. L" ! \xd801\xdc01" L"abc 123",
  216. #else
  217. #error wchar_t should be either UTF-16 or UTF-32
  218. #endif
  219. LEFT_TO_RIGHT },
  220. };
  221. for (auto& i : cases)
  222. EXPECT_EQ(i.direction, GetStringDirection(WideToUTF16(i.text)));
  223. }
  224. TEST_F(RTLTest, WrapPathWithLTRFormatting) {
  225. const wchar_t* cases[] = {
  226. // Test common path, such as "c:\foo\bar".
  227. L"c:/foo/bar",
  228. // Test path with file name, such as "c:\foo\bar\test.jpg".
  229. L"c:/foo/bar/test.jpg",
  230. // Test path ending with punctuation, such as "c:\(foo)\bar.".
  231. L"c:/(foo)/bar.",
  232. // Test path ending with separator, such as "c:\foo\bar\".
  233. L"c:/foo/bar/",
  234. // Test path with RTL character.
  235. L"c:/\x05d0",
  236. // Test path with 2 level RTL directory names.
  237. L"c:/\x05d0/\x0622",
  238. // Test path with mixed RTL/LTR directory names and ending with punctuation.
  239. L"c:/\x05d0/\x0622/(foo)/b.a.r.",
  240. // Test path without driver name, such as "/foo/bar/test/jpg".
  241. L"/foo/bar/test.jpg",
  242. // Test path start with current directory, such as "./foo".
  243. L"./foo",
  244. // Test path start with parent directory, such as "../foo/bar.jpg".
  245. L"../foo/bar.jpg",
  246. // Test absolute path, such as "//foo/bar.jpg".
  247. L"//foo/bar.jpg",
  248. // Test path with mixed RTL/LTR directory names.
  249. L"c:/foo/\x05d0/\x0622/\x05d1.jpg",
  250. // Test empty path.
  251. L""
  252. };
  253. for (auto*& i : cases) {
  254. FilePath path;
  255. #if BUILDFLAG(IS_WIN)
  256. std::wstring win_path(i);
  257. std::replace(win_path.begin(), win_path.end(), '/', '\\');
  258. path = FilePath(win_path);
  259. std::wstring wrapped_expected =
  260. std::wstring(L"\x202a") + win_path + L"\x202c";
  261. #else
  262. path = FilePath(base::SysWideToNativeMB(i));
  263. std::wstring wrapped_expected = std::wstring(L"\x202a") + i + L"\x202c";
  264. #endif
  265. std::u16string localized_file_path_string;
  266. WrapPathWithLTRFormatting(path, &localized_file_path_string);
  267. std::wstring wrapped_actual = UTF16ToWide(localized_file_path_string);
  268. EXPECT_EQ(wrapped_expected, wrapped_actual);
  269. }
  270. }
  271. TEST_F(RTLTest, WrapString) {
  272. const wchar_t* cases[] = {
  273. L" . ",
  274. L"abc",
  275. L"a" L"\x5d0\x5d1",
  276. L"a" L"\x5d1" L"b",
  277. L"\x5d0\x5d1\x5d2",
  278. L"\x5d0\x5d1" L"a",
  279. L"\x5d0" L"a" L"\x5d1",
  280. };
  281. const bool was_rtl = IsRTL();
  282. test::ScopedRestoreICUDefaultLocale restore_locale;
  283. for (size_t i = 0; i < 2; ++i) {
  284. // Toggle the application default text direction (to try each direction).
  285. SetRTLForTesting(!IsRTL());
  286. std::u16string empty;
  287. WrapStringWithLTRFormatting(&empty);
  288. EXPECT_TRUE(empty.empty());
  289. WrapStringWithRTLFormatting(&empty);
  290. EXPECT_TRUE(empty.empty());
  291. for (auto*& test_case : cases) {
  292. std::u16string input = WideToUTF16(test_case);
  293. std::u16string ltr_wrap = input;
  294. WrapStringWithLTRFormatting(&ltr_wrap);
  295. EXPECT_EQ(ltr_wrap[0], kLeftToRightEmbeddingMark);
  296. EXPECT_EQ(ltr_wrap.substr(1, ltr_wrap.length() - 2), input);
  297. EXPECT_EQ(ltr_wrap[ltr_wrap.length() -1], kPopDirectionalFormatting);
  298. std::u16string rtl_wrap = input;
  299. WrapStringWithRTLFormatting(&rtl_wrap);
  300. EXPECT_EQ(rtl_wrap[0], kRightToLeftEmbeddingMark);
  301. EXPECT_EQ(rtl_wrap.substr(1, rtl_wrap.length() - 2), input);
  302. EXPECT_EQ(rtl_wrap[rtl_wrap.length() -1], kPopDirectionalFormatting);
  303. }
  304. }
  305. EXPECT_EQ(was_rtl, IsRTL());
  306. }
  307. TEST_F(RTLTest, GetDisplayStringInLTRDirectionality) {
  308. struct {
  309. const wchar_t* path;
  310. bool wrap_ltr;
  311. bool wrap_rtl;
  312. } cases[] = {
  313. { L"test", false, true },
  314. { L"test.html", false, true },
  315. { L"\x05d0\x05d1\x05d2", true, true },
  316. { L"\x05d0\x05d1\x05d2.txt", true, true },
  317. { L"\x05d0" L"abc", true, true },
  318. { L"\x05d0" L"abc.txt", true, true },
  319. { L"abc\x05d0\x05d1", false, true },
  320. { L"abc\x05d0\x05d1.jpg", false, true },
  321. };
  322. const bool was_rtl = IsRTL();
  323. test::ScopedRestoreICUDefaultLocale restore_locale;
  324. for (size_t i = 0; i < 2; ++i) {
  325. // Toggle the application default text direction (to try each direction).
  326. SetRTLForTesting(!IsRTL());
  327. for (auto& test_case : cases) {
  328. std::u16string input = WideToUTF16(test_case.path);
  329. std::u16string output = GetDisplayStringInLTRDirectionality(input);
  330. // Test the expected wrapping behavior for the current UI directionality.
  331. if (IsRTL() ? test_case.wrap_rtl : test_case.wrap_ltr)
  332. EXPECT_NE(output, input);
  333. else
  334. EXPECT_EQ(output, input);
  335. }
  336. }
  337. EXPECT_EQ(was_rtl, IsRTL());
  338. }
  339. TEST_F(RTLTest, GetTextDirection) {
  340. EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocale("ar"));
  341. EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocale("ar_EG"));
  342. EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocale("he"));
  343. EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocale("he_IL"));
  344. // iw is an obsolete code for Hebrew.
  345. EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocale("iw"));
  346. // Although we're not yet localized to Farsi and Urdu, we
  347. // do have the text layout direction information for them.
  348. EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocale("fa"));
  349. EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocale("ur"));
  350. #if 0
  351. // Enable these when we include the minimal locale data for Azerbaijani
  352. // written in Arabic and Dhivehi. At the moment, our copy of
  353. // ICU data does not have entries for them.
  354. EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocale("az_Arab"));
  355. // Dhivehi that uses Thaana script.
  356. EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocale("dv"));
  357. #endif
  358. EXPECT_EQ(LEFT_TO_RIGHT, GetTextDirectionForLocale("en"));
  359. // Chinese in China with '-'.
  360. EXPECT_EQ(LEFT_TO_RIGHT, GetTextDirectionForLocale("zh-CN"));
  361. // Filipino : 3-letter code
  362. EXPECT_EQ(LEFT_TO_RIGHT, GetTextDirectionForLocale("fil"));
  363. // Russian
  364. EXPECT_EQ(LEFT_TO_RIGHT, GetTextDirectionForLocale("ru"));
  365. // Japanese that uses multiple scripts
  366. EXPECT_EQ(LEFT_TO_RIGHT, GetTextDirectionForLocale("ja"));
  367. }
  368. TEST_F(RTLTest, GetTextDirectionForLocaleInStartUp) {
  369. EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocaleInStartUp("ar"));
  370. EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocaleInStartUp("ar_EG"));
  371. EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocaleInStartUp("he"));
  372. EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocaleInStartUp("he_IL"));
  373. // iw is an obsolete code for Hebrew.
  374. EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocaleInStartUp("iw"));
  375. // Although we're not yet localized to Farsi and Urdu, we
  376. // do have the text layout direction information for them.
  377. EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocaleInStartUp("fa"));
  378. EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocaleInStartUp("ur"));
  379. EXPECT_EQ(LEFT_TO_RIGHT, GetTextDirectionForLocaleInStartUp("en"));
  380. // Chinese in China with '-'.
  381. EXPECT_EQ(LEFT_TO_RIGHT, GetTextDirectionForLocaleInStartUp("zh-CN"));
  382. // Filipino : 3-letter code
  383. EXPECT_EQ(LEFT_TO_RIGHT, GetTextDirectionForLocaleInStartUp("fil"));
  384. // Russian
  385. EXPECT_EQ(LEFT_TO_RIGHT, GetTextDirectionForLocaleInStartUp("ru"));
  386. // Japanese that uses multiple scripts
  387. EXPECT_EQ(LEFT_TO_RIGHT, GetTextDirectionForLocaleInStartUp("ja"));
  388. }
  389. TEST_F(RTLTest, UnadjustStringForLocaleDirection) {
  390. // These test strings are borrowed from WrapPathWithLTRFormatting
  391. const wchar_t* cases[] = {
  392. L"foo bar",
  393. L"foo \x05d0 bar",
  394. L"\x05d0 foo bar",
  395. L"!foo \x05d0 bar",
  396. L",\x05d0 foo bar",
  397. L"\x202a \x05d0 foo bar",
  398. L"\x202d \x05d0 foo bar",
  399. L"\x202b foo \x05d0 bar",
  400. L"\x202e foo \x05d0 bar",
  401. L"\x0622 foo \x05d0 bar",
  402. };
  403. const bool was_rtl = IsRTL();
  404. test::ScopedRestoreICUDefaultLocale restore_locale;
  405. for (size_t i = 0; i < 2; ++i) {
  406. // Toggle the application default text direction (to try each direction).
  407. SetRTLForTesting(!IsRTL());
  408. for (auto*& test_case : cases) {
  409. std::u16string unadjusted_string = WideToUTF16(test_case);
  410. std::u16string adjusted_string = unadjusted_string;
  411. if (!AdjustStringForLocaleDirection(&adjusted_string))
  412. continue;
  413. EXPECT_NE(unadjusted_string, adjusted_string);
  414. EXPECT_TRUE(UnadjustStringForLocaleDirection(&adjusted_string));
  415. EXPECT_EQ(unadjusted_string, adjusted_string)
  416. << " for test case [" << unadjusted_string
  417. << "] with IsRTL() == " << IsRTL();
  418. }
  419. }
  420. EXPECT_EQ(was_rtl, IsRTL());
  421. }
  422. TEST_F(RTLTest, EnsureTerminatedDirectionalFormatting) {
  423. struct {
  424. const wchar_t* unformated_text;
  425. const wchar_t* formatted_text;
  426. } cases[] = {
  427. // Tests string without any dir-formatting characters.
  428. {L"google.com", L"google.com"},
  429. // Tests string with properly terminated dir-formatting character.
  430. {L"\x202egoogle.com\x202c", L"\x202egoogle.com\x202c"},
  431. // Tests string with over-terminated dir-formatting characters.
  432. {L"\x202egoogle\x202c.com\x202c", L"\x202egoogle\x202c.com\x202c"},
  433. // Tests string beginning with a dir-formatting character.
  434. {L"\x202emoc.elgoog", L"\x202emoc.elgoog\x202c"},
  435. // Tests string that over-terminates then re-opens.
  436. {L"\x202egoogle\x202c\x202c.\x202eom",
  437. L"\x202egoogle\x202c\x202c.\x202eom\x202c"},
  438. // Tests string containing a dir-formatting character in the middle.
  439. {L"google\x202e.com", L"google\x202e.com\x202c"},
  440. // Tests string with multiple dir-formatting characters.
  441. {L"\x202egoogle\x202e.com/\x202eguest",
  442. L"\x202egoogle\x202e.com/\x202eguest\x202c\x202c\x202c"},
  443. // Test the other dir-formatting characters (U+202A, U+202B, and U+202D).
  444. {L"\x202agoogle.com", L"\x202agoogle.com\x202c"},
  445. {L"\x202bgoogle.com", L"\x202bgoogle.com\x202c"},
  446. {L"\x202dgoogle.com", L"\x202dgoogle.com\x202c"},
  447. };
  448. const bool was_rtl = IsRTL();
  449. test::ScopedRestoreICUDefaultLocale restore_locale;
  450. for (size_t i = 0; i < 2; ++i) {
  451. // Toggle the application default text direction (to try each direction).
  452. SetRTLForTesting(!IsRTL());
  453. for (auto& test_case : cases) {
  454. std::u16string unsanitized_text = WideToUTF16(test_case.unformated_text);
  455. std::u16string sanitized_text = WideToUTF16(test_case.formatted_text);
  456. EnsureTerminatedDirectionalFormatting(&unsanitized_text);
  457. EXPECT_EQ(sanitized_text, unsanitized_text);
  458. }
  459. }
  460. EXPECT_EQ(was_rtl, IsRTL());
  461. }
  462. TEST_F(RTLTest, SanitizeUserSuppliedString) {
  463. struct {
  464. const wchar_t* unformatted_text;
  465. const wchar_t* formatted_text;
  466. } cases[] = {
  467. // Tests RTL string with properly terminated dir-formatting character.
  468. {L"\x202eكبير Google التطبيق\x202c", L"\x202eكبير Google التطبيق\x202c"},
  469. // Tests RTL string with over-terminated dir-formatting characters.
  470. {L"\x202eكبير Google\x202cالتطبيق\x202c",
  471. L"\x202eكبير Google\x202cالتطبيق\x202c"},
  472. // Tests RTL string that over-terminates then re-opens.
  473. {L"\x202eكبير Google\x202c\x202cالتطبيق\x202e",
  474. L"\x202eكبير Google\x202c\x202cالتطبيق\x202e\x202c"},
  475. // Tests RTL string with multiple dir-formatting characters.
  476. {L"\x202eك\x202eبير Google الت\x202eطبيق",
  477. L"\x202eك\x202eبير Google الت\x202eطبيق\x202c\x202c\x202c"},
  478. // Test the other dir-formatting characters (U+202A, U+202B, and U+202D).
  479. {L"\x202aكبير Google التطبيق", L"\x202aكبير Google التطبيق\x202c"},
  480. {L"\x202bكبير Google التطبيق", L"\x202bكبير Google التطبيق\x202c"},
  481. {L"\x202dكبير Google التطبيق", L"\x202dكبير Google التطبيق\x202c"},
  482. };
  483. for (auto& i : cases) {
  484. // On Windows for an LTR locale, no changes to the string are made.
  485. std::u16string prefix, suffix = u"";
  486. #if !BUILDFLAG(IS_WIN)
  487. prefix = u"\x200e\x202b";
  488. suffix = u"\x202c\x200e";
  489. #endif // !BUILDFLAG(IS_WIN)
  490. std::u16string unsanitized_text = WideToUTF16(i.unformatted_text);
  491. std::u16string sanitized_text =
  492. prefix + WideToUTF16(i.formatted_text) + suffix;
  493. SanitizeUserSuppliedString(&unsanitized_text);
  494. EXPECT_EQ(sanitized_text, unsanitized_text);
  495. }
  496. }
  497. class SetICULocaleTest : public PlatformTest {};
  498. TEST_F(SetICULocaleTest, OverlongLocaleId) {
  499. test::ScopedRestoreICUDefaultLocale restore_locale;
  500. std::string id("fr-ca-x-foo");
  501. std::string lid("fr_CA@x=foo");
  502. while (id.length() < 152) {
  503. id.append("-x-foo");
  504. lid.append("-x-foo");
  505. }
  506. SetICUDefaultLocale(id);
  507. EXPECT_STRNE("en_US", icu::Locale::getDefault().getName());
  508. id.append("zzz");
  509. lid.append("zzz");
  510. SetICUDefaultLocale(id);
  511. // ICU-21639 fix the long locale issue now.
  512. EXPECT_STREQ(lid.c_str(), icu::Locale::getDefault().getName());
  513. }
  514. } // namespace i18n
  515. } // namespace base