OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/auto_reset.h" | 5 #include "base/auto_reset.h" |
6 #include "base/memory/scoped_ptr.h" | 6 #include "base/memory/scoped_ptr.h" |
7 #include "base/message_loop.h" | 7 #include "base/message_loop.h" |
8 #include "base/utf_string_conversions.h" | 8 #include "base/utf_string_conversions.h" |
9 #include "testing/gtest/include/gtest/gtest.h" | 9 #include "testing/gtest/include/gtest/gtest.h" |
10 #include "ui/base/clipboard/clipboard.h" | 10 #include "ui/base/clipboard/clipboard.h" |
11 #include "ui/base/clipboard/scoped_clipboard_writer.h" | 11 #include "ui/base/clipboard/scoped_clipboard_writer.h" |
12 #include "ui/base/range/range.h" | 12 #include "ui/base/range/range.h" |
13 #include "views/controls/textfield/textfield.h" | 13 #include "views/controls/textfield/textfield.h" |
14 #include "views/controls/textfield/textfield_views_model.h" | 14 #include "views/controls/textfield/textfield_views_model.h" |
15 #include "views/test/test_views_delegate.h" | 15 #include "views/test/test_views_delegate.h" |
16 #include "views/test/views_test_base.h" | 16 #include "views/test/views_test_base.h" |
17 #include "views/views_delegate.h" | 17 #include "views/views_delegate.h" |
18 | 18 |
19 namespace views { | 19 namespace views { |
20 | 20 |
21 #include "views/test/views_test_base.h" | 21 #include "views/test/views_test_base.h" |
22 | 22 |
23 class TextfieldViewsModelTest : public ViewsTestBase { | 23 class TextfieldViewsModelTest : public ViewsTestBase, |
| 24 public TextfieldViewsModel::Delegate { |
24 public: | 25 public: |
25 TextfieldViewsModelTest() : ViewsTestBase() {} | 26 TextfieldViewsModelTest() |
| 27 : ViewsTestBase(), |
| 28 composition_text_confirmed_or_cleared_(false) { |
| 29 } |
| 30 |
| 31 virtual void OnCompositionTextConfirmedOrCleared() { |
| 32 composition_text_confirmed_or_cleared_ = true; |
| 33 } |
| 34 |
| 35 protected: |
| 36 bool composition_text_confirmed_or_cleared_; |
26 | 37 |
27 private: | 38 private: |
28 DISALLOW_COPY_AND_ASSIGN(TextfieldViewsModelTest); | 39 DISALLOW_COPY_AND_ASSIGN(TextfieldViewsModelTest); |
29 }; | 40 }; |
30 | 41 |
31 #define EXPECT_STR_EQ(ascii, utf16) \ | 42 #define EXPECT_STR_EQ(ascii, utf16) \ |
32 EXPECT_EQ(ASCIIToWide(ascii), UTF16ToWide(utf16)) | 43 EXPECT_EQ(ASCIIToWide(ascii), UTF16ToWide(utf16)) |
33 | 44 |
34 TEST_F(TextfieldViewsModelTest, EditString) { | 45 TEST_F(TextfieldViewsModelTest, EditString) { |
35 TextfieldViewsModel model; | 46 TextfieldViewsModel model(NULL); |
36 // append two strings | 47 // append two strings |
37 model.Append(ASCIIToUTF16("HILL")); | 48 model.Append(ASCIIToUTF16("HILL")); |
38 EXPECT_STR_EQ("HILL", model.text()); | 49 EXPECT_STR_EQ("HILL", model.text()); |
39 model.Append(ASCIIToUTF16("WORLD")); | 50 model.Append(ASCIIToUTF16("WORLD")); |
40 EXPECT_STR_EQ("HILLWORLD", model.text()); | 51 EXPECT_STR_EQ("HILLWORLD", model.text()); |
41 | 52 |
42 // Insert "E" to make hello | 53 // Insert "E" to make hello |
43 model.MoveCursorRight(false); | 54 model.MoveCursorRight(false); |
44 model.Insert('E'); | 55 model.InsertChar('E'); |
45 EXPECT_STR_EQ("HEILLWORLD", model.text()); | 56 EXPECT_STR_EQ("HEILLWORLD", model.text()); |
46 // Replace "I" with "L" | 57 // Replace "I" with "L" |
47 model.Replace('L'); | 58 model.ReplaceChar('L'); |
48 EXPECT_STR_EQ("HELLLWORLD", model.text()); | 59 EXPECT_STR_EQ("HELLLWORLD", model.text()); |
49 model.Replace('L'); | 60 model.ReplaceChar('L'); |
50 model.Replace('O'); | 61 model.ReplaceChar('O'); |
51 EXPECT_STR_EQ("HELLOWORLD", model.text()); | 62 EXPECT_STR_EQ("HELLOWORLD", model.text()); |
52 | 63 |
53 // Delete 6th char "W", then delete 5th char O" | 64 // Delete 6th char "W", then delete 5th char O" |
54 EXPECT_EQ(5U, model.cursor_pos()); | 65 EXPECT_EQ(5U, model.cursor_pos()); |
55 EXPECT_TRUE(model.Delete()); | 66 EXPECT_TRUE(model.Delete()); |
56 EXPECT_STR_EQ("HELLOORLD", model.text()); | 67 EXPECT_STR_EQ("HELLOORLD", model.text()); |
57 EXPECT_TRUE(model.Backspace()); | 68 EXPECT_TRUE(model.Backspace()); |
58 EXPECT_EQ(4U, model.cursor_pos()); | 69 EXPECT_EQ(4U, model.cursor_pos()); |
59 EXPECT_STR_EQ("HELLORLD", model.text()); | 70 EXPECT_STR_EQ("HELLORLD", model.text()); |
60 | 71 |
61 // Move the cursor to start. backspace should fail. | 72 // Move the cursor to start. backspace should fail. |
62 model.MoveCursorToStart(false); | 73 model.MoveCursorToHome(false); |
63 EXPECT_FALSE(model.Backspace()); | 74 EXPECT_FALSE(model.Backspace()); |
64 EXPECT_STR_EQ("HELLORLD", model.text()); | 75 EXPECT_STR_EQ("HELLORLD", model.text()); |
65 // Move the cursor to the end. delete should fail. | 76 // Move the cursor to the end. delete should fail. |
66 model.MoveCursorToEnd(false); | 77 model.MoveCursorToEnd(false); |
67 EXPECT_FALSE(model.Delete()); | 78 EXPECT_FALSE(model.Delete()); |
68 EXPECT_STR_EQ("HELLORLD", model.text()); | 79 EXPECT_STR_EQ("HELLORLD", model.text()); |
69 // but backspace should work. | 80 // but backspace should work. |
70 EXPECT_TRUE(model.Backspace()); | 81 EXPECT_TRUE(model.Backspace()); |
71 EXPECT_STR_EQ("HELLORL", model.text()); | 82 EXPECT_STR_EQ("HELLORL", model.text()); |
72 } | 83 } |
73 | 84 |
74 TEST_F(TextfieldViewsModelTest, EmptyString) { | 85 TEST_F(TextfieldViewsModelTest, EmptyString) { |
75 TextfieldViewsModel model; | 86 TextfieldViewsModel model(NULL); |
76 EXPECT_EQ(string16(), model.text()); | 87 EXPECT_EQ(string16(), model.text()); |
77 EXPECT_EQ(string16(), model.GetSelectedText()); | 88 EXPECT_EQ(string16(), model.GetSelectedText()); |
78 EXPECT_EQ(string16(), model.GetVisibleText()); | 89 EXPECT_EQ(string16(), model.GetVisibleText()); |
79 | 90 |
80 model.MoveCursorLeft(true); | 91 model.MoveCursorLeft(true); |
81 EXPECT_EQ(0U, model.cursor_pos()); | 92 EXPECT_EQ(0U, model.cursor_pos()); |
82 model.MoveCursorRight(true); | 93 model.MoveCursorRight(true); |
83 EXPECT_EQ(0U, model.cursor_pos()); | 94 EXPECT_EQ(0U, model.cursor_pos()); |
84 | 95 |
85 EXPECT_EQ(string16(), model.GetSelectedText()); | 96 EXPECT_EQ(string16(), model.GetSelectedText()); |
86 | 97 |
87 EXPECT_FALSE(model.Delete()); | 98 EXPECT_FALSE(model.Delete()); |
88 EXPECT_FALSE(model.Backspace()); | 99 EXPECT_FALSE(model.Backspace()); |
89 } | 100 } |
90 | 101 |
91 TEST_F(TextfieldViewsModelTest, Selection) { | 102 TEST_F(TextfieldViewsModelTest, Selection) { |
92 TextfieldViewsModel model; | 103 TextfieldViewsModel model(NULL); |
93 model.Append(ASCIIToUTF16("HELLO")); | 104 model.Append(ASCIIToUTF16("HELLO")); |
94 model.MoveCursorRight(false); | 105 model.MoveCursorRight(false); |
95 model.MoveCursorRight(true); | 106 model.MoveCursorRight(true); |
96 EXPECT_STR_EQ("E", model.GetSelectedText()); | 107 EXPECT_STR_EQ("E", model.GetSelectedText()); |
97 model.MoveCursorRight(true); | 108 model.MoveCursorRight(true); |
98 EXPECT_STR_EQ("EL", model.GetSelectedText()); | 109 EXPECT_STR_EQ("EL", model.GetSelectedText()); |
99 | 110 |
100 model.MoveCursorToStart(true); | 111 model.MoveCursorToHome(true); |
101 EXPECT_STR_EQ("H", model.GetSelectedText()); | 112 EXPECT_STR_EQ("H", model.GetSelectedText()); |
102 model.MoveCursorToEnd(true); | 113 model.MoveCursorToEnd(true); |
103 EXPECT_STR_EQ("ELLO", model.GetSelectedText()); | 114 EXPECT_STR_EQ("ELLO", model.GetSelectedText()); |
104 model.ClearSelection(); | 115 model.ClearSelection(); |
105 EXPECT_EQ(string16(), model.GetSelectedText()); | 116 EXPECT_EQ(string16(), model.GetSelectedText()); |
106 model.SelectAll(); | 117 model.SelectAll(); |
107 EXPECT_STR_EQ("HELLO", model.GetSelectedText()); | 118 EXPECT_STR_EQ("HELLO", model.GetSelectedText()); |
108 // SelectAll should select towards the end. | 119 // SelectAll should select towards the end. |
109 ui::Range range; | 120 ui::Range range; |
110 model.GetSelectedRange(&range); | 121 model.GetSelectedRange(&range); |
(...skipping 14 matching lines...) Expand all Loading... |
125 // Select all and move cursor | 136 // Select all and move cursor |
126 model.SelectAll(); | 137 model.SelectAll(); |
127 model.MoveCursorLeft(false); | 138 model.MoveCursorLeft(false); |
128 EXPECT_EQ(0U, model.cursor_pos()); | 139 EXPECT_EQ(0U, model.cursor_pos()); |
129 model.SelectAll(); | 140 model.SelectAll(); |
130 model.MoveCursorRight(false); | 141 model.MoveCursorRight(false); |
131 EXPECT_EQ(5U, model.cursor_pos()); | 142 EXPECT_EQ(5U, model.cursor_pos()); |
132 } | 143 } |
133 | 144 |
134 TEST_F(TextfieldViewsModelTest, SelectionAndEdit) { | 145 TEST_F(TextfieldViewsModelTest, SelectionAndEdit) { |
135 TextfieldViewsModel model; | 146 TextfieldViewsModel model(NULL); |
136 model.Append(ASCIIToUTF16("HELLO")); | 147 model.Append(ASCIIToUTF16("HELLO")); |
137 model.MoveCursorRight(false); | 148 model.MoveCursorRight(false); |
138 model.MoveCursorRight(true); | 149 model.MoveCursorRight(true); |
139 model.MoveCursorRight(true); // select "EL" | 150 model.MoveCursorRight(true); // select "EL" |
140 EXPECT_TRUE(model.Backspace()); | 151 EXPECT_TRUE(model.Backspace()); |
141 EXPECT_STR_EQ("HLO", model.text()); | 152 EXPECT_STR_EQ("HLO", model.text()); |
142 | 153 |
143 model.Append(ASCIIToUTF16("ILL")); | 154 model.Append(ASCIIToUTF16("ILL")); |
144 model.MoveCursorRight(true); | 155 model.MoveCursorRight(true); |
145 model.MoveCursorRight(true); // select "LO" | 156 model.MoveCursorRight(true); // select "LO" |
146 EXPECT_TRUE(model.Delete()); | 157 EXPECT_TRUE(model.Delete()); |
147 EXPECT_STR_EQ("HILL", model.text()); | 158 EXPECT_STR_EQ("HILL", model.text()); |
148 EXPECT_EQ(1U, model.cursor_pos()); | 159 EXPECT_EQ(1U, model.cursor_pos()); |
149 model.MoveCursorRight(true); // select "I" | 160 model.MoveCursorRight(true); // select "I" |
150 model.Insert('E'); | 161 model.InsertChar('E'); |
151 EXPECT_STR_EQ("HELL", model.text()); | 162 EXPECT_STR_EQ("HELL", model.text()); |
152 model.MoveCursorToStart(false); | 163 model.MoveCursorToHome(false); |
153 model.MoveCursorRight(true); // select "H" | 164 model.MoveCursorRight(true); // select "H" |
154 model.Replace('B'); | 165 model.ReplaceChar('B'); |
155 EXPECT_STR_EQ("BELL", model.text()); | 166 EXPECT_STR_EQ("BELL", model.text()); |
156 model.MoveCursorToEnd(false); | 167 model.MoveCursorToEnd(false); |
157 model.MoveCursorLeft(true); | 168 model.MoveCursorLeft(true); |
158 model.MoveCursorLeft(true); // select ">LL" | 169 model.MoveCursorLeft(true); // select ">LL" |
159 model.Replace('E'); | 170 model.ReplaceChar('E'); |
160 EXPECT_STR_EQ("BEE", model.text()); | 171 EXPECT_STR_EQ("BEE", model.text()); |
161 } | 172 } |
162 | 173 |
163 TEST_F(TextfieldViewsModelTest, Password) { | 174 TEST_F(TextfieldViewsModelTest, Password) { |
164 TextfieldViewsModel model; | 175 TextfieldViewsModel model(NULL); |
165 model.set_is_password(true); | 176 model.set_is_password(true); |
166 model.Append(ASCIIToUTF16("HELLO")); | 177 model.Append(ASCIIToUTF16("HELLO")); |
167 EXPECT_STR_EQ("*****", model.GetVisibleText()); | 178 EXPECT_STR_EQ("*****", model.GetVisibleText()); |
168 EXPECT_STR_EQ("HELLO", model.text()); | 179 EXPECT_STR_EQ("HELLO", model.text()); |
169 EXPECT_TRUE(model.Delete()); | 180 EXPECT_TRUE(model.Delete()); |
170 | 181 |
171 EXPECT_STR_EQ("****", model.GetVisibleText()); | 182 EXPECT_STR_EQ("****", model.GetVisibleText()); |
172 EXPECT_STR_EQ("ELLO", model.text()); | 183 EXPECT_STR_EQ("ELLO", model.text()); |
173 EXPECT_EQ(0U, model.cursor_pos()); | 184 EXPECT_EQ(0U, model.cursor_pos()); |
174 | 185 |
175 model.SelectAll(); | 186 model.SelectAll(); |
176 EXPECT_STR_EQ("ELLO", model.GetSelectedText()); | 187 EXPECT_STR_EQ("ELLO", model.GetSelectedText()); |
177 EXPECT_EQ(4U, model.cursor_pos()); | 188 EXPECT_EQ(4U, model.cursor_pos()); |
178 | 189 |
179 model.Insert('X'); | 190 model.InsertChar('X'); |
180 EXPECT_STR_EQ("*", model.GetVisibleText()); | 191 EXPECT_STR_EQ("*", model.GetVisibleText()); |
181 EXPECT_STR_EQ("X", model.text()); | 192 EXPECT_STR_EQ("X", model.text()); |
182 } | 193 } |
183 | 194 |
184 TEST_F(TextfieldViewsModelTest, Word) { | 195 TEST_F(TextfieldViewsModelTest, Word) { |
185 TextfieldViewsModel model; | 196 TextfieldViewsModel model(NULL); |
186 model.Append( | 197 model.Append( |
187 ASCIIToUTF16("The answer to Life, the Universe, and Everything")); | 198 ASCIIToUTF16("The answer to Life, the Universe, and Everything")); |
188 model.MoveCursorToNextWord(false); | 199 model.MoveCursorToNextWord(false); |
189 EXPECT_EQ(3U, model.cursor_pos()); | 200 EXPECT_EQ(3U, model.cursor_pos()); |
190 model.MoveCursorToNextWord(false); | 201 model.MoveCursorToNextWord(false); |
191 EXPECT_EQ(10U, model.cursor_pos()); | 202 EXPECT_EQ(10U, model.cursor_pos()); |
192 model.MoveCursorToNextWord(false); | 203 model.MoveCursorToNextWord(false); |
193 model.MoveCursorToNextWord(false); | 204 model.MoveCursorToNextWord(false); |
194 EXPECT_EQ(18U, model.cursor_pos()); | 205 EXPECT_EQ(18U, model.cursor_pos()); |
195 | 206 |
196 // Should passes the non word char ',' | 207 // Should passes the non word char ',' |
197 model.MoveCursorToNextWord(true); | 208 model.MoveCursorToNextWord(true); |
198 EXPECT_EQ(23U, model.cursor_pos()); | 209 EXPECT_EQ(23U, model.cursor_pos()); |
199 EXPECT_STR_EQ(", the", model.GetSelectedText()); | 210 EXPECT_STR_EQ(", the", model.GetSelectedText()); |
200 | 211 |
201 // Move to the end. | 212 // Move to the end. |
202 model.MoveCursorToNextWord(true); | 213 model.MoveCursorToNextWord(true); |
203 model.MoveCursorToNextWord(true); | 214 model.MoveCursorToNextWord(true); |
204 model.MoveCursorToNextWord(true); | 215 model.MoveCursorToNextWord(true); |
205 EXPECT_STR_EQ(", the Universe, and Everything", model.GetSelectedText()); | 216 EXPECT_STR_EQ(", the Universe, and Everything", model.GetSelectedText()); |
206 // Should be safe to go next word at the end. | 217 // Should be safe to go next word at the end. |
207 model.MoveCursorToNextWord(true); | 218 model.MoveCursorToNextWord(true); |
208 EXPECT_STR_EQ(", the Universe, and Everything", model.GetSelectedText()); | 219 EXPECT_STR_EQ(", the Universe, and Everything", model.GetSelectedText()); |
209 model.Insert('2'); | 220 model.InsertChar('2'); |
210 EXPECT_EQ(19U, model.cursor_pos()); | 221 EXPECT_EQ(19U, model.cursor_pos()); |
211 | 222 |
212 // Now backwards. | 223 // Now backwards. |
213 model.MoveCursorLeft(false); // leave 2. | 224 model.MoveCursorLeft(false); // leave 2. |
214 model.MoveCursorToPreviousWord(true); | 225 model.MoveCursorToPreviousWord(true); |
215 EXPECT_EQ(14U, model.cursor_pos()); | 226 EXPECT_EQ(14U, model.cursor_pos()); |
216 EXPECT_STR_EQ("Life", model.GetSelectedText()); | 227 EXPECT_STR_EQ("Life", model.GetSelectedText()); |
217 model.MoveCursorToPreviousWord(true); | 228 model.MoveCursorToPreviousWord(true); |
218 EXPECT_STR_EQ("to Life", model.GetSelectedText()); | 229 EXPECT_STR_EQ("to Life", model.GetSelectedText()); |
219 model.MoveCursorToPreviousWord(true); | 230 model.MoveCursorToPreviousWord(true); |
220 model.MoveCursorToPreviousWord(true); | 231 model.MoveCursorToPreviousWord(true); |
221 model.MoveCursorToPreviousWord(true); // Select to the begining. | 232 model.MoveCursorToPreviousWord(true); // Select to the begining. |
222 EXPECT_STR_EQ("The answer to Life", model.GetSelectedText()); | 233 EXPECT_STR_EQ("The answer to Life", model.GetSelectedText()); |
223 // Should be safe to go pervious word at the begining. | 234 // Should be safe to go pervious word at the begining. |
224 model.MoveCursorToPreviousWord(true); | 235 model.MoveCursorToPreviousWord(true); |
225 EXPECT_STR_EQ("The answer to Life", model.GetSelectedText()); | 236 EXPECT_STR_EQ("The answer to Life", model.GetSelectedText()); |
226 model.Replace('4'); | 237 model.ReplaceChar('4'); |
227 EXPECT_EQ(string16(), model.GetSelectedText()); | 238 EXPECT_EQ(string16(), model.GetSelectedText()); |
228 EXPECT_STR_EQ("42", model.GetVisibleText()); | 239 EXPECT_STR_EQ("42", model.GetVisibleText()); |
229 } | 240 } |
230 | 241 |
231 TEST_F(TextfieldViewsModelTest, TextFragment) { | 242 TEST_F(TextfieldViewsModelTest, TextFragment) { |
232 TextfieldViewsModel model; | 243 TextfieldViewsModel model(NULL); |
233 TextfieldViewsModel::TextFragments fragments; | 244 TextfieldViewsModel::TextFragments fragments; |
234 // Empty string | 245 // Empty string |
235 model.GetFragments(&fragments); | 246 model.GetFragments(&fragments); |
236 EXPECT_EQ(1U, fragments.size()); | 247 EXPECT_EQ(1U, fragments.size()); |
237 EXPECT_EQ(0U, fragments[0].begin); | 248 EXPECT_EQ(0U, fragments[0].start); |
238 EXPECT_EQ(0U, fragments[0].end); | 249 EXPECT_EQ(0U, fragments[0].end); |
239 EXPECT_FALSE(fragments[0].selected); | 250 EXPECT_FALSE(fragments[0].selected); |
240 | 251 |
241 // Some string | 252 // Some string |
242 model.Append(ASCIIToUTF16("Hello world")); | 253 model.Append(ASCIIToUTF16("Hello world")); |
243 model.GetFragments(&fragments); | 254 model.GetFragments(&fragments); |
244 EXPECT_EQ(1U, fragments.size()); | 255 EXPECT_EQ(1U, fragments.size()); |
245 EXPECT_EQ(0U, fragments[0].begin); | 256 EXPECT_EQ(0U, fragments[0].start); |
246 EXPECT_EQ(11U, fragments[0].end); | 257 EXPECT_EQ(11U, fragments[0].end); |
247 EXPECT_FALSE(fragments[0].selected); | 258 EXPECT_FALSE(fragments[0].selected); |
248 | 259 |
249 // Select 1st word | 260 // Select 1st word |
250 model.MoveCursorToNextWord(true); | 261 model.MoveCursorToNextWord(true); |
251 model.GetFragments(&fragments); | 262 model.GetFragments(&fragments); |
252 EXPECT_EQ(2U, fragments.size()); | 263 EXPECT_EQ(2U, fragments.size()); |
253 EXPECT_EQ(0U, fragments[0].begin); | 264 EXPECT_EQ(0U, fragments[0].start); |
254 EXPECT_EQ(5U, fragments[0].end); | 265 EXPECT_EQ(5U, fragments[0].end); |
255 EXPECT_TRUE(fragments[0].selected); | 266 EXPECT_TRUE(fragments[0].selected); |
256 EXPECT_EQ(5U, fragments[1].begin); | 267 EXPECT_EQ(5U, fragments[1].start); |
257 EXPECT_EQ(11U, fragments[1].end); | 268 EXPECT_EQ(11U, fragments[1].end); |
258 EXPECT_FALSE(fragments[1].selected); | 269 EXPECT_FALSE(fragments[1].selected); |
259 | 270 |
260 // Select empty string | 271 // Select empty string |
261 model.ClearSelection(); | 272 model.ClearSelection(); |
262 model.MoveCursorRight(true); | 273 model.MoveCursorRight(true); |
263 model.GetFragments(&fragments); | 274 model.GetFragments(&fragments); |
264 EXPECT_EQ(3U, fragments.size()); | 275 EXPECT_EQ(3U, fragments.size()); |
265 EXPECT_EQ(0U, fragments[0].begin); | 276 EXPECT_EQ(0U, fragments[0].start); |
266 EXPECT_EQ(5U, fragments[0].end); | 277 EXPECT_EQ(5U, fragments[0].end); |
267 EXPECT_FALSE(fragments[0].selected); | 278 EXPECT_FALSE(fragments[0].selected); |
268 EXPECT_EQ(5U, fragments[1].begin); | 279 EXPECT_EQ(5U, fragments[1].start); |
269 EXPECT_EQ(6U, fragments[1].end); | 280 EXPECT_EQ(6U, fragments[1].end); |
270 EXPECT_TRUE(fragments[1].selected); | 281 EXPECT_TRUE(fragments[1].selected); |
271 | 282 |
272 EXPECT_EQ(6U, fragments[2].begin); | 283 EXPECT_EQ(6U, fragments[2].start); |
273 EXPECT_EQ(11U, fragments[2].end); | 284 EXPECT_EQ(11U, fragments[2].end); |
274 EXPECT_FALSE(fragments[2].selected); | 285 EXPECT_FALSE(fragments[2].selected); |
275 | 286 |
276 // Select to the end. | 287 // Select to the end. |
277 model.MoveCursorToEnd(true); | 288 model.MoveCursorToEnd(true); |
278 model.GetFragments(&fragments); | 289 model.GetFragments(&fragments); |
279 EXPECT_EQ(2U, fragments.size()); | 290 EXPECT_EQ(2U, fragments.size()); |
280 EXPECT_EQ(0U, fragments[0].begin); | 291 EXPECT_EQ(0U, fragments[0].start); |
281 EXPECT_EQ(5U, fragments[0].end); | 292 EXPECT_EQ(5U, fragments[0].end); |
282 EXPECT_FALSE(fragments[0].selected); | 293 EXPECT_FALSE(fragments[0].selected); |
283 EXPECT_EQ(5U, fragments[1].begin); | 294 EXPECT_EQ(5U, fragments[1].start); |
284 EXPECT_EQ(11U, fragments[1].end); | 295 EXPECT_EQ(11U, fragments[1].end); |
285 EXPECT_TRUE(fragments[1].selected); | 296 EXPECT_TRUE(fragments[1].selected); |
286 } | 297 } |
287 | 298 |
288 TEST_F(TextfieldViewsModelTest, SetText) { | 299 TEST_F(TextfieldViewsModelTest, SetText) { |
289 TextfieldViewsModel model; | 300 TextfieldViewsModel model(NULL); |
290 model.Append(ASCIIToUTF16("HELLO")); | 301 model.Append(ASCIIToUTF16("HELLO")); |
291 model.MoveCursorToEnd(false); | 302 model.MoveCursorToEnd(false); |
292 model.SetText(ASCIIToUTF16("GOODBYE")); | 303 model.SetText(ASCIIToUTF16("GOODBYE")); |
293 EXPECT_STR_EQ("GOODBYE", model.text()); | 304 EXPECT_STR_EQ("GOODBYE", model.text()); |
294 EXPECT_EQ(5U, model.cursor_pos()); | 305 EXPECT_EQ(5U, model.cursor_pos()); |
295 model.SelectAll(); | 306 model.SelectAll(); |
296 EXPECT_STR_EQ("GOODBYE", model.GetSelectedText()); | 307 EXPECT_STR_EQ("GOODBYE", model.GetSelectedText()); |
297 // Selection move the current pos to the end. | 308 // Selection move the current pos to the end. |
298 EXPECT_EQ(7U, model.cursor_pos()); | 309 EXPECT_EQ(7U, model.cursor_pos()); |
299 model.MoveCursorToStart(false); | 310 model.MoveCursorToHome(false); |
300 EXPECT_EQ(0U, model.cursor_pos()); | 311 EXPECT_EQ(0U, model.cursor_pos()); |
301 model.MoveCursorToEnd(false); | 312 model.MoveCursorToEnd(false); |
302 | 313 |
303 model.SetText(ASCIIToUTF16("BYE")); | 314 model.SetText(ASCIIToUTF16("BYE")); |
304 EXPECT_EQ(3U, model.cursor_pos()); | 315 EXPECT_EQ(3U, model.cursor_pos()); |
305 EXPECT_EQ(string16(), model.GetSelectedText()); | 316 EXPECT_EQ(string16(), model.GetSelectedText()); |
306 model.SetText(ASCIIToUTF16("")); | 317 model.SetText(ASCIIToUTF16("")); |
307 EXPECT_EQ(0U, model.cursor_pos()); | 318 EXPECT_EQ(0U, model.cursor_pos()); |
308 } | 319 } |
309 | 320 |
310 TEST_F(TextfieldViewsModelTest, Clipboard) { | 321 TEST_F(TextfieldViewsModelTest, Clipboard) { |
311 scoped_ptr<TestViewsDelegate> test_views_delegate(new TestViewsDelegate()); | 322 scoped_ptr<TestViewsDelegate> test_views_delegate(new TestViewsDelegate()); |
312 AutoReset<views::ViewsDelegate*> auto_reset( | 323 AutoReset<views::ViewsDelegate*> auto_reset( |
313 &views::ViewsDelegate::views_delegate, test_views_delegate.get()); | 324 &views::ViewsDelegate::views_delegate, test_views_delegate.get()); |
314 ui::Clipboard* clipboard | 325 ui::Clipboard* clipboard |
315 = views::ViewsDelegate::views_delegate->GetClipboard(); | 326 = views::ViewsDelegate::views_delegate->GetClipboard(); |
316 string16 initial_clipboard_text; | 327 string16 initial_clipboard_text; |
317 clipboard->ReadText(ui::Clipboard::BUFFER_STANDARD, &initial_clipboard_text); | 328 clipboard->ReadText(ui::Clipboard::BUFFER_STANDARD, &initial_clipboard_text); |
318 string16 clipboard_text; | 329 string16 clipboard_text; |
319 TextfieldViewsModel model; | 330 TextfieldViewsModel model(NULL); |
320 model.Append(ASCIIToUTF16("HELLO WORLD")); | 331 model.Append(ASCIIToUTF16("HELLO WORLD")); |
321 model.MoveCursorToEnd(false); | 332 model.MoveCursorToEnd(false); |
322 | 333 |
323 // Test for cut: Empty selection. | 334 // Test for cut: Empty selection. |
324 EXPECT_FALSE(model.Cut()); | 335 EXPECT_FALSE(model.Cut()); |
325 clipboard->ReadText(ui::Clipboard::BUFFER_STANDARD, &clipboard_text); | 336 clipboard->ReadText(ui::Clipboard::BUFFER_STANDARD, &clipboard_text); |
326 EXPECT_STR_EQ(UTF16ToUTF8(initial_clipboard_text), clipboard_text); | 337 EXPECT_STR_EQ(UTF16ToUTF8(initial_clipboard_text), clipboard_text); |
327 EXPECT_STR_EQ("HELLO WORLD", model.text()); | 338 EXPECT_STR_EQ("HELLO WORLD", model.text()); |
328 EXPECT_EQ(11U, model.cursor_pos()); | 339 EXPECT_EQ(11U, model.cursor_pos()); |
329 | 340 |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
362 EXPECT_EQ(29U, model.cursor_pos()); | 373 EXPECT_EQ(29U, model.cursor_pos()); |
363 } | 374 } |
364 | 375 |
365 void SelectWordTestVerifier(TextfieldViewsModel &model, | 376 void SelectWordTestVerifier(TextfieldViewsModel &model, |
366 const std::string &expected_selected_string, size_t expected_cursor_pos) { | 377 const std::string &expected_selected_string, size_t expected_cursor_pos) { |
367 EXPECT_STR_EQ(expected_selected_string, model.GetSelectedText()); | 378 EXPECT_STR_EQ(expected_selected_string, model.GetSelectedText()); |
368 EXPECT_EQ(expected_cursor_pos, model.cursor_pos()); | 379 EXPECT_EQ(expected_cursor_pos, model.cursor_pos()); |
369 } | 380 } |
370 | 381 |
371 TEST_F(TextfieldViewsModelTest, SelectWordTest) { | 382 TEST_F(TextfieldViewsModelTest, SelectWordTest) { |
372 TextfieldViewsModel model; | 383 TextfieldViewsModel model(NULL); |
373 model.Append(ASCIIToUTF16(" HELLO !! WO RLD ")); | 384 model.Append(ASCIIToUTF16(" HELLO !! WO RLD ")); |
374 | 385 |
375 // Test when cursor is at the beginning. | 386 // Test when cursor is at the beginning. |
376 model.MoveCursorToStart(false); | 387 model.MoveCursorToHome(false); |
377 model.SelectWord(); | 388 model.SelectWord(); |
378 SelectWordTestVerifier(model, " ", 2U); | 389 SelectWordTestVerifier(model, " ", 2U); |
379 | 390 |
380 // Test when cursor is at the beginning of a word. | 391 // Test when cursor is at the beginning of a word. |
381 model.MoveCursorTo(2U, false); | 392 model.MoveCursorTo(2U, false); |
382 model.SelectWord(); | 393 model.SelectWord(); |
383 SelectWordTestVerifier(model, "HELLO", 7U); | 394 SelectWordTestVerifier(model, "HELLO", 7U); |
384 | 395 |
385 // Test when cursor is at the end of a word. | 396 // Test when cursor is at the end of a word. |
386 model.MoveCursorTo(15U, false); | 397 model.MoveCursorTo(15U, false); |
(...skipping 12 matching lines...) Expand all Loading... |
399 model.SelectWord(); | 410 model.SelectWord(); |
400 SelectWordTestVerifier(model, " ", 20U); | 411 SelectWordTestVerifier(model, " ", 20U); |
401 | 412 |
402 // Test when cursor is at the end. | 413 // Test when cursor is at the end. |
403 model.MoveCursorToEnd(false); | 414 model.MoveCursorToEnd(false); |
404 model.SelectWord(); | 415 model.SelectWord(); |
405 SelectWordTestVerifier(model, " ", 24U); | 416 SelectWordTestVerifier(model, " ", 24U); |
406 } | 417 } |
407 | 418 |
408 TEST_F(TextfieldViewsModelTest, RangeTest) { | 419 TEST_F(TextfieldViewsModelTest, RangeTest) { |
409 TextfieldViewsModel model; | 420 TextfieldViewsModel model(NULL); |
410 model.Append(ASCIIToUTF16("HELLO WORLD")); | 421 model.Append(ASCIIToUTF16("HELLO WORLD")); |
411 model.MoveCursorToStart(false); | 422 model.MoveCursorToHome(false); |
412 ui::Range range; | 423 ui::Range range; |
413 model.GetSelectedRange(&range); | 424 model.GetSelectedRange(&range); |
414 EXPECT_TRUE(range.is_empty()); | 425 EXPECT_TRUE(range.is_empty()); |
415 EXPECT_EQ(0U, range.start()); | 426 EXPECT_EQ(0U, range.start()); |
416 EXPECT_EQ(0U, range.end()); | 427 EXPECT_EQ(0U, range.end()); |
417 | 428 |
418 model.MoveCursorToNextWord(true); | 429 model.MoveCursorToNextWord(true); |
419 model.GetSelectedRange(&range); | 430 model.GetSelectedRange(&range); |
420 EXPECT_FALSE(range.is_empty()); | 431 EXPECT_FALSE(range.is_empty()); |
421 EXPECT_FALSE(range.is_reversed()); | 432 EXPECT_FALSE(range.is_reversed()); |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
455 EXPECT_EQ(11U, range.start()); | 466 EXPECT_EQ(11U, range.start()); |
456 EXPECT_EQ(7U, range.end()); | 467 EXPECT_EQ(7U, range.end()); |
457 | 468 |
458 model.MoveCursorToNextWord(true); | 469 model.MoveCursorToNextWord(true); |
459 model.GetSelectedRange(&range); | 470 model.GetSelectedRange(&range); |
460 EXPECT_TRUE(range.is_empty()); | 471 EXPECT_TRUE(range.is_empty()); |
461 EXPECT_EQ(11U, range.start()); | 472 EXPECT_EQ(11U, range.start()); |
462 EXPECT_EQ(11U, range.end()); | 473 EXPECT_EQ(11U, range.end()); |
463 | 474 |
464 // Select All | 475 // Select All |
465 model.MoveCursorToStart(true); | 476 model.MoveCursorToHome(true); |
466 model.GetSelectedRange(&range); | 477 model.GetSelectedRange(&range); |
467 EXPECT_FALSE(range.is_empty()); | 478 EXPECT_FALSE(range.is_empty()); |
468 EXPECT_TRUE(range.is_reversed()); | 479 EXPECT_TRUE(range.is_reversed()); |
469 EXPECT_EQ(11U, range.start()); | 480 EXPECT_EQ(11U, range.start()); |
470 EXPECT_EQ(0U, range.end()); | 481 EXPECT_EQ(0U, range.end()); |
471 } | 482 } |
472 | 483 |
473 TEST_F(TextfieldViewsModelTest, SelectRangeTest) { | 484 TEST_F(TextfieldViewsModelTest, SelectRangeTest) { |
474 TextfieldViewsModel model; | 485 TextfieldViewsModel model(NULL); |
475 model.Append(ASCIIToUTF16("HELLO WORLD")); | 486 model.Append(ASCIIToUTF16("HELLO WORLD")); |
476 ui::Range range(0, 6); | 487 ui::Range range(0, 6); |
477 EXPECT_FALSE(range.is_reversed()); | 488 EXPECT_FALSE(range.is_reversed()); |
478 model.SelectRange(range); | 489 model.SelectRange(range); |
479 EXPECT_STR_EQ("HELLO ", model.GetSelectedText()); | 490 EXPECT_STR_EQ("HELLO ", model.GetSelectedText()); |
480 | 491 |
481 range = ui::Range(6, 1); | 492 range = ui::Range(6, 1); |
482 EXPECT_TRUE(range.is_reversed()); | 493 EXPECT_TRUE(range.is_reversed()); |
483 model.SelectRange(range); | 494 model.SelectRange(range); |
484 EXPECT_STR_EQ("ELLO ", model.GetSelectedText()); | 495 EXPECT_STR_EQ("ELLO ", model.GetSelectedText()); |
(...skipping 22 matching lines...) Expand all Loading... |
507 EXPECT_FALSE(range.is_empty()); | 518 EXPECT_FALSE(range.is_empty()); |
508 model.SelectRange(range); | 519 model.SelectRange(range); |
509 EXPECT_TRUE(model.GetSelectedText().empty()); | 520 EXPECT_TRUE(model.GetSelectedText().empty()); |
510 | 521 |
511 range = ui::Range(1000, 1000); | 522 range = ui::Range(1000, 1000); |
512 EXPECT_TRUE(range.is_empty()); | 523 EXPECT_TRUE(range.is_empty()); |
513 model.SelectRange(range); | 524 model.SelectRange(range); |
514 EXPECT_TRUE(model.GetSelectedText().empty()); | 525 EXPECT_TRUE(model.GetSelectedText().empty()); |
515 } | 526 } |
516 | 527 |
| 528 TEST_F(TextfieldViewsModelTest, CompositionTextTest) { |
| 529 TextfieldViewsModel model(this); |
| 530 model.Append(ASCIIToUTF16("1234590")); |
| 531 model.SelectRange(ui::Range(5, 5)); |
| 532 EXPECT_FALSE(model.HasSelection()); |
| 533 EXPECT_EQ(5U, model.cursor_pos()); |
| 534 |
| 535 ui::Range range; |
| 536 model.GetTextRange(&range); |
| 537 EXPECT_EQ(0U, range.start()); |
| 538 EXPECT_EQ(7U, range.end()); |
| 539 |
| 540 ui::CompositionText composition; |
| 541 composition.text = ASCIIToUTF16("678"); |
| 542 composition.underlines.push_back(ui::CompositionUnderline(0, 3, 0, false)); |
| 543 composition.selection = ui::Range(2, 3); |
| 544 model.SetCompositionText(composition); |
| 545 EXPECT_TRUE(model.HasCompositionText()); |
| 546 EXPECT_TRUE(model.HasSelection()); |
| 547 |
| 548 model.GetTextRange(&range); |
| 549 EXPECT_EQ(10U, range.end()); |
| 550 |
| 551 model.GetCompositionTextRange(&range); |
| 552 EXPECT_EQ(5U, range.start()); |
| 553 EXPECT_EQ(8U, range.end()); |
| 554 |
| 555 model.GetSelectedRange(&range); |
| 556 EXPECT_EQ(7U, range.start()); |
| 557 EXPECT_EQ(8U, range.end()); |
| 558 |
| 559 EXPECT_STR_EQ("1234567890", model.text()); |
| 560 EXPECT_STR_EQ("8", model.GetSelectedText()); |
| 561 EXPECT_STR_EQ("456", model.GetTextFromRange(ui::Range(3, 6))); |
| 562 |
| 563 TextfieldViewsModel::TextFragments fragments; |
| 564 model.GetFragments(&fragments); |
| 565 EXPECT_EQ(4U, fragments.size()); |
| 566 EXPECT_EQ(0U, fragments[0].start); |
| 567 EXPECT_EQ(5U, fragments[0].end); |
| 568 EXPECT_FALSE(fragments[0].selected); |
| 569 EXPECT_FALSE(fragments[0].underline); |
| 570 EXPECT_EQ(5U, fragments[1].start); |
| 571 EXPECT_EQ(7U, fragments[1].end); |
| 572 EXPECT_FALSE(fragments[1].selected); |
| 573 EXPECT_TRUE(fragments[1].underline); |
| 574 EXPECT_EQ(7U, fragments[2].start); |
| 575 EXPECT_EQ(8U, fragments[2].end); |
| 576 EXPECT_TRUE(fragments[2].selected); |
| 577 EXPECT_TRUE(fragments[2].underline); |
| 578 EXPECT_EQ(8U, fragments[3].start); |
| 579 EXPECT_EQ(10U, fragments[3].end); |
| 580 EXPECT_FALSE(fragments[3].selected); |
| 581 EXPECT_FALSE(fragments[3].underline); |
| 582 |
| 583 EXPECT_FALSE(composition_text_confirmed_or_cleared_); |
| 584 model.ClearCompositionText(); |
| 585 EXPECT_TRUE(composition_text_confirmed_or_cleared_); |
| 586 composition_text_confirmed_or_cleared_ = false; |
| 587 EXPECT_FALSE(model.HasCompositionText()); |
| 588 EXPECT_FALSE(model.HasSelection()); |
| 589 EXPECT_EQ(5U, model.cursor_pos()); |
| 590 |
| 591 model.SetCompositionText(composition); |
| 592 EXPECT_STR_EQ("1234567890", model.text()); |
| 593 EXPECT_TRUE(model.SetText(ASCIIToUTF16("1234567890"))); |
| 594 EXPECT_TRUE(composition_text_confirmed_or_cleared_); |
| 595 composition_text_confirmed_or_cleared_ = false; |
| 596 model.MoveCursorToEnd(false); |
| 597 |
| 598 model.SetCompositionText(composition); |
| 599 EXPECT_STR_EQ("1234567890678", model.text()); |
| 600 |
| 601 model.InsertText(UTF8ToUTF16("-")); |
| 602 EXPECT_TRUE(composition_text_confirmed_or_cleared_); |
| 603 composition_text_confirmed_or_cleared_ = false; |
| 604 EXPECT_STR_EQ("1234567890-", model.text()); |
| 605 EXPECT_FALSE(model.HasCompositionText()); |
| 606 EXPECT_FALSE(model.HasSelection()); |
| 607 |
| 608 model.MoveCursorLeft(true); |
| 609 EXPECT_STR_EQ("-", model.GetSelectedText()); |
| 610 model.SetCompositionText(composition); |
| 611 EXPECT_STR_EQ("1234567890678", model.text()); |
| 612 |
| 613 model.ReplaceText(UTF8ToUTF16("-")); |
| 614 EXPECT_TRUE(composition_text_confirmed_or_cleared_); |
| 615 composition_text_confirmed_or_cleared_ = false; |
| 616 EXPECT_STR_EQ("1234567890-", model.text()); |
| 617 EXPECT_FALSE(model.HasCompositionText()); |
| 618 EXPECT_FALSE(model.HasSelection()); |
| 619 |
| 620 model.SetCompositionText(composition); |
| 621 model.Append(UTF8ToUTF16("-")); |
| 622 EXPECT_TRUE(composition_text_confirmed_or_cleared_); |
| 623 composition_text_confirmed_or_cleared_ = false; |
| 624 EXPECT_STR_EQ("1234567890-678-", model.text()); |
| 625 |
| 626 model.SetCompositionText(composition); |
| 627 model.Delete(); |
| 628 EXPECT_TRUE(composition_text_confirmed_or_cleared_); |
| 629 composition_text_confirmed_or_cleared_ = false; |
| 630 EXPECT_STR_EQ("1234567890-678-", model.text()); |
| 631 |
| 632 model.SetCompositionText(composition); |
| 633 model.Backspace(); |
| 634 EXPECT_TRUE(composition_text_confirmed_or_cleared_); |
| 635 composition_text_confirmed_or_cleared_ = false; |
| 636 EXPECT_STR_EQ("1234567890-678-", model.text()); |
| 637 |
| 638 model.SetText(string16()); |
| 639 model.SetCompositionText(composition); |
| 640 model.MoveCursorLeft(false); |
| 641 EXPECT_TRUE(composition_text_confirmed_or_cleared_); |
| 642 composition_text_confirmed_or_cleared_ = false; |
| 643 EXPECT_STR_EQ("678", model.text()); |
| 644 EXPECT_EQ(2U, model.cursor_pos()); |
| 645 |
| 646 model.SetCompositionText(composition); |
| 647 model.MoveCursorRight(false); |
| 648 EXPECT_TRUE(composition_text_confirmed_or_cleared_); |
| 649 composition_text_confirmed_or_cleared_ = false; |
| 650 EXPECT_STR_EQ("676788", model.text()); |
| 651 EXPECT_EQ(6U, model.cursor_pos()); |
| 652 |
| 653 model.SetCompositionText(composition); |
| 654 model.MoveCursorToPreviousWord(false); |
| 655 EXPECT_TRUE(composition_text_confirmed_or_cleared_); |
| 656 composition_text_confirmed_or_cleared_ = false; |
| 657 EXPECT_STR_EQ("676788678", model.text()); |
| 658 |
| 659 model.SetText(string16()); |
| 660 model.SetCompositionText(composition); |
| 661 model.MoveCursorToNextWord(false); |
| 662 EXPECT_TRUE(composition_text_confirmed_or_cleared_); |
| 663 composition_text_confirmed_or_cleared_ = false; |
| 664 |
| 665 model.SetCompositionText(composition); |
| 666 model.MoveCursorToHome(true); |
| 667 EXPECT_TRUE(composition_text_confirmed_or_cleared_); |
| 668 composition_text_confirmed_or_cleared_ = false; |
| 669 EXPECT_STR_EQ("678678", model.text()); |
| 670 |
| 671 model.SetCompositionText(composition); |
| 672 model.MoveCursorToEnd(false); |
| 673 EXPECT_TRUE(composition_text_confirmed_or_cleared_); |
| 674 composition_text_confirmed_or_cleared_ = false; |
| 675 EXPECT_STR_EQ("678", model.text()); |
| 676 |
| 677 model.SetCompositionText(composition); |
| 678 model.MoveCursorTo(0, true); |
| 679 EXPECT_TRUE(composition_text_confirmed_or_cleared_); |
| 680 composition_text_confirmed_or_cleared_ = false; |
| 681 EXPECT_STR_EQ("678678", model.text()); |
| 682 |
| 683 model.SetCompositionText(composition); |
| 684 model.SelectRange(ui::Range(0, 3)); |
| 685 EXPECT_TRUE(composition_text_confirmed_or_cleared_); |
| 686 composition_text_confirmed_or_cleared_ = false; |
| 687 EXPECT_STR_EQ("678", model.text()); |
| 688 |
| 689 model.SetCompositionText(composition); |
| 690 model.SelectAll(); |
| 691 EXPECT_TRUE(composition_text_confirmed_or_cleared_); |
| 692 composition_text_confirmed_or_cleared_ = false; |
| 693 EXPECT_STR_EQ("678", model.text()); |
| 694 |
| 695 model.SetCompositionText(composition); |
| 696 model.SelectWord(); |
| 697 EXPECT_TRUE(composition_text_confirmed_or_cleared_); |
| 698 composition_text_confirmed_or_cleared_ = false; |
| 699 EXPECT_STR_EQ("678", model.text()); |
| 700 |
| 701 model.SetCompositionText(composition); |
| 702 model.ClearSelection(); |
| 703 EXPECT_TRUE(composition_text_confirmed_or_cleared_); |
| 704 composition_text_confirmed_or_cleared_ = false; |
| 705 |
| 706 model.SetCompositionText(composition); |
| 707 EXPECT_FALSE(model.Cut()); |
| 708 EXPECT_FALSE(composition_text_confirmed_or_cleared_); |
| 709 } |
| 710 |
517 } // namespace views | 711 } // namespace views |
OLD | NEW |