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
5 #include "ui/gfx/text_utils.h"
6
7 #include <stddef.h>
8
9 #include "base/stl_util.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "build/build_config.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13 #include "ui/gfx/font_list.h"
14
15 namespace gfx {
16 namespace {
17
18 const base::char16 kAcceleratorChar = '&';
19
20 struct RemoveAcceleratorCharData {
21 const char* input;
22 int accelerated_char_pos;
23 int accelerated_char_span;
24 const char* output;
25 const char* name;
26 };
27
TEST(TextUtilsTest,GetStringWidth)28 TEST(TextUtilsTest, GetStringWidth) {
29 FontList font_list;
30 EXPECT_EQ(GetStringWidth(base::string16(), font_list), 0);
31 EXPECT_GT(GetStringWidth(base::ASCIIToUTF16("a"), font_list),
32 GetStringWidth(base::string16(), font_list));
33 EXPECT_GT(GetStringWidth(base::ASCIIToUTF16("ab"), font_list),
34 GetStringWidth(base::ASCIIToUTF16("a"), font_list));
35 EXPECT_GT(GetStringWidth(base::ASCIIToUTF16("abc"), font_list),
36 GetStringWidth(base::ASCIIToUTF16("ab"), font_list));
37 }
38
39 class RemoveAcceleratorCharTest
40 : public testing::TestWithParam<RemoveAcceleratorCharData> {
41 public:
42 static const RemoveAcceleratorCharData kCases[];
43 };
44
45 const RemoveAcceleratorCharData RemoveAcceleratorCharTest::kCases[] = {
46 {"", -1, 0, "", "EmptyString"},
47 {"&", -1, 0, "", "AcceleratorCharOnly"},
48 {"no accelerator", -1, 0, "no accelerator", "NoAccelerator"},
49 {"&one accelerator", 0, 1, "one accelerator", "OneAccelerator_Start"},
50 {"one &accelerator", 4, 1, "one accelerator", "OneAccelerator_Middle"},
51 {"one_accelerator&", -1, 0, "one_accelerator", "OneAccelerator_End"},
52 {"&two &accelerators", 4, 1, "two accelerators",
53 "TwoAccelerators_OneAtStart"},
54 {"two &accelerators&", 4, 1, "two accelerators",
55 "TwoAccelerators_OneAtEnd"},
56 {"two& &accelerators", 4, 1, "two accelerators",
57 "TwoAccelerators_SpaceBetween"},
58 {"&&escaping", -1, 0, "&escaping", "Escape_Start"},
59 {"escap&&ing", -1, 0, "escap&ing", "Escape_Middle"},
60 {"escaping&&", -1, 0, "escaping&", "Escape_End"},
61 {"&mix&&ed", 0, 1, "mix&ed", "Mixed_EscapeAfterAccelerator"},
62 {"&&m&ix&&e&d&", 6, 1, "&mix&ed", "Mixed_MiddleAcceleratorSkipped"},
63 {"&&m&&ix&ed&&", 5, 1, "&m&ixed&", "Mixed_OneAccelerator"},
64 {"&m&&ix&ed&&", 4, 1, "m&ixed&", "Mixed_InitialAcceleratorSkipped"},
65 // U+1D49C MATHEMATICAL SCRIPT CAPITAL A, which occupies two |char16|'s.
66 {"&\U0001D49C", 0, 2, "\U0001D49C", "MultibyteAccelerator_Start"},
67 {"Test&\U0001D49Cing", 4, 2, "Test\U0001D49Cing",
68 "MultibyteAccelerator_Middle"},
69 {"Test\U0001D49C&ing", 6, 1, "Test\U0001D49Cing",
70 "OneAccelerator_AfterMultibyte"},
71 {"Test&\U0001D49C&ing", 6, 1, "Test\U0001D49Cing",
72 "MultibyteAccelerator_Skipped"},
73 {"Test&\U0001D49C&&ing", 4, 2, "Test\U0001D49C&ing",
74 "MultibyteAccelerator_EscapeAfter"},
75 {"Test&\U0001D49C&\U0001D49Cing", 6, 2, "Test\U0001D49C\U0001D49Cing",
76 "MultibyteAccelerator_AfterMultibyteAccelerator"},
77 };
78
79 INSTANTIATE_TEST_SUITE_P(
80 All,
81 RemoveAcceleratorCharTest,
82 testing::ValuesIn(RemoveAcceleratorCharTest::kCases),
__anon5c47ba490202(const testing::TestParamInfo<RemoveAcceleratorCharData>& param_info) 83 [](const testing::TestParamInfo<RemoveAcceleratorCharData>& param_info) {
84 return param_info.param.name;
85 });
86
TEST_P(RemoveAcceleratorCharTest,RemoveAcceleratorChar)87 TEST_P(RemoveAcceleratorCharTest, RemoveAcceleratorChar) {
88 RemoveAcceleratorCharData data = GetParam();
89 int accelerated_char_pos;
90 int accelerated_char_span;
91 base::string16 result =
92 RemoveAcceleratorChar(base::UTF8ToUTF16(data.input), kAcceleratorChar,
93 &accelerated_char_pos, &accelerated_char_span);
94 EXPECT_EQ(result, base::UTF8ToUTF16(data.output));
95 EXPECT_EQ(accelerated_char_pos, data.accelerated_char_pos);
96 EXPECT_EQ(accelerated_char_span, data.accelerated_char_span);
97 }
98
99 struct FindValidBoundaryData {
100 const char16_t* input;
101 size_t index_in;
102 bool trim_whitespace;
103 size_t index_out;
104 const char* name;
105 };
106
107 class FindValidBoundaryBeforeTest
108 : public testing::TestWithParam<FindValidBoundaryData> {
109 public:
110 static const FindValidBoundaryData kCases[];
111 };
112
113 const FindValidBoundaryData FindValidBoundaryBeforeTest::kCases[] = {
114 {u"", 0, false, 0, "Empty"},
115 {u"word", 0, false, 0, "StartOfString"},
116 {u"word", 4, false, 4, "EndOfString"},
117 {u"word", 2, false, 2, "MiddleOfString_OnValidCharacter"},
118 {u"wd", 2, false, 1, "MiddleOfString_OnSurrogatePair"},
119 {u"wd", 1, false, 1, "MiddleOfString_BeforeSurrogatePair"},
120 {u"wd", 3, false, 3, "MiddleOfString_AfterSurrogatePair"},
121 {u"wo d", 3, false, 3, "MiddleOfString_OnSpace_NoTrim"},
122 {u"wo d", 3, true, 2, "MiddleOfString_OnSpace_Trim"},
123 {u"wo d", 2, false, 2, "MiddleOfString_LeftOfSpace_NoTrim"},
124 {u"wo d", 2, true, 2, "MiddleOfString_LeftOfSpace_Trim"},
125 {u"wo\td", 3, false, 3, "MiddleOfString_OnTab_NoTrim"},
126 {u"wo\td", 3, true, 2, "MiddleOfString_OnTab_Trim"},
127 {u"w d", 3, false, 3, "MiddleOfString_MultipleWhitespace_NoTrim"},
128 {u"w d", 3, true, 1, "MiddleOfString_MultipleWhitespace_Trim"},
129 {u"w d", 2, false, 2, "MiddleOfString_MiddleOfWhitespace_NoTrim"},
130 {u"w d", 2, true, 1, "MiddleOfString_MiddleOfWhitespace_Trim"},
131 {u"w ", 3, false, 3, "EndOfString_Whitespace_NoTrim"},
132 {u"w ", 3, true, 1, "EndOfString_Whitespace_Trim"},
133 {u" d", 2, false, 2, "MiddleOfString_Whitespace_NoTrim"},
134 {u" d", 2, true, 0, "MiddleOfString_Whitespace_Trim"},
135 // COMBINING GRAVE ACCENT (U+0300)
136 {u"wo\u0300d", 2, false, 1, "MiddleOfString_OnCombiningMark"},
137 {u"wo\u0300d", 1, false, 1, "MiddleOfString_BeforeCombiningMark"},
138 {u"wo\u0300d", 3, false, 3, "MiddleOfString_AfterCombiningMark"},
139 {u"w o\u0300d", 3, true, 1, "MiddleOfString_SpaceAndCombinginMark_Trim"},
140 {u"wo\u0300 d", 3, true, 3, "MiddleOfString_CombiningMarkAndSpace_Trim"},
141 {u"w \u0300d", 3, true, 3,
142 "MiddleOfString_AfterSpaceWithCombiningMark_Trim"},
143 {u"w \u0300d", 2, true, 1, "MiddleOfString_OnSpaceWithCombiningMark_Trim"},
144 {u"w \u0300 d", 4, true, 3,
145 "MiddleOfString_AfterSpaceAfterSpaceWithCombiningMark_Trim"},
146 // MUSICAL SYMBOL G CLEF (U+1D11E) + MUSICAL SYMBOL COMBINING FLAG-1
147 // (U+1D16E)
148 {u"w\U0001D11E\U0001D16Ed", 1, false, 1,
149 "MiddleOfString_BeforeCombiningSurrogate"},
150 {u"w\U0001D11E\U0001D16Ed", 2, false, 1,
151 "MiddleOfString_OnCombiningSurrogate_Pos1"},
152 {u"w\U0001D11E\U0001D16Ed", 3, false, 1,
153 "MiddleOfString_OnCombiningSurrogate_Pos2"},
154 {u"w\U0001D11E\U0001D16Ed", 4, false, 1,
155 "MiddleOfString_OnCombiningSurrogate_Pos3"},
156 {u"w\U0001D11E\U0001D16Ed", 5, false, 5,
157 "MiddleOfString_AfterCombiningSurrogate"},
158 };
159
160 INSTANTIATE_TEST_SUITE_P(
161 All,
162 FindValidBoundaryBeforeTest,
163 testing::ValuesIn(FindValidBoundaryBeforeTest::kCases),
__anon5c47ba490302(const testing::TestParamInfo<FindValidBoundaryData>& param_info) 164 [](const testing::TestParamInfo<FindValidBoundaryData>& param_info) {
165 return param_info.param.name;
166 });
167
TEST_P(FindValidBoundaryBeforeTest,FindValidBoundaryBefore)168 TEST_P(FindValidBoundaryBeforeTest, FindValidBoundaryBefore) {
169 FindValidBoundaryData data = GetParam();
170 const base::string16::const_pointer input =
171 reinterpret_cast<base::string16::const_pointer>(data.input);
172 DLOG(INFO) << input;
173 size_t result =
174 FindValidBoundaryBefore(input, data.index_in, data.trim_whitespace);
175 EXPECT_EQ(data.index_out, result);
176 }
177
178 class FindValidBoundaryAfterTest
179 : public testing::TestWithParam<FindValidBoundaryData> {
180 public:
181 static const FindValidBoundaryData kCases[];
182 };
183
184 const FindValidBoundaryData FindValidBoundaryAfterTest::kCases[] = {
185 {u"", 0, false, 0, "Empty"},
186 {u"word", 0, false, 0, "StartOfString"},
187 {u"word", 4, false, 4, "EndOfString"},
188 {u"word", 2, false, 2, "MiddleOfString_OnValidCharacter"},
189 {u"wd", 2, false, 3, "MiddleOfString_OnSurrogatePair"},
190 {u"wd", 1, false, 1, "MiddleOfString_BeforeSurrogatePair"},
191 {u"wd", 3, false, 3, "MiddleOfString_AfterSurrogatePair"},
192 {u"wo d", 2, false, 2, "MiddleOfString_OnSpace_NoTrim"},
193 {u"wo d", 2, true, 3, "MiddleOfString_OnSpace_Trim"},
194 {u"wo d", 3, false, 3, "MiddleOfString_RightOfSpace_NoTrim"},
195 {u"wo d", 3, true, 3, "MiddleOfString_RightOfSpace_Trim"},
196 {u"wo\td", 2, false, 2, "MiddleOfString_OnTab_NoTrim"},
197 {u"wo\td", 2, true, 3, "MiddleOfString_OnTab_Trim"},
198 {u"w d", 1, false, 1, "MiddleOfString_MultipleWhitespace_NoTrim"},
199 {u"w d", 1, true, 3, "MiddleOfString_MultipleWhitespace_Trim"},
200 {u"w d", 2, false, 2, "MiddleOfString_MiddleOfWhitespace_NoTrim"},
201 {u"w d", 2, true, 3, "MiddleOfString_MiddleOfWhitespace_Trim"},
202 {u"w ", 1, false, 1, "MiddleOfString_Whitespace_NoTrim"},
203 {u"w ", 1, true, 3, "MiddleOfString_Whitespace_Trim"},
204 {u" d", 0, false, 0, "StartOfString_Whitespace_NoTrim"},
205 {u" d", 0, true, 2, "StartOfString_Whitespace_Trim"},
206 // COMBINING GRAVE ACCENT (U+0300)
207 {u"wo\u0300d", 2, false, 3, "MiddleOfString_OnCombiningMark"},
208 {u"wo\u0300d", 1, false, 1, "MiddleOfString_BeforeCombiningMark"},
209 {u"wo\u0300d", 3, false, 3, "MiddleOfString_AfterCombiningMark"},
210 {u"w o\u0300d", 1, true, 2, "MiddleOfString_SpaceAndCombinginMark_Trim"},
211 {u"wo\u0300 d", 1, true, 1,
212 "MiddleOfString_BeforeCombiningMarkAndSpace_Trim"},
213 {u"wo\u0300 d", 2, true, 4, "MiddleOfString_OnCombiningMarkAndSpace_Trim"},
214 {u"w \u0300d", 1, true, 1,
215 "MiddleOfString_BeforeSpaceWithCombiningMark_Trim"},
216 {u"w \u0300d", 2, true, 3, "MiddleOfString_OnSpaceWithCombiningMark_Trim"},
217 {u"w \u0300d", 1, true, 2,
218 "MiddleOfString_BeforeSpaceBeforeSpaceWithCombiningMark_Trim"},
219 // MUSICAL SYMBOL G CLEF (U+1D11E) + MUSICAL SYMBOL COMBINING FLAG-1
220 // (U+1D16E)
221 {u"w\U0001D11E\U0001D16Ed", 1, false, 1,
222 "MiddleOfString_BeforeCombiningSurrogate"},
223 {u"w\U0001D11E\U0001D16Ed", 2, false, 5,
224 "MiddleOfString_OnCombiningSurrogate_Pos1"},
225 {u"w\U0001D11E\U0001D16Ed", 3, false, 5,
226 "MiddleOfString_OnCombiningSurrogate_Pos2"},
227 {u"w\U0001D11E\U0001D16Ed", 4, false, 5,
228 "MiddleOfString_OnCombiningSurrogate_Pos3"},
229 {u"w\U0001D11E\U0001D16Ed", 5, false, 5,
230 "MiddleOfString_AfterCombiningSurrogate"},
231 };
232
233 INSTANTIATE_TEST_SUITE_P(
234 All,
235 FindValidBoundaryAfterTest,
236 testing::ValuesIn(FindValidBoundaryAfterTest::kCases),
__anon5c47ba490402(const testing::TestParamInfo<FindValidBoundaryData>& param_info) 237 [](const testing::TestParamInfo<FindValidBoundaryData>& param_info) {
238 return param_info.param.name;
239 });
240
TEST_P(FindValidBoundaryAfterTest,FindValidBoundaryAfter)241 TEST_P(FindValidBoundaryAfterTest, FindValidBoundaryAfter) {
242 FindValidBoundaryData data = GetParam();
243 const base::string16::const_pointer input =
244 reinterpret_cast<base::string16::const_pointer>(data.input);
245 size_t result =
246 FindValidBoundaryAfter(input, data.index_in, data.trim_whitespace);
247 EXPECT_EQ(data.index_out, result);
248 }
249
250 } // namespace
251 } // namespace gfx
252