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/ime/win/tsf_text_store.h" | |
6 | |
7 #include <initguid.h> // for GUID_NULL and GUID_PROP_INPUTSCOPE | |
8 #include <InputScope.h> | |
9 #include <OleCtl.h> | |
10 | |
11 #include "base/memory/ref_counted.h" | |
12 #include "base/win/scoped_com_initializer.h" | |
13 #include "base/win/scoped_variant.h" | |
14 #include "testing/gtest/include/gtest/gtest.h" | |
15 #include "testing/gmock/include/gmock/gmock.h" | |
16 #include "ui/base/ime/text_input_client.h" | |
17 #include "ui/gfx/rect.h" | |
18 | |
19 using testing::_; | |
20 using testing::Invoke; | |
21 using testing::Return; | |
22 | |
23 namespace ui { | |
24 namespace { | |
25 | |
26 class MockTextInputClient : public TextInputClient { | |
27 public: | |
28 ~MockTextInputClient() {} | |
29 MOCK_METHOD1(SetCompositionText, void(const ui::CompositionText&)); | |
30 MOCK_METHOD0(ConfirmCompositionText, void()); | |
31 MOCK_METHOD0(ClearCompositionText, void()); | |
32 MOCK_METHOD1(InsertText, void(const base::string16&)); | |
33 MOCK_METHOD2(InsertChar, void(base::char16, int)); | |
34 MOCK_CONST_METHOD0(GetAttachedWindow, gfx::NativeWindow()); | |
35 MOCK_CONST_METHOD0(GetTextInputType, ui::TextInputType()); | |
36 MOCK_CONST_METHOD0(GetTextInputMode, ui::TextInputMode()); | |
37 MOCK_CONST_METHOD0(CanComposeInline, bool()); | |
38 MOCK_CONST_METHOD0(GetCaretBounds, gfx::Rect()); | |
39 MOCK_CONST_METHOD2(GetCompositionCharacterBounds, bool(uint32, gfx::Rect*)); | |
40 MOCK_CONST_METHOD0(HasCompositionText, bool()); | |
41 MOCK_CONST_METHOD1(GetTextRange, bool(gfx::Range*)); | |
42 MOCK_CONST_METHOD1(GetCompositionTextRange, bool(gfx::Range*)); | |
43 MOCK_CONST_METHOD1(GetSelectionRange, bool(gfx::Range*)); | |
44 MOCK_METHOD1(SetSelectionRange, bool(const gfx::Range&)); | |
45 MOCK_METHOD1(DeleteRange, bool(const gfx::Range&)); | |
46 MOCK_CONST_METHOD2(GetTextFromRange, bool(const gfx::Range&, | |
47 base::string16*)); | |
48 MOCK_METHOD0(OnInputMethodChanged, void()); | |
49 MOCK_METHOD1(ChangeTextDirectionAndLayoutAlignment, | |
50 bool(base::i18n::TextDirection)); | |
51 MOCK_METHOD2(ExtendSelectionAndDelete, void(size_t, size_t)); | |
52 MOCK_METHOD1(EnsureCaretInRect, void(const gfx::Rect&)); | |
53 MOCK_METHOD0(OnCandidateWindowShown, void()); | |
54 MOCK_METHOD0(OnCandidateWindowUpdated, void()); | |
55 MOCK_METHOD0(OnCandidateWindowHidden, void()); | |
56 }; | |
57 | |
58 class MockStoreACPSink : public ITextStoreACPSink { | |
59 public: | |
60 MockStoreACPSink() : ref_count_(0) {} | |
61 | |
62 // IUnknown | |
63 virtual ULONG STDMETHODCALLTYPE AddRef() OVERRIDE { | |
64 return InterlockedIncrement(&ref_count_); | |
65 } | |
66 virtual ULONG STDMETHODCALLTYPE Release() OVERRIDE { | |
67 const LONG count = InterlockedDecrement(&ref_count_); | |
68 if (!count) { | |
69 delete this; | |
70 return 0; | |
71 } | |
72 return static_cast<ULONG>(count); | |
73 } | |
74 virtual HRESULT STDMETHODCALLTYPE QueryInterface( | |
75 REFIID iid, void** report) OVERRIDE { | |
76 if (iid == IID_IUnknown || iid == IID_ITextStoreACPSink) { | |
77 *report = static_cast<ITextStoreACPSink*>(this); | |
78 } else { | |
79 *report = NULL; | |
80 return E_NOINTERFACE; | |
81 } | |
82 AddRef(); | |
83 return S_OK; | |
84 } | |
85 | |
86 // ITextStoreACPSink | |
87 MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, OnTextChange, | |
88 HRESULT(DWORD, const TS_TEXTCHANGE*)); | |
89 MOCK_METHOD0_WITH_CALLTYPE(STDMETHODCALLTYPE, OnSelectionChange, | |
90 HRESULT()); | |
91 MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, OnLayoutChange, | |
92 HRESULT(TsLayoutCode, TsViewCookie)); | |
93 MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, OnStatusChange, | |
94 HRESULT(DWORD)); | |
95 MOCK_METHOD4_WITH_CALLTYPE(STDMETHODCALLTYPE, OnAttrsChange, | |
96 HRESULT(LONG, LONG, ULONG, const TS_ATTRID*)); | |
97 MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, OnLockGranted, | |
98 HRESULT(DWORD)); | |
99 MOCK_METHOD0_WITH_CALLTYPE(STDMETHODCALLTYPE, OnStartEditTransaction, | |
100 HRESULT()); | |
101 MOCK_METHOD0_WITH_CALLTYPE(STDMETHODCALLTYPE, OnEndEditTransaction, | |
102 HRESULT()); | |
103 | |
104 private: | |
105 virtual ~MockStoreACPSink() {} | |
106 | |
107 volatile LONG ref_count_; | |
108 }; | |
109 | |
110 const HWND kWindowHandle = reinterpret_cast<HWND>(1); | |
111 | |
112 } // namespace | |
113 | |
114 class TSFTextStoreTest : public testing::Test { | |
115 protected: | |
116 virtual void SetUp() OVERRIDE { | |
117 text_store_ = new TSFTextStore(); | |
118 sink_ = new MockStoreACPSink(); | |
119 EXPECT_EQ(S_OK, text_store_->AdviseSink(IID_ITextStoreACPSink, | |
120 sink_, TS_AS_ALL_SINKS)); | |
121 text_store_->SetFocusedTextInputClient(kWindowHandle, | |
122 &text_input_client_); | |
123 } | |
124 | |
125 virtual void TearDown() OVERRIDE { | |
126 EXPECT_EQ(S_OK, text_store_->UnadviseSink(sink_)); | |
127 sink_ = NULL; | |
128 text_store_ = NULL; | |
129 } | |
130 | |
131 // Accessors to the internal state of TSFTextStore. | |
132 base::string16* string_buffer() { return &text_store_->string_buffer_; } | |
133 size_t* committed_size() { return &text_store_->committed_size_; } | |
134 | |
135 base::win::ScopedCOMInitializer com_initializer_; | |
136 MockTextInputClient text_input_client_; | |
137 scoped_refptr<TSFTextStore> text_store_; | |
138 scoped_refptr<MockStoreACPSink> sink_; | |
139 }; | |
140 | |
141 class TSFTextStoreTestCallback { | |
142 public: | |
143 explicit TSFTextStoreTestCallback(TSFTextStore* text_store) | |
144 : text_store_(text_store) { | |
145 CHECK(text_store_); | |
146 } | |
147 virtual ~TSFTextStoreTestCallback() {} | |
148 | |
149 protected: | |
150 // Accessors to the internal state of TSFTextStore. | |
151 bool* edit_flag() { return &text_store_->edit_flag_; } | |
152 base::string16* string_buffer() { return &text_store_->string_buffer_; } | |
153 size_t* committed_size() { return &text_store_->committed_size_; } | |
154 gfx::Range* selection() { return &text_store_->selection_; } | |
155 CompositionUnderlines* composition_undelines() { | |
156 return &text_store_->composition_undelines_; | |
157 } | |
158 | |
159 void SetInternalState(const base::string16& new_string_buffer, | |
160 LONG new_committed_size, LONG new_selection_start, | |
161 LONG new_selection_end) { | |
162 ASSERT_LE(0, new_committed_size); | |
163 ASSERT_LE(new_committed_size, new_selection_start); | |
164 ASSERT_LE(new_selection_start, new_selection_end); | |
165 ASSERT_LE(new_selection_end, static_cast<LONG>(new_string_buffer.size())); | |
166 *string_buffer() = new_string_buffer; | |
167 *committed_size() = new_committed_size; | |
168 selection()->set_start(new_selection_start); | |
169 selection()->set_end(new_selection_end); | |
170 } | |
171 | |
172 bool HasReadLock() const { return text_store_->HasReadLock(); } | |
173 bool HasReadWriteLock() const { return text_store_->HasReadWriteLock(); } | |
174 | |
175 void GetSelectionTest(LONG expected_acp_start, LONG expected_acp_end) { | |
176 TS_SELECTION_ACP selection = {}; | |
177 ULONG fetched = 0; | |
178 EXPECT_EQ(S_OK, text_store_->GetSelection(0, 1, &selection, &fetched)); | |
179 EXPECT_EQ(1, fetched); | |
180 EXPECT_EQ(expected_acp_start, selection.acpStart); | |
181 EXPECT_EQ(expected_acp_end, selection.acpEnd); | |
182 } | |
183 | |
184 void SetSelectionTest(LONG acp_start, LONG acp_end, HRESULT expected_result) { | |
185 TS_SELECTION_ACP selection = {}; | |
186 selection.acpStart = acp_start; | |
187 selection.acpEnd = acp_end; | |
188 selection.style.ase = TS_AE_NONE; | |
189 selection.style.fInterimChar = 0; | |
190 EXPECT_EQ(expected_result, text_store_->SetSelection(1, &selection)); | |
191 if (expected_result == S_OK) { | |
192 GetSelectionTest(acp_start, acp_end); | |
193 } | |
194 } | |
195 | |
196 void SetTextTest(LONG acp_start, LONG acp_end, | |
197 const base::string16& text, HRESULT error_code) { | |
198 TS_TEXTCHANGE change = {}; | |
199 ASSERT_EQ(error_code, | |
200 text_store_->SetText(0, acp_start, acp_end, | |
201 text.c_str(), text.size(), &change)); | |
202 if (error_code == S_OK) { | |
203 EXPECT_EQ(acp_start, change.acpStart); | |
204 EXPECT_EQ(acp_end, change.acpOldEnd); | |
205 EXPECT_EQ(acp_start + text.size(), change.acpNewEnd); | |
206 } | |
207 } | |
208 | |
209 void GetTextTest(LONG acp_start, LONG acp_end, | |
210 const base::string16& expected_string, | |
211 LONG expected_next_acp) { | |
212 wchar_t buffer[1024] = {}; | |
213 ULONG text_buffer_copied = 0; | |
214 TS_RUNINFO run_info = {}; | |
215 ULONG run_info_buffer_copied = 0; | |
216 LONG next_acp = 0; | |
217 ASSERT_EQ(S_OK, | |
218 text_store_->GetText(acp_start, acp_end, buffer, 1024, | |
219 &text_buffer_copied, | |
220 &run_info, 1, &run_info_buffer_copied, | |
221 &next_acp)); | |
222 ASSERT_EQ(expected_string.size(), text_buffer_copied); | |
223 EXPECT_EQ(expected_string, | |
224 base::string16(buffer, buffer + text_buffer_copied)); | |
225 EXPECT_EQ(1, run_info_buffer_copied); | |
226 EXPECT_EQ(expected_string.size(), run_info.uCount); | |
227 EXPECT_EQ(TS_RT_PLAIN, run_info.type); | |
228 EXPECT_EQ(expected_next_acp, next_acp); | |
229 } | |
230 | |
231 void GetTextErrorTest(LONG acp_start, LONG acp_end, HRESULT error_code) { | |
232 wchar_t buffer[1024] = {}; | |
233 ULONG text_buffer_copied = 0; | |
234 TS_RUNINFO run_info = {}; | |
235 ULONG run_info_buffer_copied = 0; | |
236 LONG next_acp = 0; | |
237 EXPECT_EQ(error_code, | |
238 text_store_->GetText(acp_start, acp_end, buffer, 1024, | |
239 &text_buffer_copied, | |
240 &run_info, 1, &run_info_buffer_copied, | |
241 &next_acp)); | |
242 } | |
243 | |
244 void InsertTextAtSelectionTest(const wchar_t* buffer, ULONG buffer_size, | |
245 LONG expected_start, LONG expected_end, | |
246 LONG expected_change_start, | |
247 LONG expected_change_old_end, | |
248 LONG expected_change_new_end) { | |
249 LONG start = 0; | |
250 LONG end = 0; | |
251 TS_TEXTCHANGE change = {}; | |
252 EXPECT_EQ(S_OK, | |
253 text_store_->InsertTextAtSelection(0, buffer, buffer_size, | |
254 &start, &end, &change)); | |
255 EXPECT_EQ(expected_start, start); | |
256 EXPECT_EQ(expected_end, end); | |
257 EXPECT_EQ(expected_change_start, change.acpStart); | |
258 EXPECT_EQ(expected_change_old_end, change.acpOldEnd); | |
259 EXPECT_EQ(expected_change_new_end, change.acpNewEnd); | |
260 } | |
261 | |
262 void InsertTextAtSelectionQueryOnlyTest(const wchar_t* buffer, | |
263 ULONG buffer_size, | |
264 LONG expected_start, | |
265 LONG expected_end) { | |
266 LONG start = 0; | |
267 LONG end = 0; | |
268 EXPECT_EQ(S_OK, | |
269 text_store_->InsertTextAtSelection(TS_IAS_QUERYONLY, buffer, | |
270 buffer_size, &start, &end, | |
271 NULL)); | |
272 EXPECT_EQ(expected_start, start); | |
273 EXPECT_EQ(expected_end, end); | |
274 } | |
275 | |
276 void GetTextExtTest(TsViewCookie view_cookie, LONG acp_start, LONG acp_end, | |
277 LONG expected_left, LONG expected_top, | |
278 LONG expected_right, LONG expected_bottom) { | |
279 RECT rect = {}; | |
280 BOOL clipped = FALSE; | |
281 EXPECT_EQ(S_OK, text_store_->GetTextExt(view_cookie, acp_start, acp_end, | |
282 &rect, &clipped)); | |
283 EXPECT_EQ(expected_left, rect.left); | |
284 EXPECT_EQ(expected_top, rect.top); | |
285 EXPECT_EQ(expected_right, rect.right); | |
286 EXPECT_EQ(expected_bottom, rect.bottom); | |
287 EXPECT_EQ(FALSE, clipped); | |
288 } | |
289 | |
290 void GetTextExtNoLayoutTest(TsViewCookie view_cookie, LONG acp_start, | |
291 LONG acp_end) { | |
292 RECT rect = {}; | |
293 BOOL clipped = FALSE; | |
294 EXPECT_EQ(TS_E_NOLAYOUT, | |
295 text_store_->GetTextExt(view_cookie, acp_start, acp_end, | |
296 &rect, &clipped)); | |
297 } | |
298 | |
299 scoped_refptr<TSFTextStore> text_store_; | |
300 | |
301 private: | |
302 DISALLOW_COPY_AND_ASSIGN(TSFTextStoreTestCallback); | |
303 }; | |
304 | |
305 namespace { | |
306 | |
307 const HRESULT kInvalidResult = 0x12345678; | |
308 | |
309 TEST_F(TSFTextStoreTest, GetStatusTest) { | |
310 TS_STATUS status = {}; | |
311 EXPECT_EQ(S_OK, text_store_->GetStatus(&status)); | |
312 EXPECT_EQ(0, status.dwDynamicFlags); | |
313 EXPECT_EQ(TS_SS_TRANSITORY | TS_SS_NOHIDDENTEXT, status.dwStaticFlags); | |
314 } | |
315 | |
316 TEST_F(TSFTextStoreTest, QueryInsertTest) { | |
317 LONG result_start = 0; | |
318 LONG result_end = 0; | |
319 *string_buffer() = L""; | |
320 *committed_size() = 0; | |
321 EXPECT_EQ(E_INVALIDARG, | |
322 text_store_->QueryInsert(0, 0, 0, NULL, &result_end)); | |
323 EXPECT_EQ(E_INVALIDARG, | |
324 text_store_->QueryInsert(0, 0, 0, &result_start, NULL)); | |
325 EXPECT_EQ(S_OK, | |
326 text_store_->QueryInsert(0, 0, 0, &result_start, &result_end)); | |
327 EXPECT_EQ(0, result_start); | |
328 EXPECT_EQ(0, result_end); | |
329 *string_buffer() = L"1234"; | |
330 *committed_size() = 1; | |
331 EXPECT_EQ(S_OK, | |
332 text_store_->QueryInsert(0, 1, 0, &result_start, &result_end)); | |
333 EXPECT_EQ(1, result_start); | |
334 EXPECT_EQ(1, result_end); | |
335 EXPECT_EQ(E_INVALIDARG, | |
336 text_store_->QueryInsert(1, 0, 0, &result_start, &result_end)); | |
337 EXPECT_EQ(S_OK, | |
338 text_store_->QueryInsert(2, 2, 0, &result_start, &result_end)); | |
339 EXPECT_EQ(2, result_start); | |
340 EXPECT_EQ(2, result_end); | |
341 EXPECT_EQ(S_OK, | |
342 text_store_->QueryInsert(2, 3, 0, &result_start, &result_end)); | |
343 EXPECT_EQ(2, result_start); | |
344 EXPECT_EQ(3, result_end); | |
345 EXPECT_EQ(E_INVALIDARG, | |
346 text_store_->QueryInsert(3, 2, 0, &result_start, &result_end)); | |
347 EXPECT_EQ(S_OK, | |
348 text_store_->QueryInsert(3, 4, 0, &result_start, &result_end)); | |
349 EXPECT_EQ(3, result_start); | |
350 EXPECT_EQ(4, result_end); | |
351 EXPECT_EQ(S_OK, | |
352 text_store_->QueryInsert(3, 5, 0, &result_start, &result_end)); | |
353 EXPECT_EQ(3, result_start); | |
354 EXPECT_EQ(4, result_end); | |
355 } | |
356 | |
357 class SyncRequestLockTestCallback : public TSFTextStoreTestCallback { | |
358 public: | |
359 explicit SyncRequestLockTestCallback(TSFTextStore* text_store) | |
360 : TSFTextStoreTestCallback(text_store) {} | |
361 | |
362 HRESULT LockGranted1(DWORD flags) { | |
363 EXPECT_TRUE(HasReadLock()); | |
364 EXPECT_FALSE(HasReadWriteLock()); | |
365 return S_OK; | |
366 } | |
367 | |
368 HRESULT LockGranted2(DWORD flags) { | |
369 EXPECT_TRUE(HasReadLock()); | |
370 EXPECT_TRUE(HasReadWriteLock()); | |
371 return S_OK; | |
372 } | |
373 | |
374 HRESULT LockGranted3(DWORD flags) { | |
375 EXPECT_TRUE(HasReadLock()); | |
376 EXPECT_FALSE(HasReadWriteLock()); | |
377 HRESULT result = kInvalidResult; | |
378 EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READ | TS_LF_SYNC, &result)); | |
379 EXPECT_EQ(TS_E_SYNCHRONOUS, result); | |
380 return S_OK; | |
381 } | |
382 | |
383 HRESULT LockGranted4(DWORD flags) { | |
384 EXPECT_TRUE(HasReadLock()); | |
385 EXPECT_FALSE(HasReadWriteLock()); | |
386 HRESULT result = kInvalidResult; | |
387 EXPECT_EQ(S_OK, | |
388 text_store_->RequestLock(TS_LF_READWRITE | TS_LF_SYNC, &result)); | |
389 EXPECT_EQ(TS_E_SYNCHRONOUS, result); | |
390 return S_OK; | |
391 } | |
392 | |
393 HRESULT LockGranted5(DWORD flags) { | |
394 EXPECT_TRUE(HasReadLock()); | |
395 EXPECT_TRUE(HasReadWriteLock()); | |
396 HRESULT result = kInvalidResult; | |
397 EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READ | TS_LF_SYNC, &result)); | |
398 EXPECT_EQ(TS_E_SYNCHRONOUS, result); | |
399 return S_OK; | |
400 } | |
401 | |
402 HRESULT LockGranted6(DWORD flags) { | |
403 EXPECT_TRUE(HasReadLock()); | |
404 EXPECT_TRUE(HasReadWriteLock()); | |
405 HRESULT result = kInvalidResult; | |
406 EXPECT_EQ(S_OK, | |
407 text_store_->RequestLock(TS_LF_READWRITE | TS_LF_SYNC, &result)); | |
408 EXPECT_EQ(TS_E_SYNCHRONOUS, result); | |
409 return S_OK; | |
410 } | |
411 | |
412 private: | |
413 DISALLOW_COPY_AND_ASSIGN(SyncRequestLockTestCallback); | |
414 }; | |
415 | |
416 TEST_F(TSFTextStoreTest, SynchronousRequestLockTest) { | |
417 SyncRequestLockTestCallback callback(text_store_); | |
418 EXPECT_CALL(*sink_, OnLockGranted(_)) | |
419 .WillOnce(Invoke(&callback, &SyncRequestLockTestCallback::LockGranted1)) | |
420 .WillOnce(Invoke(&callback, &SyncRequestLockTestCallback::LockGranted2)) | |
421 .WillOnce(Invoke(&callback, &SyncRequestLockTestCallback::LockGranted3)) | |
422 .WillOnce(Invoke(&callback, &SyncRequestLockTestCallback::LockGranted4)) | |
423 .WillOnce(Invoke(&callback, &SyncRequestLockTestCallback::LockGranted5)) | |
424 .WillOnce(Invoke(&callback, &SyncRequestLockTestCallback::LockGranted6)); | |
425 | |
426 HRESULT result = kInvalidResult; | |
427 EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READ | TS_LF_SYNC, &result)); | |
428 EXPECT_EQ(S_OK, result); | |
429 result = kInvalidResult; | |
430 EXPECT_EQ(S_OK, | |
431 text_store_->RequestLock(TS_LF_READWRITE | TS_LF_SYNC, &result)); | |
432 EXPECT_EQ(S_OK, result); | |
433 | |
434 EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READ | TS_LF_SYNC, &result)); | |
435 EXPECT_EQ(S_OK, result); | |
436 result = kInvalidResult; | |
437 EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READ | TS_LF_SYNC, &result)); | |
438 EXPECT_EQ(S_OK, result); | |
439 | |
440 result = kInvalidResult; | |
441 EXPECT_EQ(S_OK, | |
442 text_store_->RequestLock(TS_LF_READWRITE | TS_LF_SYNC, &result)); | |
443 EXPECT_EQ(S_OK, result); | |
444 result = kInvalidResult; | |
445 EXPECT_EQ(S_OK, | |
446 text_store_->RequestLock(TS_LF_READWRITE | TS_LF_SYNC, &result)); | |
447 EXPECT_EQ(S_OK, result); | |
448 } | |
449 | |
450 class AsyncRequestLockTestCallback : public TSFTextStoreTestCallback { | |
451 public: | |
452 explicit AsyncRequestLockTestCallback(TSFTextStore* text_store) | |
453 : TSFTextStoreTestCallback(text_store), | |
454 state_(0) {} | |
455 | |
456 HRESULT LockGranted1(DWORD flags) { | |
457 EXPECT_EQ(0, state_); | |
458 state_ = 1; | |
459 EXPECT_TRUE(HasReadLock()); | |
460 EXPECT_FALSE(HasReadWriteLock()); | |
461 HRESULT result = kInvalidResult; | |
462 EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READ, &result)); | |
463 EXPECT_EQ(TS_S_ASYNC, result); | |
464 EXPECT_EQ(1, state_); | |
465 state_ = 2; | |
466 return S_OK; | |
467 } | |
468 | |
469 HRESULT LockGranted2(DWORD flags) { | |
470 EXPECT_EQ(2, state_); | |
471 EXPECT_TRUE(HasReadLock()); | |
472 EXPECT_FALSE(HasReadWriteLock()); | |
473 HRESULT result = kInvalidResult; | |
474 EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READWRITE, &result)); | |
475 EXPECT_EQ(TS_S_ASYNC, result); | |
476 EXPECT_EQ(2, state_); | |
477 state_ = 3; | |
478 return S_OK; | |
479 } | |
480 | |
481 HRESULT LockGranted3(DWORD flags) { | |
482 EXPECT_EQ(3, state_); | |
483 EXPECT_TRUE(HasReadLock()); | |
484 EXPECT_TRUE(HasReadWriteLock()); | |
485 HRESULT result = kInvalidResult; | |
486 EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READWRITE, &result)); | |
487 EXPECT_EQ(TS_S_ASYNC, result); | |
488 EXPECT_EQ(3, state_); | |
489 state_ = 4; | |
490 return S_OK; | |
491 } | |
492 | |
493 HRESULT LockGranted4(DWORD flags) { | |
494 EXPECT_EQ(4, state_); | |
495 EXPECT_TRUE(HasReadLock()); | |
496 EXPECT_TRUE(HasReadWriteLock()); | |
497 HRESULT result = kInvalidResult; | |
498 EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READ, &result)); | |
499 EXPECT_EQ(TS_S_ASYNC, result); | |
500 EXPECT_EQ(4, state_); | |
501 state_ = 5; | |
502 return S_OK; | |
503 } | |
504 | |
505 HRESULT LockGranted5(DWORD flags) { | |
506 EXPECT_EQ(5, state_); | |
507 EXPECT_TRUE(HasReadLock()); | |
508 EXPECT_FALSE(HasReadWriteLock()); | |
509 state_ = 6; | |
510 return S_OK; | |
511 } | |
512 | |
513 private: | |
514 int state_; | |
515 | |
516 DISALLOW_COPY_AND_ASSIGN(AsyncRequestLockTestCallback); | |
517 }; | |
518 | |
519 TEST_F(TSFTextStoreTest, AsynchronousRequestLockTest) { | |
520 AsyncRequestLockTestCallback callback(text_store_); | |
521 EXPECT_CALL(*sink_, OnLockGranted(_)) | |
522 .WillOnce(Invoke(&callback, &AsyncRequestLockTestCallback::LockGranted1)) | |
523 .WillOnce(Invoke(&callback, &AsyncRequestLockTestCallback::LockGranted2)) | |
524 .WillOnce(Invoke(&callback, &AsyncRequestLockTestCallback::LockGranted3)) | |
525 .WillOnce(Invoke(&callback, &AsyncRequestLockTestCallback::LockGranted4)) | |
526 .WillOnce(Invoke(&callback, &AsyncRequestLockTestCallback::LockGranted5)); | |
527 | |
528 HRESULT result = kInvalidResult; | |
529 EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READ, &result)); | |
530 EXPECT_EQ(S_OK, result); | |
531 } | |
532 | |
533 class RequestLockTextChangeTestCallback : public TSFTextStoreTestCallback { | |
534 public: | |
535 explicit RequestLockTextChangeTestCallback(TSFTextStore* text_store) | |
536 : TSFTextStoreTestCallback(text_store), | |
537 state_(0) {} | |
538 | |
539 HRESULT LockGranted1(DWORD flags) { | |
540 EXPECT_EQ(0, state_); | |
541 state_ = 1; | |
542 EXPECT_TRUE(HasReadLock()); | |
543 EXPECT_TRUE(HasReadWriteLock()); | |
544 | |
545 *edit_flag() = true; | |
546 SetInternalState(L"012345", 6, 6, 6); | |
547 composition_undelines()->clear(); | |
548 | |
549 state_ = 2; | |
550 return S_OK; | |
551 } | |
552 | |
553 void InsertText(const base::string16& text) { | |
554 EXPECT_EQ(2, state_); | |
555 EXPECT_EQ(L"012345", text); | |
556 state_ = 3; | |
557 } | |
558 | |
559 void SetCompositionText(const ui::CompositionText& composition) { | |
560 EXPECT_EQ(3, state_); | |
561 EXPECT_EQ(L"", composition.text); | |
562 EXPECT_EQ(0, composition.selection.start()); | |
563 EXPECT_EQ(0, composition.selection.end()); | |
564 EXPECT_EQ(0, composition.underlines.size()); | |
565 state_ = 4; | |
566 } | |
567 | |
568 HRESULT OnTextChange(DWORD flags, const TS_TEXTCHANGE* change) { | |
569 EXPECT_EQ(4, state_); | |
570 HRESULT result = kInvalidResult; | |
571 state_ = 5; | |
572 EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READWRITE, &result)); | |
573 EXPECT_EQ(S_OK, result); | |
574 EXPECT_EQ(6, state_); | |
575 state_ = 7; | |
576 return S_OK; | |
577 } | |
578 | |
579 HRESULT LockGranted2(DWORD flags) { | |
580 EXPECT_EQ(5, state_); | |
581 EXPECT_TRUE(HasReadLock()); | |
582 EXPECT_TRUE(HasReadWriteLock()); | |
583 state_ = 6; | |
584 return S_OK; | |
585 } | |
586 | |
587 private: | |
588 int state_; | |
589 | |
590 DISALLOW_COPY_AND_ASSIGN(RequestLockTextChangeTestCallback); | |
591 }; | |
592 | |
593 TEST_F(TSFTextStoreTest, RequestLockOnTextChangeTest) { | |
594 RequestLockTextChangeTestCallback callback(text_store_); | |
595 EXPECT_CALL(*sink_, OnLockGranted(_)) | |
596 .WillOnce(Invoke(&callback, | |
597 &RequestLockTextChangeTestCallback::LockGranted1)) | |
598 .WillOnce(Invoke(&callback, | |
599 &RequestLockTextChangeTestCallback::LockGranted2)); | |
600 | |
601 EXPECT_CALL(*sink_, OnSelectionChange()) | |
602 .WillOnce(Return(S_OK)); | |
603 EXPECT_CALL(*sink_, OnLayoutChange(_, _)) | |
604 .WillOnce(Return(S_OK)); | |
605 EXPECT_CALL(*sink_, OnTextChange(_, _)) | |
606 .WillOnce(Invoke(&callback, | |
607 &RequestLockTextChangeTestCallback::OnTextChange)); | |
608 EXPECT_CALL(text_input_client_, InsertText(_)) | |
609 .WillOnce(Invoke(&callback, | |
610 &RequestLockTextChangeTestCallback::InsertText)); | |
611 EXPECT_CALL(text_input_client_, SetCompositionText(_)) | |
612 .WillOnce(Invoke(&callback, | |
613 &RequestLockTextChangeTestCallback::SetCompositionText)); | |
614 | |
615 HRESULT result = kInvalidResult; | |
616 EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READWRITE, &result)); | |
617 EXPECT_EQ(S_OK, result); | |
618 } | |
619 | |
620 class SelectionTestCallback : public TSFTextStoreTestCallback { | |
621 public: | |
622 explicit SelectionTestCallback(TSFTextStore* text_store) | |
623 : TSFTextStoreTestCallback(text_store) {} | |
624 | |
625 HRESULT ReadLockGranted(DWORD flags) { | |
626 SetInternalState(L"", 0, 0, 0); | |
627 | |
628 GetSelectionTest(0, 0); | |
629 SetSelectionTest(0, 0, TF_E_NOLOCK); | |
630 | |
631 SetInternalState(L"012345", 0, 0, 3); | |
632 | |
633 GetSelectionTest(0, 3); | |
634 SetSelectionTest(0, 0, TF_E_NOLOCK); | |
635 | |
636 return S_OK; | |
637 } | |
638 | |
639 HRESULT ReadWriteLockGranted(DWORD flags) { | |
640 SetInternalState(L"", 0, 0, 0); | |
641 | |
642 SetSelectionTest(0, 0, S_OK); | |
643 GetSelectionTest(0, 0); | |
644 SetSelectionTest(0, 1, TF_E_INVALIDPOS); | |
645 SetSelectionTest(1, 0, TF_E_INVALIDPOS); | |
646 SetSelectionTest(1, 1, TF_E_INVALIDPOS); | |
647 | |
648 SetInternalState(L"0123456", 3, 3, 3); | |
649 | |
650 SetSelectionTest(0, 0, TF_E_INVALIDPOS); | |
651 SetSelectionTest(0, 1, TF_E_INVALIDPOS); | |
652 SetSelectionTest(0, 3, TF_E_INVALIDPOS); | |
653 SetSelectionTest(0, 6, TF_E_INVALIDPOS); | |
654 SetSelectionTest(0, 7, TF_E_INVALIDPOS); | |
655 SetSelectionTest(0, 8, TF_E_INVALIDPOS); | |
656 | |
657 SetSelectionTest(1, 0, TF_E_INVALIDPOS); | |
658 SetSelectionTest(1, 1, TF_E_INVALIDPOS); | |
659 SetSelectionTest(1, 3, TF_E_INVALIDPOS); | |
660 SetSelectionTest(1, 6, TF_E_INVALIDPOS); | |
661 SetSelectionTest(1, 7, TF_E_INVALIDPOS); | |
662 SetSelectionTest(1, 8, TF_E_INVALIDPOS); | |
663 | |
664 SetSelectionTest(3, 0, TF_E_INVALIDPOS); | |
665 SetSelectionTest(3, 1, TF_E_INVALIDPOS); | |
666 SetSelectionTest(3, 3, S_OK); | |
667 SetSelectionTest(3, 6, S_OK); | |
668 SetSelectionTest(3, 7, S_OK); | |
669 SetSelectionTest(3, 8, TF_E_INVALIDPOS); | |
670 | |
671 SetSelectionTest(6, 0, TF_E_INVALIDPOS); | |
672 SetSelectionTest(6, 1, TF_E_INVALIDPOS); | |
673 SetSelectionTest(6, 3, TF_E_INVALIDPOS); | |
674 SetSelectionTest(6, 6, S_OK); | |
675 SetSelectionTest(6, 7, S_OK); | |
676 SetSelectionTest(6, 8, TF_E_INVALIDPOS); | |
677 | |
678 SetSelectionTest(7, 0, TF_E_INVALIDPOS); | |
679 SetSelectionTest(7, 1, TF_E_INVALIDPOS); | |
680 SetSelectionTest(7, 3, TF_E_INVALIDPOS); | |
681 SetSelectionTest(7, 6, TF_E_INVALIDPOS); | |
682 SetSelectionTest(7, 7, S_OK); | |
683 SetSelectionTest(7, 8, TF_E_INVALIDPOS); | |
684 | |
685 SetSelectionTest(8, 0, TF_E_INVALIDPOS); | |
686 SetSelectionTest(8, 1, TF_E_INVALIDPOS); | |
687 SetSelectionTest(8, 3, TF_E_INVALIDPOS); | |
688 SetSelectionTest(8, 6, TF_E_INVALIDPOS); | |
689 SetSelectionTest(8, 7, TF_E_INVALIDPOS); | |
690 SetSelectionTest(8, 8, TF_E_INVALIDPOS); | |
691 | |
692 return S_OK; | |
693 } | |
694 }; | |
695 | |
696 TEST_F(TSFTextStoreTest, SetGetSelectionTest) { | |
697 SelectionTestCallback callback(text_store_); | |
698 EXPECT_CALL(*sink_, OnLockGranted(_)) | |
699 .WillOnce(Invoke(&callback, &SelectionTestCallback::ReadLockGranted)) | |
700 .WillOnce(Invoke(&callback, | |
701 &SelectionTestCallback::ReadWriteLockGranted)); | |
702 | |
703 TS_SELECTION_ACP selection_buffer = {}; | |
704 ULONG fetched_count = 0; | |
705 EXPECT_EQ(TS_E_NOLOCK, | |
706 text_store_->GetSelection(0, 1, &selection_buffer, | |
707 &fetched_count)); | |
708 | |
709 HRESULT result = kInvalidResult; | |
710 EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READ, &result)); | |
711 EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READWRITE, &result)); | |
712 } | |
713 | |
714 class SetGetTextTestCallback : public TSFTextStoreTestCallback { | |
715 public: | |
716 explicit SetGetTextTestCallback(TSFTextStore* text_store) | |
717 : TSFTextStoreTestCallback(text_store) {} | |
718 | |
719 HRESULT ReadLockGranted(DWORD flags) { | |
720 SetTextTest(0, 0, L"", TF_E_NOLOCK); | |
721 | |
722 GetTextTest(0, -1, L"", 0); | |
723 GetTextTest(0, 0, L"", 0); | |
724 GetTextErrorTest(0, 1, TF_E_INVALIDPOS); | |
725 | |
726 SetInternalState(L"0123456", 3, 3, 3); | |
727 | |
728 GetTextErrorTest(-1, -1, TF_E_INVALIDPOS); | |
729 GetTextErrorTest(-1, 0, TF_E_INVALIDPOS); | |
730 GetTextErrorTest(-1, 1, TF_E_INVALIDPOS); | |
731 GetTextErrorTest(-1, 3, TF_E_INVALIDPOS); | |
732 GetTextErrorTest(-1, 6, TF_E_INVALIDPOS); | |
733 GetTextErrorTest(-1, 7, TF_E_INVALIDPOS); | |
734 GetTextErrorTest(-1, 8, TF_E_INVALIDPOS); | |
735 | |
736 GetTextTest(0, -1, L"0123456", 7); | |
737 GetTextTest(0, 0, L"", 0); | |
738 GetTextTest(0, 1, L"0", 1); | |
739 GetTextTest(0, 3, L"012", 3); | |
740 GetTextTest(0, 6, L"012345", 6); | |
741 GetTextTest(0, 7, L"0123456", 7); | |
742 GetTextErrorTest(0, 8, TF_E_INVALIDPOS); | |
743 | |
744 GetTextTest(1, -1, L"123456", 7); | |
745 GetTextErrorTest(1, 0, TF_E_INVALIDPOS); | |
746 GetTextTest(1, 1, L"", 1); | |
747 GetTextTest(1, 3, L"12", 3); | |
748 GetTextTest(1, 6, L"12345", 6); | |
749 GetTextTest(1, 7, L"123456", 7); | |
750 GetTextErrorTest(1, 8, TF_E_INVALIDPOS); | |
751 | |
752 GetTextTest(3, -1, L"3456", 7); | |
753 GetTextErrorTest(3, 0, TF_E_INVALIDPOS); | |
754 GetTextErrorTest(3, 1, TF_E_INVALIDPOS); | |
755 GetTextTest(3, 3, L"", 3); | |
756 GetTextTest(3, 6, L"345", 6); | |
757 GetTextTest(3, 7, L"3456", 7); | |
758 GetTextErrorTest(3, 8, TF_E_INVALIDPOS); | |
759 | |
760 GetTextTest(6, -1, L"6", 7); | |
761 GetTextErrorTest(6, 0, TF_E_INVALIDPOS); | |
762 GetTextErrorTest(6, 1, TF_E_INVALIDPOS); | |
763 GetTextErrorTest(6, 3, TF_E_INVALIDPOS); | |
764 GetTextTest(6, 6, L"", 6); | |
765 GetTextTest(6, 7, L"6", 7); | |
766 GetTextErrorTest(6, 8, TF_E_INVALIDPOS); | |
767 | |
768 GetTextTest(7, -1, L"", 7); | |
769 GetTextErrorTest(7, 0, TF_E_INVALIDPOS); | |
770 GetTextErrorTest(7, 1, TF_E_INVALIDPOS); | |
771 GetTextErrorTest(7, 3, TF_E_INVALIDPOS); | |
772 GetTextErrorTest(7, 6, TF_E_INVALIDPOS); | |
773 GetTextTest(7, 7, L"", 7); | |
774 GetTextErrorTest(7, 8, TF_E_INVALIDPOS); | |
775 | |
776 GetTextErrorTest(8, -1, TF_E_INVALIDPOS); | |
777 GetTextErrorTest(8, 0, TF_E_INVALIDPOS); | |
778 GetTextErrorTest(8, 1, TF_E_INVALIDPOS); | |
779 GetTextErrorTest(8, 3, TF_E_INVALIDPOS); | |
780 GetTextErrorTest(8, 6, TF_E_INVALIDPOS); | |
781 GetTextErrorTest(8, 7, TF_E_INVALIDPOS); | |
782 GetTextErrorTest(8, 8, TF_E_INVALIDPOS); | |
783 | |
784 return S_OK; | |
785 } | |
786 | |
787 HRESULT ReadWriteLockGranted(DWORD flags) { | |
788 SetInternalState(L"", 0, 0, 0); | |
789 SetTextTest(0, 0, L"", S_OK); | |
790 | |
791 SetInternalState(L"", 0, 0, 0); | |
792 SetTextTest(0, 1, L"", TS_E_INVALIDPOS); | |
793 | |
794 SetInternalState(L"0123456", 3, 3, 3); | |
795 | |
796 SetTextTest(0, 0, L"", TS_E_INVALIDPOS); | |
797 SetTextTest(0, 1, L"", TS_E_INVALIDPOS); | |
798 SetTextTest(0, 3, L"", TS_E_INVALIDPOS); | |
799 SetTextTest(0, 6, L"", TS_E_INVALIDPOS); | |
800 SetTextTest(0, 7, L"", TS_E_INVALIDPOS); | |
801 SetTextTest(0, 8, L"", TS_E_INVALIDPOS); | |
802 | |
803 SetTextTest(1, 0, L"", TS_E_INVALIDPOS); | |
804 SetTextTest(1, 1, L"", TS_E_INVALIDPOS); | |
805 SetTextTest(1, 3, L"", TS_E_INVALIDPOS); | |
806 SetTextTest(1, 6, L"", TS_E_INVALIDPOS); | |
807 SetTextTest(1, 7, L"", TS_E_INVALIDPOS); | |
808 SetTextTest(1, 8, L"", TS_E_INVALIDPOS); | |
809 | |
810 SetTextTest(3, 0, L"", TS_E_INVALIDPOS); | |
811 SetTextTest(3, 1, L"", TS_E_INVALIDPOS); | |
812 | |
813 SetTextTest(3, 3, L"", S_OK); | |
814 GetTextTest(0, -1, L"0123456", 7); | |
815 GetSelectionTest(3, 3); | |
816 SetInternalState(L"0123456", 3, 3, 3); | |
817 | |
818 SetTextTest(3, 6, L"", S_OK); | |
819 GetTextTest(0, -1, L"0126", 4); | |
820 GetSelectionTest(3, 3); | |
821 SetInternalState(L"0123456", 3, 3, 3); | |
822 | |
823 SetTextTest(3, 7, L"", S_OK); | |
824 GetTextTest(0, -1, L"012", 3); | |
825 GetSelectionTest(3, 3); | |
826 SetInternalState(L"0123456", 3, 3, 3); | |
827 | |
828 SetTextTest(3, 8, L"", TS_E_INVALIDPOS); | |
829 | |
830 SetTextTest(6, 0, L"", TS_E_INVALIDPOS); | |
831 SetTextTest(6, 1, L"", TS_E_INVALIDPOS); | |
832 SetTextTest(6, 3, L"", TS_E_INVALIDPOS); | |
833 | |
834 SetTextTest(6, 6, L"", S_OK); | |
835 GetTextTest(0, -1, L"0123456", 7); | |
836 GetSelectionTest(6, 6); | |
837 SetInternalState(L"0123456", 3, 3, 3); | |
838 | |
839 SetTextTest(6, 7, L"", S_OK); | |
840 GetTextTest(0, -1, L"012345", 6); | |
841 GetSelectionTest(6, 6); | |
842 SetInternalState(L"0123456", 3, 3, 3); | |
843 | |
844 SetTextTest(6, 8, L"", TS_E_INVALIDPOS); | |
845 | |
846 SetTextTest(7, 0, L"", TS_E_INVALIDPOS); | |
847 SetTextTest(7, 1, L"", TS_E_INVALIDPOS); | |
848 SetTextTest(7, 3, L"", TS_E_INVALIDPOS); | |
849 SetTextTest(7, 6, L"", TS_E_INVALIDPOS); | |
850 | |
851 SetTextTest(7, 7, L"", S_OK); | |
852 GetTextTest(0, -1, L"0123456", 7); | |
853 GetSelectionTest(7, 7); | |
854 SetInternalState(L"0123456", 3, 3, 3); | |
855 | |
856 SetTextTest(7, 8, L"", TS_E_INVALIDPOS); | |
857 | |
858 SetInternalState(L"0123456", 3, 3, 3); | |
859 SetTextTest(3, 3, L"abc", S_OK); | |
860 GetTextTest(0, -1, L"012abc3456", 10); | |
861 GetSelectionTest(3, 6); | |
862 | |
863 SetInternalState(L"0123456", 3, 3, 3); | |
864 SetTextTest(3, 6, L"abc", S_OK); | |
865 GetTextTest(0, -1, L"012abc6", 7); | |
866 GetSelectionTest(3, 6); | |
867 | |
868 SetInternalState(L"0123456", 3, 3, 3); | |
869 SetTextTest(3, 7, L"abc", S_OK); | |
870 GetTextTest(0, -1, L"012abc", 6); | |
871 GetSelectionTest(3, 6); | |
872 | |
873 SetInternalState(L"0123456", 3, 3, 3); | |
874 SetTextTest(6, 6, L"abc", S_OK); | |
875 GetTextTest(0, -1, L"012345abc6", 10); | |
876 GetSelectionTest(6, 9); | |
877 | |
878 SetInternalState(L"0123456", 3, 3, 3); | |
879 SetTextTest(6, 7, L"abc", S_OK); | |
880 GetTextTest(0, -1, L"012345abc", 9); | |
881 GetSelectionTest(6, 9); | |
882 | |
883 SetInternalState(L"0123456", 3, 3, 3); | |
884 SetTextTest(7, 7, L"abc", S_OK); | |
885 GetTextTest(0, -1, L"0123456abc", 10); | |
886 GetSelectionTest(7, 10); | |
887 | |
888 return S_OK; | |
889 } | |
890 | |
891 private: | |
892 DISALLOW_COPY_AND_ASSIGN(SetGetTextTestCallback); | |
893 }; | |
894 | |
895 TEST_F(TSFTextStoreTest, SetGetTextTest) { | |
896 SetGetTextTestCallback callback(text_store_); | |
897 EXPECT_CALL(*sink_, OnLockGranted(_)) | |
898 .WillOnce(Invoke(&callback, &SetGetTextTestCallback::ReadLockGranted)) | |
899 .WillOnce(Invoke(&callback, | |
900 &SetGetTextTestCallback::ReadWriteLockGranted)); | |
901 | |
902 wchar_t buffer[1024] = {}; | |
903 ULONG text_buffer_copied = 0; | |
904 TS_RUNINFO run_info = {}; | |
905 ULONG run_info_buffer_copied = 0; | |
906 LONG next_acp = 0; | |
907 EXPECT_EQ(TF_E_NOLOCK, | |
908 text_store_->GetText(0, -1, buffer, 1024, &text_buffer_copied, | |
909 &run_info, 1, &run_info_buffer_copied, | |
910 &next_acp)); | |
911 TS_TEXTCHANGE change = {}; | |
912 EXPECT_EQ(TF_E_NOLOCK, text_store_->SetText(0, 0, 0, L"abc", 3, &change)); | |
913 | |
914 HRESULT result = kInvalidResult; | |
915 EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READ, &result)); | |
916 EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READWRITE, &result)); | |
917 } | |
918 | |
919 class InsertTextAtSelectionTestCallback : public TSFTextStoreTestCallback { | |
920 public: | |
921 explicit InsertTextAtSelectionTestCallback(TSFTextStore* text_store) | |
922 : TSFTextStoreTestCallback(text_store) {} | |
923 | |
924 HRESULT ReadLockGranted(DWORD flags) { | |
925 const wchar_t kBuffer[] = L"0123456789"; | |
926 | |
927 SetInternalState(L"abcedfg", 0, 0, 0); | |
928 InsertTextAtSelectionQueryOnlyTest(kBuffer, 10, 0, 0); | |
929 GetSelectionTest(0, 0); | |
930 InsertTextAtSelectionQueryOnlyTest(kBuffer, 0, 0, 0); | |
931 | |
932 SetInternalState(L"abcedfg", 0, 2, 5); | |
933 InsertTextAtSelectionQueryOnlyTest(kBuffer, 10, 2, 5); | |
934 GetSelectionTest(2, 5); | |
935 InsertTextAtSelectionQueryOnlyTest(kBuffer, 0, 2, 5); | |
936 | |
937 LONG start = 0; | |
938 LONG end = 0; | |
939 TS_TEXTCHANGE change = {}; | |
940 EXPECT_EQ(TS_E_NOLOCK, | |
941 text_store_->InsertTextAtSelection(0, kBuffer, 10, | |
942 &start, &end, &change)); | |
943 return S_OK; | |
944 } | |
945 | |
946 HRESULT ReadWriteLockGranted(DWORD flags) { | |
947 SetInternalState(L"abcedfg", 0, 0, 0); | |
948 | |
949 const wchar_t kBuffer[] = L"0123456789"; | |
950 InsertTextAtSelectionQueryOnlyTest(kBuffer, 10, 0, 0); | |
951 GetSelectionTest(0, 0); | |
952 InsertTextAtSelectionQueryOnlyTest(kBuffer, 0, 0, 0); | |
953 | |
954 SetInternalState(L"", 0, 0, 0); | |
955 InsertTextAtSelectionTest(kBuffer, 10, 0, 10, 0, 0, 10); | |
956 GetSelectionTest(0, 10); | |
957 GetTextTest(0, -1, L"0123456789", 10); | |
958 | |
959 SetInternalState(L"abcedfg", 0, 0, 0); | |
960 InsertTextAtSelectionTest(kBuffer, 10, 0, 10, 0, 0, 10); | |
961 GetSelectionTest(0, 10); | |
962 GetTextTest(0, -1, L"0123456789abcedfg", 17); | |
963 | |
964 SetInternalState(L"abcedfg", 0, 0, 3); | |
965 InsertTextAtSelectionTest(kBuffer, 0, 0, 0, 0, 3, 0); | |
966 GetSelectionTest(0, 0); | |
967 GetTextTest(0, -1, L"edfg", 4); | |
968 | |
969 SetInternalState(L"abcedfg", 0, 3, 7); | |
970 InsertTextAtSelectionTest(kBuffer, 10, 3, 13, 3, 7, 13); | |
971 GetSelectionTest(3, 13); | |
972 GetTextTest(0, -1, L"abc0123456789", 13); | |
973 | |
974 SetInternalState(L"abcedfg", 0, 7, 7); | |
975 InsertTextAtSelectionTest(kBuffer, 10, 7, 17, 7, 7, 17); | |
976 GetSelectionTest(7, 17); | |
977 GetTextTest(0, -1, L"abcedfg0123456789", 17); | |
978 | |
979 return S_OK; | |
980 } | |
981 | |
982 private: | |
983 DISALLOW_COPY_AND_ASSIGN(InsertTextAtSelectionTestCallback); | |
984 }; | |
985 | |
986 TEST_F(TSFTextStoreTest, InsertTextAtSelectionTest) { | |
987 InsertTextAtSelectionTestCallback callback(text_store_); | |
988 EXPECT_CALL(*sink_, OnLockGranted(_)) | |
989 .WillOnce(Invoke(&callback, | |
990 &InsertTextAtSelectionTestCallback::ReadLockGranted)) | |
991 .WillOnce( | |
992 Invoke(&callback, | |
993 &InsertTextAtSelectionTestCallback::ReadWriteLockGranted)); | |
994 | |
995 HRESULT result = kInvalidResult; | |
996 EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READ, &result)); | |
997 EXPECT_EQ(S_OK, result); | |
998 result = kInvalidResult; | |
999 EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READWRITE, &result)); | |
1000 EXPECT_EQ(S_OK, result); | |
1001 } | |
1002 | |
1003 class ScenarioTestCallback : public TSFTextStoreTestCallback { | |
1004 public: | |
1005 explicit ScenarioTestCallback(TSFTextStore* text_store) | |
1006 : TSFTextStoreTestCallback(text_store) {} | |
1007 | |
1008 HRESULT LockGranted1(DWORD flags) { | |
1009 SetSelectionTest(0, 0, S_OK); | |
1010 | |
1011 SetTextTest(0, 0, L"abc", S_OK); | |
1012 SetTextTest(1, 2, L"xyz", S_OK); | |
1013 | |
1014 GetTextTest(0, -1, L"axyzc", 5); | |
1015 | |
1016 composition_undelines()->clear(); | |
1017 CompositionUnderline underline; | |
1018 underline.start_offset = 0; | |
1019 underline.end_offset = 5; | |
1020 underline.color = SK_ColorBLACK; | |
1021 underline.thick = false; | |
1022 composition_undelines()->push_back(underline); | |
1023 *edit_flag() = true; | |
1024 *committed_size() = 0; | |
1025 return S_OK; | |
1026 } | |
1027 | |
1028 void SetCompositionText1(const ui::CompositionText& composition) { | |
1029 EXPECT_EQ(L"axyzc", composition.text); | |
1030 EXPECT_EQ(1, composition.selection.start()); | |
1031 EXPECT_EQ(4, composition.selection.end()); | |
1032 ASSERT_EQ(1, composition.underlines.size()); | |
1033 EXPECT_EQ(SK_ColorBLACK, composition.underlines[0].color); | |
1034 EXPECT_EQ(0, composition.underlines[0].start_offset); | |
1035 EXPECT_EQ(5, composition.underlines[0].end_offset); | |
1036 EXPECT_FALSE(composition.underlines[0].thick); | |
1037 } | |
1038 | |
1039 HRESULT LockGranted2(DWORD flags) { | |
1040 SetTextTest(3, 4, L"ZCP", S_OK); | |
1041 GetTextTest(0, -1, L"axyZCPc", 7); | |
1042 | |
1043 composition_undelines()->clear(); | |
1044 CompositionUnderline underline; | |
1045 underline.start_offset = 3; | |
1046 underline.end_offset = 5; | |
1047 underline.color = SK_ColorBLACK; | |
1048 underline.thick = true; | |
1049 composition_undelines()->push_back(underline); | |
1050 underline.start_offset = 5; | |
1051 underline.end_offset = 7; | |
1052 underline.color = SK_ColorBLACK; | |
1053 underline.thick = false; | |
1054 composition_undelines()->push_back(underline); | |
1055 | |
1056 *edit_flag() = true; | |
1057 *committed_size() = 3; | |
1058 | |
1059 return S_OK; | |
1060 } | |
1061 | |
1062 void InsertText2(const base::string16& text) { | |
1063 EXPECT_EQ(L"axy", text); | |
1064 } | |
1065 | |
1066 void SetCompositionText2(const ui::CompositionText& composition) { | |
1067 EXPECT_EQ(L"ZCPc", composition.text); | |
1068 EXPECT_EQ(0, composition.selection.start()); | |
1069 EXPECT_EQ(3, composition.selection.end()); | |
1070 ASSERT_EQ(2, composition.underlines.size()); | |
1071 EXPECT_EQ(SK_ColorBLACK, composition.underlines[0].color); | |
1072 EXPECT_EQ(0, composition.underlines[0].start_offset); | |
1073 EXPECT_EQ(2, composition.underlines[0].end_offset); | |
1074 EXPECT_TRUE(composition.underlines[0].thick); | |
1075 EXPECT_EQ(SK_ColorBLACK, composition.underlines[1].color); | |
1076 EXPECT_EQ(2, composition.underlines[1].start_offset); | |
1077 EXPECT_EQ(4, composition.underlines[1].end_offset); | |
1078 EXPECT_FALSE(composition.underlines[1].thick); | |
1079 } | |
1080 | |
1081 HRESULT LockGranted3(DWORD flags) { | |
1082 GetTextTest(0, -1, L"axyZCPc", 7); | |
1083 | |
1084 composition_undelines()->clear(); | |
1085 *edit_flag() = true; | |
1086 *committed_size() = 7; | |
1087 | |
1088 return S_OK; | |
1089 } | |
1090 | |
1091 void InsertText3(const base::string16& text) { | |
1092 EXPECT_EQ(L"ZCPc", text); | |
1093 } | |
1094 | |
1095 void SetCompositionText3(const ui::CompositionText& composition) { | |
1096 EXPECT_EQ(L"", composition.text); | |
1097 EXPECT_EQ(0, composition.selection.start()); | |
1098 EXPECT_EQ(0, composition.selection.end()); | |
1099 EXPECT_EQ(0, composition.underlines.size()); | |
1100 } | |
1101 | |
1102 private: | |
1103 DISALLOW_COPY_AND_ASSIGN(ScenarioTestCallback); | |
1104 }; | |
1105 | |
1106 TEST_F(TSFTextStoreTest, ScenarioTest) { | |
1107 ScenarioTestCallback callback(text_store_); | |
1108 EXPECT_CALL(text_input_client_, SetCompositionText(_)) | |
1109 .WillOnce(Invoke(&callback, &ScenarioTestCallback::SetCompositionText1)) | |
1110 .WillOnce(Invoke(&callback, &ScenarioTestCallback::SetCompositionText2)) | |
1111 .WillOnce(Invoke(&callback, &ScenarioTestCallback::SetCompositionText3)); | |
1112 | |
1113 EXPECT_CALL(text_input_client_, InsertText(_)) | |
1114 .WillOnce(Invoke(&callback, &ScenarioTestCallback::InsertText2)) | |
1115 .WillOnce(Invoke(&callback, &ScenarioTestCallback::InsertText3)); | |
1116 | |
1117 EXPECT_CALL(*sink_, OnLockGranted(_)) | |
1118 .WillOnce(Invoke(&callback, &ScenarioTestCallback::LockGranted1)) | |
1119 .WillOnce(Invoke(&callback, &ScenarioTestCallback::LockGranted2)) | |
1120 .WillOnce(Invoke(&callback, &ScenarioTestCallback::LockGranted3)); | |
1121 | |
1122 // OnSelectionChange will be called once after LockGranted3(). | |
1123 EXPECT_CALL(*sink_, OnSelectionChange()) | |
1124 .WillOnce(Return(S_OK)); | |
1125 | |
1126 // OnLayoutChange will be called once after LockGranted3(). | |
1127 EXPECT_CALL(*sink_, OnLayoutChange(_, _)) | |
1128 .WillOnce(Return(S_OK)); | |
1129 | |
1130 // OnTextChange will be called once after LockGranted3(). | |
1131 EXPECT_CALL(*sink_, OnTextChange(_, _)) | |
1132 .WillOnce(Return(S_OK)); | |
1133 | |
1134 HRESULT result = kInvalidResult; | |
1135 EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READWRITE, &result)); | |
1136 EXPECT_EQ(S_OK, result); | |
1137 result = kInvalidResult; | |
1138 EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READWRITE, &result)); | |
1139 EXPECT_EQ(S_OK, result); | |
1140 result = kInvalidResult; | |
1141 EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READWRITE, &result)); | |
1142 EXPECT_EQ(S_OK, result); | |
1143 } | |
1144 | |
1145 class GetTextExtTestCallback : public TSFTextStoreTestCallback { | |
1146 public: | |
1147 explicit GetTextExtTestCallback(TSFTextStore* text_store) | |
1148 : TSFTextStoreTestCallback(text_store), | |
1149 layout_prepared_character_num_(0) {} | |
1150 | |
1151 HRESULT LockGranted(DWORD flags) { | |
1152 SetInternalState(L"0123456789012", 0, 0, 0); | |
1153 layout_prepared_character_num_ = 13; | |
1154 | |
1155 TsViewCookie view_cookie = 0; | |
1156 EXPECT_EQ(S_OK, text_store_->GetActiveView(&view_cookie)); | |
1157 GetTextExtTest(view_cookie, 0, 0, 11, 12, 11, 20); | |
1158 GetTextExtTest(view_cookie, 0, 1, 11, 12, 20, 20); | |
1159 GetTextExtTest(view_cookie, 0, 2, 11, 12, 30, 20); | |
1160 GetTextExtTest(view_cookie, 9, 9, 100, 12, 100, 20); | |
1161 GetTextExtTest(view_cookie, 9, 10, 101, 12, 110, 20); | |
1162 GetTextExtTest(view_cookie, 10, 10, 110, 12, 110, 20); | |
1163 GetTextExtTest(view_cookie, 11, 11, 20, 112, 20, 120); | |
1164 GetTextExtTest(view_cookie, 11, 12, 21, 112, 30, 120); | |
1165 GetTextExtTest(view_cookie, 9, 12, 101, 12, 30, 120); | |
1166 GetTextExtTest(view_cookie, 9, 13, 101, 12, 40, 120); | |
1167 GetTextExtTest(view_cookie, 0, 13, 11, 12, 40, 120); | |
1168 GetTextExtTest(view_cookie, 13, 13, 40, 112, 40, 120); | |
1169 | |
1170 layout_prepared_character_num_ = 12; | |
1171 GetTextExtNoLayoutTest(view_cookie, 13, 13); | |
1172 | |
1173 layout_prepared_character_num_ = 0; | |
1174 GetTextExtNoLayoutTest(view_cookie, 0, 0); | |
1175 | |
1176 SetInternalState(L"", 0, 0, 0); | |
1177 GetTextExtTest(view_cookie, 0, 0, 1, 2, 4, 6); | |
1178 | |
1179 // Last character is not availabe due to timing issue of async API. | |
1180 // In this case, we will get first character bounds instead of whole text | |
1181 // bounds. | |
1182 SetInternalState(L"abc", 0, 0, 3); | |
1183 layout_prepared_character_num_ = 2; | |
1184 GetTextExtTest(view_cookie, 0, 0, 11, 12, 11, 20); | |
1185 | |
1186 // TODO(nona, kinaba): Remove following test case after PPAPI supporting | |
1187 // GetCompositionCharacterBounds. | |
1188 SetInternalState(L"a", 0, 0, 1); | |
1189 layout_prepared_character_num_ = 0; | |
1190 GetTextExtTest(view_cookie, 0, 1, 1, 2, 4, 6); | |
1191 return S_OK; | |
1192 } | |
1193 | |
1194 bool GetCompositionCharacterBounds(uint32 index, gfx::Rect* rect) { | |
1195 if (index >= layout_prepared_character_num_) | |
1196 return false; | |
1197 rect->set_x((index % 10) * 10 + 11); | |
1198 rect->set_y((index / 10) * 100 + 12); | |
1199 rect->set_width(9); | |
1200 rect->set_height(8); | |
1201 return true; | |
1202 } | |
1203 | |
1204 gfx::Rect GetCaretBounds() { | |
1205 return gfx::Rect(1, 2, 3, 4); | |
1206 } | |
1207 | |
1208 private: | |
1209 uint32 layout_prepared_character_num_; | |
1210 | |
1211 DISALLOW_COPY_AND_ASSIGN(GetTextExtTestCallback); | |
1212 }; | |
1213 | |
1214 TEST_F(TSFTextStoreTest, GetTextExtTest) { | |
1215 GetTextExtTestCallback callback(text_store_); | |
1216 EXPECT_CALL(text_input_client_, GetCaretBounds()) | |
1217 .WillRepeatedly(Invoke(&callback, | |
1218 &GetTextExtTestCallback::GetCaretBounds)); | |
1219 | |
1220 EXPECT_CALL(text_input_client_, GetCompositionCharacterBounds(_, _)) | |
1221 .WillRepeatedly( | |
1222 Invoke(&callback, | |
1223 &GetTextExtTestCallback::GetCompositionCharacterBounds)); | |
1224 | |
1225 EXPECT_CALL(*sink_, OnLockGranted(_)) | |
1226 .WillOnce(Invoke(&callback, &GetTextExtTestCallback::LockGranted)); | |
1227 | |
1228 HRESULT result = kInvalidResult; | |
1229 EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READ, &result)); | |
1230 EXPECT_EQ(S_OK, result); | |
1231 } | |
1232 | |
1233 TEST_F(TSFTextStoreTest, RequestSupportedAttrs) { | |
1234 EXPECT_CALL(text_input_client_, GetTextInputType()) | |
1235 .WillRepeatedly(Return(TEXT_INPUT_TYPE_TEXT)); | |
1236 EXPECT_CALL(text_input_client_, GetTextInputMode()) | |
1237 .WillRepeatedly(Return(TEXT_INPUT_MODE_DEFAULT)); | |
1238 | |
1239 EXPECT_HRESULT_FAILED(text_store_->RequestSupportedAttrs(0, 1, NULL)); | |
1240 | |
1241 const TS_ATTRID kUnknownAttributes[] = {GUID_NULL}; | |
1242 EXPECT_HRESULT_FAILED(text_store_->RequestSupportedAttrs( | |
1243 0, arraysize(kUnknownAttributes), kUnknownAttributes)) | |
1244 << "Must fail for unknown attributes"; | |
1245 | |
1246 const TS_ATTRID kAttributes[] = {GUID_NULL, GUID_PROP_INPUTSCOPE, GUID_NULL}; | |
1247 EXPECT_EQ(S_OK, text_store_->RequestSupportedAttrs( | |
1248 0, arraysize(kAttributes), kAttributes)) | |
1249 << "InputScope must be supported"; | |
1250 | |
1251 { | |
1252 SCOPED_TRACE("Check if RequestSupportedAttrs fails while focus is lost"); | |
1253 // Emulate focus lost | |
1254 text_store_->SetFocusedTextInputClient(NULL, NULL); | |
1255 EXPECT_HRESULT_FAILED(text_store_->RequestSupportedAttrs(0, 0, NULL)); | |
1256 EXPECT_HRESULT_FAILED(text_store_->RequestSupportedAttrs( | |
1257 0, arraysize(kAttributes), kAttributes)); | |
1258 } | |
1259 } | |
1260 | |
1261 TEST_F(TSFTextStoreTest, RetrieveRequestedAttrs) { | |
1262 EXPECT_CALL(text_input_client_, GetTextInputType()) | |
1263 .WillRepeatedly(Return(TEXT_INPUT_TYPE_TEXT)); | |
1264 EXPECT_CALL(text_input_client_, GetTextInputMode()) | |
1265 .WillRepeatedly(Return(TEXT_INPUT_MODE_DEFAULT)); | |
1266 | |
1267 ULONG num_copied = 0xfffffff; | |
1268 EXPECT_HRESULT_FAILED(text_store_->RetrieveRequestedAttrs( | |
1269 1, NULL, &num_copied)); | |
1270 | |
1271 { | |
1272 SCOPED_TRACE("Make sure if InputScope is supported"); | |
1273 TS_ATTRVAL buffer[2] = {}; | |
1274 num_copied = 0xfffffff; | |
1275 ASSERT_EQ(S_OK, text_store_->RetrieveRequestedAttrs( | |
1276 arraysize(buffer), buffer, &num_copied)); | |
1277 bool input_scope_found = false; | |
1278 for (size_t i = 0; i < num_copied; ++i) { | |
1279 base::win::ScopedVariant variant; | |
1280 // Move ownership from |buffer[i].varValue| to |variant|. | |
1281 std::swap(*variant.Receive(), buffer[i].varValue); | |
1282 if (IsEqualGUID(buffer[i].idAttr, GUID_PROP_INPUTSCOPE)) { | |
1283 EXPECT_EQ(VT_UNKNOWN, variant.type()); | |
1284 base::win::ScopedComPtr<ITfInputScope> input_scope; | |
1285 EXPECT_HRESULT_SUCCEEDED(input_scope.QueryFrom((&variant)->punkVal)); | |
1286 input_scope_found = true; | |
1287 // we do not break here to clean up all the retrieved VARIANTs. | |
1288 } | |
1289 } | |
1290 EXPECT_TRUE(input_scope_found); | |
1291 } | |
1292 { | |
1293 SCOPED_TRACE("Check if RetrieveRequestedAttrs fails while focus is lost"); | |
1294 // Emulate focus lost | |
1295 text_store_->SetFocusedTextInputClient(NULL, NULL); | |
1296 num_copied = 0xfffffff; | |
1297 TS_ATTRVAL buffer[2] = {}; | |
1298 EXPECT_HRESULT_FAILED(text_store_->RetrieveRequestedAttrs( | |
1299 arraysize(buffer), buffer, &num_copied)); | |
1300 } | |
1301 } | |
1302 | |
1303 } // namespace | |
1304 } // namespace ui | |
OLD | NEW |