| 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 |