OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2012 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/base/win/tsf_text_store.h" | |
6 | |
7 #include "base/win/scoped_com_initializer.h" | |
8 #include "testing/gtest/include/gtest/gtest.h" | |
9 #include "testing/gmock/include/gmock/gmock.h" | |
10 #include "ui/base/ime/text_input_client.h" | |
11 #include "ui/gfx/rect.h" | |
12 | |
13 using testing::_; | |
14 using testing::Invoke; | |
15 using testing::Return; | |
16 | |
17 namespace ui { | |
18 | |
19 namespace { | |
20 class MockTextInputClient : public TextInputClient { | |
21 public: | |
22 ~MockTextInputClient() {} | |
23 MOCK_METHOD1(SetCompositionText, void(const ui::CompositionText&)); | |
24 MOCK_METHOD0(ConfirmCompositionText, void()); | |
25 MOCK_METHOD0(ClearCompositionText, void()); | |
26 MOCK_METHOD1(InsertText, void(const string16&)); | |
27 MOCK_METHOD2(InsertChar, void(char16, int)); | |
28 MOCK_CONST_METHOD0(GetTextInputType, ui::TextInputType()); | |
29 MOCK_CONST_METHOD0(CanComposeInline, bool()); | |
30 MOCK_METHOD0(GetCaretBounds, gfx::Rect()); | |
31 MOCK_METHOD2(GetCompositionCharacterBounds, bool(uint32, gfx::Rect*)); | |
32 MOCK_METHOD0(HasCompositionText, bool()); | |
33 MOCK_METHOD1(GetTextRange, bool(ui::Range*)); | |
34 MOCK_METHOD1(GetCompositionTextRange, bool(ui::Range*)); | |
35 MOCK_METHOD1(GetSelectionRange, bool(ui::Range*)); | |
36 MOCK_METHOD1(SetSelectionRange, bool(const ui::Range&)); | |
37 MOCK_METHOD1(DeleteRange, bool(const ui::Range&)); | |
38 MOCK_METHOD2(GetTextFromRange, bool(const ui::Range&, string16*)); | |
39 MOCK_METHOD0(OnInputMethodChanged, void()); | |
40 MOCK_METHOD1(ChangeTextDirectionAndLayoutAlignment, | |
41 bool(base::i18n::TextDirection)); | |
42 }; | |
43 | |
44 class MockStoreACPSink : public ITextStoreACPSink { | |
45 public: | |
46 MockStoreACPSink() : ref_count_(0) { | |
47 } | |
48 | |
49 // IUnknown | |
50 virtual ULONG STDMETHODCALLTYPE AddRef() OVERRIDE { | |
51 return InterlockedIncrement(&ref_count_); | |
52 } | |
53 virtual ULONG STDMETHODCALLTYPE Release() OVERRIDE { | |
54 const LONG count = InterlockedDecrement(&ref_count_); | |
55 if (!count) { | |
56 delete this; | |
57 return 0; | |
58 } | |
59 return static_cast<ULONG>(count); | |
60 } | |
61 virtual HRESULT STDMETHODCALLTYPE QueryInterface( | |
62 REFIID iid, void** report) OVERRIDE { | |
63 if (iid == IID_IUnknown || iid == IID_ITextStoreACPSink) { | |
64 *report = static_cast<ITextStoreACPSink*>(this); | |
65 } else { | |
66 *report = NULL; | |
67 return E_NOINTERFACE; | |
68 } | |
69 AddRef(); | |
70 return S_OK; | |
71 } | |
72 | |
73 // ITextStoreACPSink | |
74 MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, OnTextChange, | |
75 HRESULT(DWORD, const TS_TEXTCHANGE*)); | |
76 MOCK_METHOD0_WITH_CALLTYPE(STDMETHODCALLTYPE, OnSelectionChange, | |
77 HRESULT()); | |
78 MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, OnLayoutChange, | |
79 HRESULT(TsLayoutCode, TsViewCookie)); | |
80 MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, OnStatusChange, | |
81 HRESULT(DWORD)); | |
82 MOCK_METHOD4_WITH_CALLTYPE(STDMETHODCALLTYPE, OnAttrsChange, | |
83 HRESULT(LONG, LONG, ULONG, const TS_ATTRID*)); | |
84 MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, OnLockGranted, | |
85 HRESULT(DWORD)); | |
86 MOCK_METHOD0_WITH_CALLTYPE(STDMETHODCALLTYPE, OnStartEditTransaction, | |
87 HRESULT()); | |
88 MOCK_METHOD0_WITH_CALLTYPE(STDMETHODCALLTYPE, OnEndEditTransaction, | |
89 HRESULT()); | |
90 | |
91 private: | |
92 ~MockStoreACPSink() { | |
93 } | |
94 | |
95 volatile LONG ref_count_; | |
96 }; | |
97 | |
98 } // namespace | |
99 | |
100 class TsfTextStoreTest : public testing::Test { | |
101 protected: | |
102 virtual void SetUp() OVERRIDE { | |
103 text_store_ = new TsfTextStore(); | |
104 text_store_->AddRef(); | |
105 sink_ = new MockStoreACPSink(); | |
106 sink_->AddRef(); | |
107 EXPECT_EQ(S_OK, text_store_->AdviseSink(IID_ITextStoreACPSink, | |
108 sink_, TS_AS_ALL_SINKS)); | |
109 text_store_->SetFocusedTextInputClient(0, &text_input_client_); | |
110 } | |
111 | |
112 virtual void TearDown() OVERRIDE { | |
113 EXPECT_EQ(S_OK, text_store_->UnadviseSink(sink_)); | |
114 sink_->Release(); | |
115 text_store_->Release(); | |
116 } | |
117 | |
118 base::win::ScopedCOMInitializer com_initializer_; | |
119 MockTextInputClient text_input_client_; | |
120 TsfTextStore* text_store_; | |
121 MockStoreACPSink* sink_; | |
122 }; | |
123 | |
124 class TsfTextStoreTestCallback { | |
125 public: | |
126 explicit TsfTextStoreTestCallback(TsfTextStore* text_store) | |
127 : text_store_(text_store) { | |
128 CHECK(text_store_); | |
129 } | |
130 virtual ~TsfTextStoreTestCallback() {} | |
131 | |
132 protected: | |
133 // Accessors to the internal state of TsfTextStore. | |
134 bool* edit_flag() { return &text_store_->edit_flag_; } | |
135 string16* string_buffer() { return &text_store_->string_buffer_; } | |
136 size_t* committed_size() { return &text_store_->committed_size_; } | |
137 Range* selection() { return &text_store_->selection_; } | |
138 CompositionUnderlines* composition_undelines() { | |
139 return &text_store_->composition_undelines_; | |
140 } | |
141 | |
142 TsfTextStore* text_store_; | |
143 }; | |
144 | |
145 class SelectionTestCallback : public TsfTextStoreTestCallback { | |
146 public: | |
147 explicit SelectionTestCallback(TsfTextStore* text_store) | |
148 : TsfTextStoreTestCallback(text_store) { | |
149 } | |
150 | |
151 HRESULT ReadLockGranted(DWORD flags) { | |
152 *string_buffer() = L""; | |
153 *committed_size() = 0; | |
154 selection()->set_start(0); | |
155 selection()->set_end(0); | |
156 | |
157 GetSelectionTest(0, 0); | |
158 SetSelectionTest(0, 0, TF_E_NOLOCK); | |
159 | |
160 *string_buffer() = L"012345"; | |
161 *committed_size() = 0; | |
162 selection()->set_start(0); | |
163 selection()->set_end(3); | |
164 | |
165 GetSelectionTest(0, 3); | |
166 SetSelectionTest(0, 0, TF_E_NOLOCK); | |
167 | |
168 return S_OK; | |
169 } | |
170 | |
171 HRESULT ReadWriteLockGranted(DWORD flags) { | |
172 *string_buffer() = L""; | |
173 *committed_size() = 0; | |
174 selection()->set_start(0); | |
175 selection()->set_end(0); | |
176 | |
177 SetSelectionTest(0, 0, S_OK); | |
178 GetSelectionTest(0, 0); | |
179 SetSelectionTest(0, 1, TF_E_INVALIDPOS); | |
180 GetSelectionTest(0, 0); | |
181 SetSelectionTest(1, 0, TF_E_INVALIDPOS); | |
182 GetSelectionTest(0, 0); | |
183 SetSelectionTest(1, 1, TF_E_INVALIDPOS); | |
184 GetSelectionTest(0, 0); | |
185 | |
186 *string_buffer() = L"012345"; | |
187 *committed_size() = 0; | |
188 selection()->set_start(0); | |
189 selection()->set_end(0); | |
190 | |
191 SetSelectionTest(0, 0, S_OK); | |
192 GetSelectionTest(0, 0); | |
193 SetSelectionTest(0, 3, S_OK); | |
194 GetSelectionTest(0, 3); | |
195 SetSelectionTest(0, 6, S_OK); | |
196 GetSelectionTest(0, 6); | |
197 SetSelectionTest(0, 7, TF_E_INVALIDPOS); | |
198 GetSelectionTest(0, 6); | |
199 | |
200 SetSelectionTest(3, 0, TF_E_INVALIDPOS); | |
201 GetSelectionTest(0, 6); | |
202 SetSelectionTest(3, 3, S_OK); | |
203 GetSelectionTest(3, 3); | |
204 SetSelectionTest(3, 6, S_OK); | |
205 GetSelectionTest(3, 6); | |
206 SetSelectionTest(3, 7, TF_E_INVALIDPOS); | |
207 GetSelectionTest(3, 6); | |
208 | |
209 SetSelectionTest(6, 0, TF_E_INVALIDPOS); | |
210 GetSelectionTest(3, 6); | |
211 SetSelectionTest(6, 3, TF_E_INVALIDPOS); | |
212 GetSelectionTest(3, 6); | |
213 SetSelectionTest(6, 6, S_OK); | |
214 GetSelectionTest(6, 6); | |
215 SetSelectionTest(6, 7, TF_E_INVALIDPOS); | |
216 GetSelectionTest(6, 6); | |
217 | |
218 return S_OK; | |
219 } | |
220 | |
221 private: | |
222 void SetSelectionTest(LONG acp_start, LONG acp_end, HRESULT expected_result) { | |
223 TS_SELECTION_ACP selection; | |
224 selection.acpStart = acp_start; | |
225 selection.acpEnd = acp_end; | |
226 selection.style.ase = TS_AE_NONE; | |
227 selection.style.fInterimChar = 0; | |
228 EXPECT_EQ(expected_result, text_store_->SetSelection(1, &selection)); | |
229 } | |
230 | |
231 void GetSelectionTest(LONG expected_acp_start, LONG expected_acp_end) { | |
232 TS_SELECTION_ACP selection; | |
233 ULONG fetched; | |
234 EXPECT_EQ(S_OK, text_store_->GetSelection(0, 1, &selection, &fetched)); | |
235 EXPECT_EQ(1, fetched); | |
236 EXPECT_EQ(expected_acp_start, selection.acpStart); | |
237 EXPECT_EQ(expected_acp_end, selection.acpEnd); | |
238 } | |
239 }; | |
240 | |
241 TEST_F(TsfTextStoreTest, GetStatusTest) { | |
242 TS_STATUS status; | |
243 EXPECT_EQ(S_OK, text_store_->GetStatus(&status)); | |
244 EXPECT_EQ(0, status.dwDynamicFlags); | |
245 EXPECT_EQ(TS_SS_NOHIDDENTEXT, status.dwStaticFlags); | |
246 } | |
247 | |
248 TEST_F(TsfTextStoreTest, SetGetSelectionTest) { | |
249 SelectionTestCallback callback(text_store_); | |
250 EXPECT_CALL(*sink_, OnLockGranted(_)) | |
251 .WillOnce(Invoke(&callback, &SelectionTestCallback::ReadLockGranted)) | |
252 .WillOnce(Invoke(&callback, | |
253 &SelectionTestCallback::ReadWriteLockGranted)); | |
254 | |
255 TS_SELECTION_ACP selection_buffer; | |
256 ULONG fetched_count; | |
257 EXPECT_EQ(TS_E_NOLOCK, | |
258 text_store_->GetSelection(0, 1, &selection_buffer, | |
259 &fetched_count)); | |
260 | |
261 HRESULT result; | |
262 EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READ, &result)); | |
263 EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READWRITE, &result)); | |
264 } | |
cpu_(ooo_6.6-7.5)
2012/08/23 19:36:45
how aboout testing also when you call
RequestLoc
horo
2012/08/24 11:42:23
Done.
| |
265 | |
266 class SenarioTestCallback : public TsfTextStoreTestCallback { | |
267 public: | |
268 explicit SenarioTestCallback(TsfTextStore* text_store) | |
269 : TsfTextStoreTestCallback(text_store) { | |
270 } | |
271 | |
272 HRESULT LockGranted1(DWORD flags) { | |
273 TS_SELECTION_ACP selection; | |
274 selection.acpStart = 0; | |
275 selection.acpEnd = 0; | |
276 selection.style.ase = TS_AE_NONE; | |
277 selection.style.fInterimChar = 0; | |
278 EXPECT_EQ(S_OK, text_store_->SetSelection(1, &selection)); | |
279 TS_TEXTCHANGE change; | |
280 EXPECT_EQ(S_OK, text_store_->SetText(0, 0, 0, L"abc", 3, &change)); | |
281 EXPECT_EQ(0, change.acpStart); | |
282 EXPECT_EQ(0, change.acpOldEnd); | |
283 EXPECT_EQ(3, change.acpNewEnd); | |
284 | |
285 EXPECT_EQ(S_OK, text_store_->SetText(0, 1, 2, L"xyz", 3, &change)); | |
286 EXPECT_EQ(1, change.acpStart); | |
287 EXPECT_EQ(2, change.acpOldEnd); | |
288 EXPECT_EQ(4, change.acpNewEnd); | |
289 | |
290 wchar_t buffer[1024]; | |
291 ULONG text_buffer_copied; | |
292 TS_RUNINFO run_info; | |
293 ULONG run_info_buffer_copied; | |
294 LONG next_acp; | |
295 EXPECT_EQ(S_OK, | |
296 text_store_->GetText(0, -1, buffer, 1024, &text_buffer_copied, | |
297 &run_info, 1, &run_info_buffer_copied, | |
298 &next_acp)); | |
299 EXPECT_EQ(5, text_buffer_copied); | |
300 EXPECT_EQ(L"axyzc", string16(buffer, buffer + text_buffer_copied)); | |
301 EXPECT_EQ(1, run_info_buffer_copied); | |
302 EXPECT_EQ(TS_RT_PLAIN, run_info.type); | |
303 EXPECT_EQ(5, run_info.uCount); | |
304 EXPECT_EQ(5, next_acp); | |
305 | |
306 composition_undelines()->clear(); | |
307 CompositionUnderline underline; | |
308 underline.start_offset = 0; | |
309 underline.end_offset = 5; | |
310 underline.color = SK_ColorBLACK; | |
311 underline.thick = false; | |
312 composition_undelines()->push_back(underline); | |
313 *edit_flag() = true; | |
314 *committed_size() = 0; | |
315 return S_OK; | |
316 } | |
317 | |
318 void SetCompositionText1(const ui::CompositionText& composition) { | |
319 EXPECT_EQ(L"axyzc", composition.text); | |
320 EXPECT_EQ(1, composition.selection.start()); | |
321 EXPECT_EQ(4, composition.selection.end()); | |
322 ASSERT_EQ(1, composition.underlines.size()); | |
323 EXPECT_EQ(SK_ColorBLACK, composition.underlines[0].color); | |
324 EXPECT_EQ(0, composition.underlines[0].start_offset); | |
325 EXPECT_EQ(5, composition.underlines[0].end_offset); | |
326 EXPECT_FALSE(composition.underlines[0].thick); | |
327 } | |
328 | |
329 HRESULT LockGranted2(DWORD flags) { | |
330 TS_TEXTCHANGE change; | |
331 EXPECT_EQ(S_OK, text_store_->SetText(0, 3, 4, L"ZCP", 3, &change)); | |
332 EXPECT_EQ(3, change.acpStart); | |
333 EXPECT_EQ(4, change.acpOldEnd); | |
334 EXPECT_EQ(6, change.acpNewEnd); | |
335 | |
336 wchar_t buffer[1024]; | |
337 ULONG text_buffer_copied; | |
338 TS_RUNINFO run_info; | |
339 ULONG run_info_buffer_copied; | |
340 LONG next_acp; | |
341 EXPECT_EQ(S_OK, | |
342 text_store_->GetText(0, -1, buffer, 1024, &text_buffer_copied, | |
343 &run_info, 1, &run_info_buffer_copied, | |
344 &next_acp)); | |
345 EXPECT_EQ(7, text_buffer_copied); | |
346 EXPECT_EQ(L"axyZCPc", string16(buffer, buffer + text_buffer_copied)); | |
347 EXPECT_EQ(1, run_info_buffer_copied); | |
348 EXPECT_EQ(TS_RT_PLAIN, run_info.type); | |
349 EXPECT_EQ(7, run_info.uCount); | |
350 EXPECT_EQ(7, next_acp); | |
351 | |
352 composition_undelines()->clear(); | |
353 CompositionUnderline underline; | |
354 underline.start_offset = 3; | |
355 underline.end_offset = 5; | |
356 underline.color = SK_ColorBLACK; | |
357 underline.thick = true; | |
358 composition_undelines()->push_back(underline); | |
359 underline.start_offset = 5; | |
360 underline.end_offset = 7; | |
361 underline.color = SK_ColorBLACK; | |
362 underline.thick = false; | |
363 composition_undelines()->push_back(underline); | |
364 | |
365 *edit_flag() = true; | |
366 *committed_size() = 3; | |
367 | |
368 return S_OK; | |
369 } | |
370 | |
371 void InsertText2(const string16& text) { | |
372 EXPECT_EQ(L"axy", text); | |
373 } | |
374 | |
375 void SetCompositionText2(const ui::CompositionText& composition) { | |
376 EXPECT_EQ(L"ZCPc", composition.text); | |
377 EXPECT_EQ(0, composition.selection.start()); | |
378 EXPECT_EQ(3, composition.selection.end()); | |
379 ASSERT_EQ(2, composition.underlines.size()); | |
380 EXPECT_EQ(SK_ColorBLACK, composition.underlines[0].color); | |
381 EXPECT_EQ(0, composition.underlines[0].start_offset); | |
382 EXPECT_EQ(2, composition.underlines[0].end_offset); | |
383 EXPECT_TRUE(composition.underlines[0].thick); | |
384 EXPECT_EQ(SK_ColorBLACK, composition.underlines[1].color); | |
385 EXPECT_EQ(2, composition.underlines[1].start_offset); | |
386 EXPECT_EQ(4, composition.underlines[1].end_offset); | |
387 EXPECT_FALSE(composition.underlines[1].thick); | |
388 } | |
389 | |
390 HRESULT LockGranted3(DWORD flags) { | |
391 wchar_t buffer[1024]; | |
392 ULONG text_buffer_copied; | |
393 TS_RUNINFO run_info; | |
394 ULONG run_info_buffer_copied; | |
395 LONG next_acp; | |
396 EXPECT_EQ(S_OK, | |
397 text_store_->GetText(0, -1, buffer, 1024, &text_buffer_copied, | |
398 &run_info, 1, &run_info_buffer_copied, | |
399 &next_acp)); | |
400 EXPECT_EQ(7, text_buffer_copied); | |
401 EXPECT_EQ(L"axyZCPc", string16(buffer, buffer + text_buffer_copied)); | |
402 EXPECT_EQ(1, run_info_buffer_copied); | |
403 EXPECT_EQ(TS_RT_PLAIN, run_info.type); | |
404 EXPECT_EQ(7, run_info.uCount); | |
405 EXPECT_EQ(7, next_acp); | |
406 | |
407 composition_undelines()->clear(); | |
408 *edit_flag() = true; | |
409 *committed_size() = 7; | |
410 | |
411 return S_OK; | |
412 } | |
413 | |
414 void InsertText3(const string16& text) { | |
415 EXPECT_EQ(L"ZCPc", text); | |
416 } | |
417 | |
418 void SetCompositionText3(const ui::CompositionText& composition) { | |
419 EXPECT_EQ(L"", composition.text); | |
420 EXPECT_EQ(0, composition.selection.start()); | |
421 EXPECT_EQ(0, composition.selection.end()); | |
422 EXPECT_EQ(0, composition.underlines.size()); | |
423 } | |
424 }; | |
425 | |
426 TEST_F(TsfTextStoreTest, SenarioTest) { | |
cpu_(ooo_6.6-7.5)
2012/08/23 19:36:45
Scenario ?
horo
2012/08/24 11:42:23
Done.
| |
427 SenarioTestCallback callback(text_store_); | |
428 EXPECT_CALL(text_input_client_, SetCompositionText(_)) | |
429 .WillOnce(Invoke(&callback, &SenarioTestCallback::SetCompositionText1)) | |
430 .WillOnce(Invoke(&callback, &SenarioTestCallback::SetCompositionText2)) | |
431 .WillOnce(Invoke(&callback, &SenarioTestCallback::SetCompositionText3)); | |
432 | |
433 EXPECT_CALL(text_input_client_, InsertText(_)) | |
434 .WillOnce(Invoke(&callback, &SenarioTestCallback::InsertText2)) | |
435 .WillOnce(Invoke(&callback, &SenarioTestCallback::InsertText3)); | |
436 | |
437 EXPECT_CALL(*sink_, OnLockGranted(_)) | |
438 .WillOnce(Invoke(&callback, &SenarioTestCallback::LockGranted1)) | |
439 .WillOnce(Invoke(&callback, &SenarioTestCallback::LockGranted2)) | |
440 .WillOnce(Invoke(&callback, &SenarioTestCallback::LockGranted3)); | |
441 | |
442 // OnSelectionChange will be called once in LockGranted3(). | |
443 EXPECT_CALL(*sink_, OnSelectionChange()) | |
444 .WillOnce(Return(S_OK)); | |
445 | |
446 // OnLayoutChange will be called once in LockGranted3(). | |
447 EXPECT_CALL(*sink_, OnLayoutChange(_, _)) | |
448 .WillOnce(Return(S_OK)); | |
449 | |
450 // OnTextChange will be called once in LockGranted3(). | |
451 EXPECT_CALL(*sink_, OnTextChange(_, _)) | |
452 .WillOnce(Return(S_OK)); | |
453 | |
454 HRESULT result; | |
455 EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READWRITE, &result)); | |
456 EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READWRITE, &result)); | |
457 EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READWRITE, &result)); | |
458 } | |
459 | |
460 } // namespace ui | |
OLD | NEW |