text_input_unittest.cc 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789
  1. // Copyright 2018 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. #include "components/exo/text_input.h"
  5. #include <memory>
  6. #include <string>
  7. #include "ash/keyboard/ui/keyboard_ui_controller.h"
  8. #include "base/strings/utf_string_conversions.h"
  9. #include "components/exo/buffer.h"
  10. #include "components/exo/seat.h"
  11. #include "components/exo/shell_surface.h"
  12. #include "components/exo/surface.h"
  13. #include "components/exo/test/exo_test_base.h"
  14. #include "components/exo/test/exo_test_helper.h"
  15. #include "testing/gmock/include/gmock/gmock.h"
  16. #include "ui/aura/client/focus_client.h"
  17. #include "ui/aura/window_tree_host.h"
  18. #include "ui/base/ime/ash/input_method_manager.h"
  19. #include "ui/base/ime/ash/mock_input_method_manager.h"
  20. #include "ui/base/ime/composition_text.h"
  21. #include "ui/base/ime/input_method_observer.h"
  22. #include "ui/events/keycodes/dom/dom_code.h"
  23. #include "ui/views/widget/widget.h"
  24. using testing::_;
  25. namespace exo {
  26. namespace {
  27. ui::CompositionText GenerateCompositionText(const std::u16string& text) {
  28. ui::CompositionText t;
  29. t.text = text;
  30. t.selection = gfx::Range(1u);
  31. t.ime_text_spans.push_back(
  32. ui::ImeTextSpan(ui::ImeTextSpan::Type::kComposition, 0, t.text.size(),
  33. ui::ImeTextSpan::Thickness::kThick));
  34. return t;
  35. }
  36. class MockTextInputDelegate : public TextInput::Delegate {
  37. public:
  38. MockTextInputDelegate() = default;
  39. MockTextInputDelegate(const MockTextInputDelegate&) = delete;
  40. MockTextInputDelegate& operator=(const MockTextInputDelegate&) = delete;
  41. // TextInput::Delegate:
  42. MOCK_METHOD(void, Activated, (), ());
  43. MOCK_METHOD(void, Deactivated, (), ());
  44. MOCK_METHOD(void, OnVirtualKeyboardVisibilityChanged, (bool), ());
  45. MOCK_METHOD(void, SetCompositionText, (const ui::CompositionText&), ());
  46. MOCK_METHOD(void, Commit, (const std::u16string&), ());
  47. MOCK_METHOD(void, SetCursor, (base::StringPiece16, const gfx::Range&), ());
  48. MOCK_METHOD(void,
  49. DeleteSurroundingText,
  50. (base::StringPiece16, const gfx::Range&),
  51. ());
  52. MOCK_METHOD(void, SendKey, (const ui::KeyEvent&), ());
  53. MOCK_METHOD(void, OnLanguageChanged, (const std::string&), ());
  54. MOCK_METHOD(void,
  55. OnTextDirectionChanged,
  56. (base::i18n::TextDirection direction),
  57. ());
  58. MOCK_METHOD(void,
  59. SetCompositionFromExistingText,
  60. (base::StringPiece16,
  61. const gfx::Range&,
  62. const gfx::Range&,
  63. const std::vector<ui::ImeTextSpan>& ui_ime_text_spans),
  64. ());
  65. MOCK_METHOD(void,
  66. ClearGrammarFragments,
  67. (base::StringPiece16, const gfx::Range&),
  68. ());
  69. MOCK_METHOD(void,
  70. AddGrammarFragment,
  71. (base::StringPiece16, const ui::GrammarFragment&),
  72. ());
  73. MOCK_METHOD(void,
  74. SetAutocorrectRange,
  75. (base::StringPiece16, const gfx::Range&),
  76. ());
  77. MOCK_METHOD(void,
  78. OnVirtualKeyboardOccludedBoundsChanged,
  79. (const gfx::Rect&),
  80. ());
  81. };
  82. class TestingInputMethodObserver : public ui::InputMethodObserver {
  83. public:
  84. explicit TestingInputMethodObserver(ui::InputMethod* input_method)
  85. : input_method_(input_method) {
  86. input_method_->AddObserver(this);
  87. }
  88. TestingInputMethodObserver(const TestingInputMethodObserver&) = delete;
  89. TestingInputMethodObserver& operator=(const TestingInputMethodObserver&) =
  90. delete;
  91. ~TestingInputMethodObserver() override {
  92. input_method_->RemoveObserver(this);
  93. }
  94. // ui::InputMethodObserver
  95. MOCK_METHOD(void, OnFocus, (), ());
  96. MOCK_METHOD(void, OnBlur, (), ());
  97. MOCK_METHOD(void, OnCaretBoundsChanged, (const ui::TextInputClient*), ());
  98. MOCK_METHOD(void, OnTextInputStateChanged, (const ui::TextInputClient*), ());
  99. MOCK_METHOD(void, OnInputMethodDestroyed, (const ui::InputMethod*), ());
  100. MOCK_METHOD(void, OnVirtualKeyboardVisibilityChangedIfEnabled, (bool), ());
  101. private:
  102. ui::InputMethod* input_method_ = nullptr;
  103. };
  104. class TextInputTest : public test::ExoTestBase {
  105. public:
  106. class TestSurface {
  107. public:
  108. void SetUp(test::ExoTestHelper* exo_test_helper);
  109. void TearDown();
  110. Surface* surface() { return surface_.get(); }
  111. private:
  112. std::unique_ptr<Buffer> buffer_;
  113. std::unique_ptr<Surface> surface_;
  114. std::unique_ptr<ShellSurface> shell_surface_;
  115. };
  116. TextInputTest() = default;
  117. TextInputTest(const TextInputTest&) = delete;
  118. TextInputTest& operator=(const TextInputTest&) = delete;
  119. void SetUp() override {
  120. test::ExoTestBase::SetUp();
  121. text_input_ =
  122. std::make_unique<TextInput>(std::make_unique<MockTextInputDelegate>());
  123. seat_ = std::make_unique<Seat>();
  124. test_surface_.SetUp(exo_test_helper());
  125. }
  126. void TearDown() override {
  127. test_surface_.TearDown();
  128. seat_.reset();
  129. text_input_.reset();
  130. test::ExoTestBase::TearDown();
  131. }
  132. protected:
  133. TextInput* text_input() { return text_input_.get(); }
  134. void DestroyTextInput() { text_input_.reset(); }
  135. MockTextInputDelegate* delegate() {
  136. return static_cast<MockTextInputDelegate*>(text_input_->delegate());
  137. }
  138. Surface* surface() { return test_surface_.surface(); }
  139. Seat* seat() { return seat_.get(); }
  140. ui::InputMethod* GetInputMethod() {
  141. return surface()->window()->GetHost()->GetInputMethod();
  142. }
  143. void SetCompositionText(const std::u16string& utf16) {
  144. ui::CompositionText t = GenerateCompositionText(utf16);
  145. EXPECT_CALL(*delegate(), SetCompositionText(t)).Times(1);
  146. text_input()->SetCompositionText(t);
  147. }
  148. private:
  149. std::unique_ptr<TextInput> text_input_;
  150. std::unique_ptr<Seat> seat_;
  151. TestSurface test_surface_;
  152. };
  153. void TextInputTest::TestSurface::SetUp(test::ExoTestHelper* exo_test_helper) {
  154. gfx::Size buffer_size(32, 32);
  155. buffer_ = std::make_unique<Buffer>(
  156. exo_test_helper->CreateGpuMemoryBuffer(buffer_size));
  157. surface_ = std::make_unique<Surface>();
  158. shell_surface_ = std::make_unique<ShellSurface>(surface_.get());
  159. surface_->Attach(buffer_.get());
  160. surface_->Commit();
  161. gfx::Point origin(100, 100);
  162. shell_surface_->SetGeometry(gfx::Rect(origin, buffer_size));
  163. }
  164. void TextInputTest::TestSurface::TearDown() {
  165. shell_surface_.reset();
  166. surface_.reset();
  167. buffer_.reset();
  168. }
  169. TEST_F(TextInputTest, Activate) {
  170. EXPECT_EQ(ui::TEXT_INPUT_TYPE_NONE, text_input()->GetTextInputType());
  171. EXPECT_EQ(ui::TEXT_INPUT_MODE_DEFAULT, text_input()->GetTextInputMode());
  172. EXPECT_CALL(*delegate(), Activated).Times(1);
  173. text_input()->Activate(seat(), surface());
  174. testing::Mock::VerifyAndClearExpectations(delegate());
  175. EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT, text_input()->GetTextInputType());
  176. EXPECT_EQ(ui::TEXT_INPUT_MODE_TEXT, text_input()->GetTextInputMode());
  177. EXPECT_EQ(0, text_input()->GetTextInputFlags());
  178. EXPECT_CALL(*delegate(), Deactivated).Times(1);
  179. text_input()->Deactivate();
  180. testing::Mock::VerifyAndClearExpectations(delegate());
  181. EXPECT_EQ(ui::TEXT_INPUT_TYPE_NONE, text_input()->GetTextInputType());
  182. EXPECT_EQ(ui::TEXT_INPUT_MODE_DEFAULT, text_input()->GetTextInputMode());
  183. }
  184. TEST_F(TextInputTest, ActivationRequiresFocus) {
  185. TestingInputMethodObserver observer(GetInputMethod());
  186. // Activation doesn't occur until the surface (window) is actually focused.
  187. aura::client::FocusClient* focus_client =
  188. aura::client::GetFocusClient(ash::Shell::GetPrimaryRootWindow());
  189. focus_client->FocusWindow(nullptr);
  190. EXPECT_CALL(observer, OnTextInputStateChanged(_)).Times(0);
  191. EXPECT_CALL(*delegate(), Activated).Times(0);
  192. text_input()->Activate(seat(), surface());
  193. testing::Mock::VerifyAndClearExpectations(&observer);
  194. testing::Mock::VerifyAndClearExpectations(delegate());
  195. EXPECT_CALL(observer, OnTextInputStateChanged(text_input())).Times(1);
  196. EXPECT_CALL(*delegate(), Activated).Times(1);
  197. focus_client->FocusWindow(surface()->window());
  198. testing::Mock::VerifyAndClearExpectations(&observer);
  199. testing::Mock::VerifyAndClearExpectations(delegate());
  200. // Deactivation occurs on blur even if TextInput::Deactivate() isn't called.
  201. EXPECT_CALL(observer, OnTextInputStateChanged(nullptr)).Times(1);
  202. EXPECT_CALL(*delegate(), Deactivated).Times(1);
  203. focus_client->FocusWindow(nullptr);
  204. testing::Mock::VerifyAndClearExpectations(&observer);
  205. testing::Mock::VerifyAndClearExpectations(delegate());
  206. EXPECT_CALL(observer, OnTextInputStateChanged(nullptr)).Times(0);
  207. EXPECT_CALL(*delegate(), Deactivated).Times(0);
  208. text_input()->Deactivate();
  209. testing::Mock::VerifyAndClearExpectations(&observer);
  210. testing::Mock::VerifyAndClearExpectations(delegate());
  211. }
  212. TEST_F(TextInputTest, MultipleActivations) {
  213. TestingInputMethodObserver observer(GetInputMethod());
  214. aura::client::FocusClient* focus_client =
  215. aura::client::GetFocusClient(ash::Shell::GetPrimaryRootWindow());
  216. TestSurface surface2;
  217. surface2.SetUp(exo_test_helper());
  218. // Activate surface 1.
  219. focus_client->FocusWindow(surface()->window());
  220. EXPECT_CALL(observer, OnTextInputStateChanged(text_input())).Times(1);
  221. EXPECT_CALL(*delegate(), Activated).Times(1);
  222. text_input()->Activate(seat(), surface());
  223. testing::Mock::VerifyAndClearExpectations(&observer);
  224. testing::Mock::VerifyAndClearExpectations(delegate());
  225. // Attempting to activate the same surface is a no-op.
  226. EXPECT_CALL(*delegate(), Activated).Times(0);
  227. text_input()->Activate(seat(), surface());
  228. testing::Mock::VerifyAndClearExpectations(delegate());
  229. // Activating a non-focused surface causes deactivation until focus.
  230. EXPECT_CALL(observer, OnTextInputStateChanged(nullptr)).Times(1);
  231. EXPECT_CALL(*delegate(), Deactivated).Times(1);
  232. text_input()->Activate(seat(), surface2.surface());
  233. testing::Mock::VerifyAndClearExpectations(&observer);
  234. testing::Mock::VerifyAndClearExpectations(delegate());
  235. EXPECT_CALL(observer, OnTextInputStateChanged(text_input())).Times(1);
  236. EXPECT_CALL(*delegate(), Activated).Times(1);
  237. focus_client->FocusWindow(surface2.surface()->window());
  238. testing::Mock::VerifyAndClearExpectations(&observer);
  239. testing::Mock::VerifyAndClearExpectations(delegate());
  240. }
  241. TEST_F(TextInputTest, ShowVirtualKeyboardIfEnabled) {
  242. TestingInputMethodObserver observer(GetInputMethod());
  243. EXPECT_CALL(observer, OnTextInputStateChanged(text_input())).Times(1);
  244. EXPECT_CALL(*delegate(), Activated).Times(1);
  245. text_input()->Activate(seat(), surface());
  246. testing::Mock::VerifyAndClearExpectations(&observer);
  247. testing::Mock::VerifyAndClearExpectations(delegate());
  248. // Currently, Virtual Keyboard Controller is not set up, and so
  249. // the virtual keyboard events are gone. Here, we capture the callback
  250. // from the observer and translate it to the ones of
  251. // VirtualKeyboardControllerObserver event as if it is done via
  252. // real VirtualKeyboardController implementation.
  253. EXPECT_CALL(observer, OnVirtualKeyboardVisibilityChangedIfEnabled)
  254. .WillOnce(testing::Invoke([this](bool should_show) {
  255. if (should_show)
  256. text_input()->OnKeyboardVisible(gfx::Rect());
  257. else
  258. text_input()->OnKeyboardHidden();
  259. }));
  260. EXPECT_CALL(*delegate(), OnVirtualKeyboardVisibilityChanged(true)).Times(1);
  261. text_input()->ShowVirtualKeyboardIfEnabled();
  262. testing::Mock::VerifyAndClearExpectations(&observer);
  263. testing::Mock::VerifyAndClearExpectations(delegate());
  264. EXPECT_CALL(observer, OnTextInputStateChanged(nullptr)).Times(1);
  265. EXPECT_CALL(*delegate(), Deactivated).Times(1);
  266. text_input()->Deactivate();
  267. testing::Mock::VerifyAndClearExpectations(&observer);
  268. testing::Mock::VerifyAndClearExpectations(delegate());
  269. }
  270. TEST_F(TextInputTest, ShowVirtualKeyboardIfEnabledBeforeActivated) {
  271. TestingInputMethodObserver observer(GetInputMethod());
  272. // ShowVirtualKeyboardIfEnabled before activation.
  273. text_input()->ShowVirtualKeyboardIfEnabled();
  274. EXPECT_CALL(observer, OnTextInputStateChanged(text_input())).Times(1);
  275. // Currently, Virtual Keyboard Controller is not set up, and so
  276. // the virtual keyboard events are gone. Here, we capture the callback
  277. // from the observer and translate it to the ones of
  278. // VirtualKeyboardControllerObserver event as if it is done via
  279. // real VirtualKeyboardController implementation.
  280. EXPECT_CALL(observer, OnVirtualKeyboardVisibilityChangedIfEnabled)
  281. .WillOnce(testing::Invoke([this](bool should_show) {
  282. if (should_show)
  283. text_input()->OnKeyboardVisible(gfx::Rect());
  284. else
  285. text_input()->OnKeyboardHidden();
  286. }));
  287. EXPECT_CALL(*delegate(), Activated).Times(1);
  288. EXPECT_CALL(*delegate(), OnVirtualKeyboardVisibilityChanged(true)).Times(1);
  289. text_input()->Activate(seat(), surface());
  290. testing::Mock::VerifyAndClearExpectations(&observer);
  291. testing::Mock::VerifyAndClearExpectations(delegate());
  292. EXPECT_CALL(*delegate(), Deactivated).Times(1);
  293. }
  294. TEST_F(TextInputTest, VirtualKeyboardObserver) {
  295. EXPECT_EQ(ui::TEXT_INPUT_TYPE_NONE, text_input()->GetTextInputType());
  296. EXPECT_EQ(ui::TEXT_INPUT_MODE_DEFAULT, text_input()->GetTextInputMode());
  297. EXPECT_CALL(*delegate(), Activated).Times(1);
  298. text_input()->Activate(seat(), surface());
  299. testing::Mock::VerifyAndClearExpectations(delegate());
  300. // Disable virtual keyboard so that GetVirtualKeyboardController() starts
  301. // to return nullptr.
  302. auto* input_method_manager =
  303. static_cast<ash::input_method::MockInputMethodManager*>(
  304. ash::input_method::InputMethodManager::Get());
  305. input_method_manager->SetVirtualKeyboardEnabled(false);
  306. EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT, text_input()->GetTextInputType());
  307. EXPECT_EQ(ui::TEXT_INPUT_MODE_TEXT, text_input()->GetTextInputMode());
  308. EXPECT_EQ(0, text_input()->GetTextInputFlags());
  309. EXPECT_CALL(*delegate(), Deactivated).Times(1);
  310. text_input()->Deactivate();
  311. testing::Mock::VerifyAndClearExpectations(delegate());
  312. EXPECT_EQ(ui::TEXT_INPUT_TYPE_NONE, text_input()->GetTextInputType());
  313. EXPECT_EQ(ui::TEXT_INPUT_MODE_DEFAULT, text_input()->GetTextInputMode());
  314. // Destroy the text_input.
  315. // Because text_input used not to be removed from VirtualKeyboardController
  316. // as its observer, this used to cause a dangling pointer problem, so
  317. // caused the crash in the following DismissVirtualKeyboard.
  318. DestroyTextInput();
  319. input_method_manager->DismissVirtualKeyboard();
  320. }
  321. TEST_F(TextInputTest, SetTypeModeFlag) {
  322. TestingInputMethodObserver observer(GetInputMethod());
  323. EXPECT_CALL(observer, OnTextInputStateChanged(text_input())).Times(1);
  324. EXPECT_CALL(*delegate(), Activated).Times(1);
  325. text_input()->Activate(seat(), surface());
  326. testing::Mock::VerifyAndClearExpectations(&observer);
  327. testing::Mock::VerifyAndClearExpectations(delegate());
  328. EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT, text_input()->GetTextInputType());
  329. EXPECT_EQ(ui::TEXT_INPUT_MODE_TEXT, text_input()->GetTextInputMode());
  330. EXPECT_EQ(0, text_input()->GetTextInputFlags());
  331. EXPECT_TRUE(text_input()->ShouldDoLearning());
  332. int flags = ui::TEXT_INPUT_FLAG_AUTOCOMPLETE_OFF |
  333. ui::TEXT_INPUT_FLAG_AUTOCAPITALIZE_NONE;
  334. EXPECT_CALL(observer, OnTextInputStateChanged(text_input())).Times(1);
  335. text_input()->SetTypeModeFlags(ui::TEXT_INPUT_TYPE_URL,
  336. ui::TEXT_INPUT_MODE_URL, flags, false);
  337. testing::Mock::VerifyAndClearExpectations(&observer);
  338. EXPECT_EQ(ui::TEXT_INPUT_TYPE_URL, text_input()->GetTextInputType());
  339. EXPECT_EQ(ui::TEXT_INPUT_MODE_URL, text_input()->GetTextInputMode());
  340. EXPECT_EQ(flags, text_input()->GetTextInputFlags());
  341. EXPECT_FALSE(text_input()->ShouldDoLearning());
  342. EXPECT_CALL(*delegate(), Deactivated).Times(1);
  343. }
  344. TEST_F(TextInputTest, CaretBounds) {
  345. TestingInputMethodObserver observer(GetInputMethod());
  346. EXPECT_CALL(observer, OnTextInputStateChanged(text_input())).Times(1);
  347. EXPECT_CALL(*delegate(), Activated).Times(1);
  348. text_input()->Activate(seat(), surface());
  349. testing::Mock::VerifyAndClearExpectations(&observer);
  350. testing::Mock::VerifyAndClearExpectations(delegate());
  351. gfx::Rect bounds(10, 10, 0, 16);
  352. EXPECT_CALL(observer, OnCaretBoundsChanged(text_input())).Times(1);
  353. text_input()->SetCaretBounds(bounds);
  354. testing::Mock::VerifyAndClearExpectations(&observer);
  355. EXPECT_EQ(bounds.size().ToString(),
  356. text_input()->GetCaretBounds().size().ToString());
  357. gfx::Point origin = surface()->window()->GetBoundsInScreen().origin();
  358. origin += bounds.OffsetFromOrigin();
  359. EXPECT_EQ(origin.ToString(),
  360. text_input()->GetCaretBounds().origin().ToString());
  361. EXPECT_CALL(*delegate(), Deactivated).Times(1);
  362. }
  363. TEST_F(TextInputTest, CompositionText) {
  364. EXPECT_FALSE(text_input()->HasCompositionText());
  365. SetCompositionText(u"composition");
  366. EXPECT_TRUE(text_input()->HasCompositionText());
  367. ui::CompositionText empty;
  368. EXPECT_CALL(*delegate(), SetCompositionText(empty)).Times(1);
  369. text_input()->ClearCompositionText();
  370. EXPECT_FALSE(text_input()->HasCompositionText());
  371. }
  372. TEST_F(TextInputTest, CompositionTextEmpty) {
  373. SetCompositionText(u"");
  374. EXPECT_CALL(*delegate(), SetCompositionText(_)).Times(0);
  375. text_input()->ClearCompositionText();
  376. }
  377. TEST_F(TextInputTest, ConfirmCompositionText) {
  378. SetCompositionText(u"composition");
  379. EXPECT_CALL(*delegate(), Commit(std::u16string(u"composition"))).Times(1);
  380. const size_t composition_text_length =
  381. text_input()->ConfirmCompositionText(/*keep_selection=*/false);
  382. EXPECT_EQ(composition_text_length, 11u);
  383. testing::Mock::VerifyAndClearExpectations(delegate());
  384. // Second call should be the empty commit string.
  385. EXPECT_EQ(0u, text_input()->ConfirmCompositionText(/*keep_selection=*/false));
  386. EXPECT_FALSE(text_input()->HasCompositionText());
  387. }
  388. TEST_F(TextInputTest, ConfirmCompositionTextKeepSelection) {
  389. constexpr char16_t kCompositionText[] = u"composition";
  390. SetCompositionText(kCompositionText);
  391. text_input()->SetSurroundingText(kCompositionText, gfx::Range(2, 3));
  392. EXPECT_CALL(*delegate(), SetCursor(base::StringPiece16(kCompositionText),
  393. gfx::Range(2, 3)))
  394. .Times(1);
  395. EXPECT_CALL(*delegate(), Commit(std::u16string(kCompositionText))).Times(1);
  396. const uint32_t composition_text_length =
  397. text_input()->ConfirmCompositionText(/*keep_selection=*/true);
  398. EXPECT_EQ(composition_text_length, static_cast<uint32_t>(11));
  399. testing::Mock::VerifyAndClearExpectations(delegate());
  400. // Second call should be the empty commit string.
  401. EXPECT_EQ(0u, text_input()->ConfirmCompositionText(/*keep_selection=*/true));
  402. EXPECT_FALSE(text_input()->HasCompositionText());
  403. }
  404. TEST_F(TextInputTest, ResetCompositionText) {
  405. SetCompositionText(u"composition");
  406. text_input()->Reset();
  407. EXPECT_EQ(0u, text_input()->ConfirmCompositionText(/*keep_selection=*/false));
  408. EXPECT_FALSE(text_input()->HasCompositionText());
  409. }
  410. TEST_F(TextInputTest, Commit) {
  411. std::u16string s = u"commit text";
  412. EXPECT_CALL(*delegate(), Commit(s)).Times(1);
  413. text_input()->InsertText(
  414. s, ui::TextInputClient::InsertTextCursorBehavior::kMoveCursorAfterText);
  415. EXPECT_FALSE(text_input()->HasCompositionText());
  416. }
  417. TEST_F(TextInputTest, InsertChar) {
  418. text_input()->Activate(seat(), surface());
  419. ui::KeyEvent ev(ui::ET_KEY_PRESSED, ui::VKEY_RETURN, 0);
  420. EXPECT_CALL(*delegate(), SendKey(testing::Ref(ev))).Times(1);
  421. text_input()->InsertChar(ev);
  422. }
  423. TEST_F(TextInputTest, InsertCharCtrlV) {
  424. text_input()->Activate(seat(), surface());
  425. // CTRL+V is interpreted as non-IME consumed KeyEvent, so should
  426. // not be sent.
  427. ui::KeyEvent ev(ui::ET_KEY_PRESSED, ui::VKEY_V, ui::EF_CONTROL_DOWN);
  428. EXPECT_CALL(*delegate(), SendKey(_)).Times(0);
  429. text_input()->InsertChar(ev);
  430. }
  431. TEST_F(TextInputTest, InsertCharNormalKey) {
  432. text_input()->Activate(seat(), surface());
  433. char16_t ch = 'x';
  434. ui::KeyEvent ev(ch, ui::VKEY_X, ui::DomCode::NONE, 0);
  435. EXPECT_CALL(*delegate(), SendKey(testing::Ref(ev))).Times(1);
  436. text_input()->InsertChar(ev);
  437. }
  438. TEST_F(TextInputTest, SurroundingText) {
  439. TestingInputMethodObserver observer(GetInputMethod());
  440. gfx::Range range;
  441. EXPECT_FALSE(text_input()->GetTextRange(&range));
  442. EXPECT_FALSE(text_input()->GetCompositionTextRange(&range));
  443. EXPECT_FALSE(text_input()->GetEditableSelectionRange(&range));
  444. std::u16string got_text;
  445. EXPECT_FALSE(text_input()->GetTextFromRange(gfx::Range(0, 1), &got_text));
  446. text_input()->Activate(seat(), surface());
  447. EXPECT_CALL(observer, OnCaretBoundsChanged(text_input())).Times(1);
  448. std::u16string text = u"surrounding\u3000text";
  449. text_input()->SetSurroundingText(text, gfx::Range(11, 12));
  450. testing::Mock::VerifyAndClearExpectations(&observer);
  451. EXPECT_TRUE(text_input()->GetTextRange(&range));
  452. EXPECT_EQ(gfx::Range(0, text.size()).ToString(), range.ToString());
  453. EXPECT_FALSE(text_input()->GetCompositionTextRange(&range));
  454. EXPECT_TRUE(text_input()->GetEditableSelectionRange(&range));
  455. EXPECT_EQ(gfx::Range(11, 12).ToString(), range.ToString());
  456. EXPECT_TRUE(text_input()->GetTextFromRange(gfx::Range(11, 12), &got_text));
  457. EXPECT_EQ(text.substr(11, 1), got_text);
  458. EXPECT_CALL(*delegate(), DeleteSurroundingText(base::StringPiece16(text),
  459. gfx::Range(11, 12)))
  460. .Times(1);
  461. text_input()->ExtendSelectionAndDelete(0, 0);
  462. testing::Mock::VerifyAndClearExpectations(delegate());
  463. size_t composition_size = std::string("composition").size();
  464. SetCompositionText(u"composition");
  465. EXPECT_TRUE(text_input()->GetCompositionTextRange(&range));
  466. EXPECT_EQ(gfx::Range(11, 11 + composition_size).ToString(), range.ToString());
  467. EXPECT_TRUE(text_input()->GetEditableSelectionRange(&range));
  468. EXPECT_EQ(gfx::Range(11, 12).ToString(), range.ToString());
  469. }
  470. TEST_F(TextInputTest, SetEditableSelectionRange) {
  471. SetCompositionText(u"text");
  472. text_input()->SetSurroundingText(u"text", gfx::Range(1, 2));
  473. // Should commit composition text and set selection range.
  474. EXPECT_CALL(*delegate(),
  475. SetCursor(base::StringPiece16(u"text"), gfx::Range(0, 3)))
  476. .Times(1);
  477. EXPECT_CALL(*delegate(), Commit(std::u16string(u"text"))).Times(1);
  478. EXPECT_TRUE(text_input()->SetEditableSelectionRange(gfx::Range(0, 3)));
  479. testing::Mock::VerifyAndClearExpectations(delegate());
  480. }
  481. TEST_F(TextInputTest, GetTextFromRange) {
  482. std::u16string text = u"surrounding text";
  483. text_input()->SetSurroundingText(text, gfx::Range(11, 12));
  484. const struct {
  485. gfx::Range range;
  486. std::u16string expected;
  487. } kTestCases[] = {
  488. {gfx::Range(0, 3), u"sur"},
  489. {gfx::Range(10, 16), u"g text"},
  490. {gfx::Range(6, 9), u"ndi"},
  491. };
  492. for (auto& c : kTestCases) {
  493. std::u16string result;
  494. EXPECT_TRUE(text_input()->GetTextFromRange(c.range, &result))
  495. << c.range.ToString();
  496. EXPECT_EQ(c.expected, result) << c.range.ToString();
  497. }
  498. }
  499. TEST_F(TextInputTest, SetCompositionFromExistingText) {
  500. // Try invalid cases fist. No delegate invocation is expected.
  501. EXPECT_CALL(*delegate(), SetCompositionFromExistingText(_, _, _, _)).Times(0);
  502. // Not set up surrounding text yet, so any request should fail.
  503. EXPECT_FALSE(text_input()->SetCompositionFromExistingText(
  504. gfx::Range::InvalidRange(), {}));
  505. EXPECT_FALSE(
  506. text_input()->SetCompositionFromExistingText(gfx::Range(0, 1), {}));
  507. text_input()->SetSurroundingText(u"surrounding text", gfx::Range(5, 5));
  508. // Invalid range.
  509. EXPECT_FALSE(text_input()->SetCompositionFromExistingText(
  510. gfx::Range::InvalidRange(), {}));
  511. // Outside of surrounding text.
  512. EXPECT_FALSE(
  513. text_input()->SetCompositionFromExistingText(gfx::Range(100, 200), {}));
  514. // Crossing the boundary of surrounding text.
  515. EXPECT_FALSE(
  516. text_input()->SetCompositionFromExistingText(gfx::Range(5, 100), {}));
  517. // Span has the range outside of the new composition.
  518. EXPECT_FALSE(text_input()->SetCompositionFromExistingText(
  519. gfx::Range(3, 10),
  520. {ui::ImeTextSpan(ui::ImeTextSpan::Type::kComposition, 7, 10)}));
  521. // Span has the range crossing the composition boundary.
  522. EXPECT_FALSE(text_input()->SetCompositionFromExistingText(
  523. gfx::Range(3, 10),
  524. {ui::ImeTextSpan(ui::ImeTextSpan::Type::kComposition, 2, 10)}));
  525. // Verify mock behavior. No delegate call is expected until now.
  526. testing::Mock::VerifyAndClearExpectations(delegate());
  527. // Checking a simple valid case.
  528. EXPECT_CALL(*delegate(), SetCompositionFromExistingText(_, _, _, _)).Times(1);
  529. EXPECT_TRUE(
  530. text_input()->SetCompositionFromExistingText(gfx::Range(3, 10), {}));
  531. testing::Mock::VerifyAndClearExpectations(delegate());
  532. // Anothe valid case with span.
  533. EXPECT_CALL(*delegate(), SetCompositionFromExistingText(_, _, _, _)).Times(1);
  534. EXPECT_TRUE(text_input()->SetCompositionFromExistingText(
  535. gfx::Range(3, 10),
  536. {ui::ImeTextSpan(ui::ImeTextSpan::Type::kComposition, 1, 5)}));
  537. testing::Mock::VerifyAndClearExpectations(delegate());
  538. }
  539. TEST_F(TextInputTest,
  540. CompositionRangeSetFromCursorWhenSetCompositionTextCalled) {
  541. text_input()->SetSurroundingText(u"surrounding text", gfx::Range(5, 5));
  542. std::u16string composition_text = u"composing";
  543. SetCompositionText(composition_text);
  544. gfx::Range composition_range;
  545. EXPECT_TRUE(text_input()->HasCompositionText());
  546. EXPECT_TRUE(text_input()->GetCompositionTextRange(&composition_range));
  547. EXPECT_EQ(composition_range, gfx::Range(5, 5 + composition_text.length()));
  548. }
  549. TEST_F(TextInputTest,
  550. CompositionRangeSetWhenSetCompositionFromExistingTextCalled) {
  551. text_input()->SetSurroundingText(u"surrounding text", gfx::Range(5, 5));
  552. text_input()->SetCompositionFromExistingText(gfx::Range(3, 6),
  553. std::vector<ui::ImeTextSpan>{});
  554. gfx::Range composition_range;
  555. EXPECT_TRUE(text_input()->HasCompositionText());
  556. EXPECT_TRUE(text_input()->GetCompositionTextRange(&composition_range));
  557. EXPECT_EQ(composition_range, gfx::Range(3, 6));
  558. }
  559. TEST_F(TextInputTest, CorrectTextReturnedAfterSetCompositionTextCalled) {
  560. gfx::Range cursor_pos = gfx::Range(11, 11);
  561. std::u16string surrounding_text = u"surrounding text";
  562. std::u16string composition_text = u" and composition";
  563. ui::CompositionText t = GenerateCompositionText(composition_text);
  564. EXPECT_CALL(*delegate(), SetCompositionText)
  565. .WillOnce(
  566. testing::Invoke([this, cursor_pos, surrounding_text,
  567. composition_text](const ui::CompositionText& t) {
  568. EXPECT_EQ(t.text, composition_text);
  569. // Simulate surrounding text update from wayland.
  570. auto before = surrounding_text.substr(0, cursor_pos.GetMin());
  571. auto after = surrounding_text.substr(cursor_pos.GetMin());
  572. auto new_surrounding = before + t.text + after;
  573. auto new_cursor_pos = cursor_pos.GetMin() + t.text.length();
  574. text_input()->SetSurroundingText(
  575. new_surrounding, gfx::Range(new_cursor_pos, new_cursor_pos));
  576. }));
  577. text_input()->SetSurroundingText(surrounding_text, cursor_pos);
  578. text_input()->SetCompositionText(t);
  579. gfx::Range text_range;
  580. std::u16string text;
  581. EXPECT_TRUE(text_input()->GetTextRange(&text_range));
  582. EXPECT_TRUE(text_input()->GetTextFromRange(text_range, &text));
  583. EXPECT_EQ(text, u"surrounding and composition text");
  584. gfx::Range composing_text_range;
  585. std::u16string composing_text;
  586. EXPECT_TRUE(text_input()->HasCompositionText());
  587. EXPECT_TRUE(text_input()->GetCompositionTextRange(&composing_text_range));
  588. EXPECT_TRUE(
  589. text_input()->GetTextFromRange(composing_text_range, &composing_text));
  590. EXPECT_EQ(composing_text, u" and composition");
  591. }
  592. TEST_F(TextInputTest, SetsAndGetsGrammarFragmentAtCursor) {
  593. ui::GrammarFragment sample_fragment(gfx::Range(1, 5), "sample-suggestion");
  594. text_input()->SetGrammarFragmentAtCursor(absl::nullopt);
  595. EXPECT_EQ(text_input()->GetGrammarFragmentAtCursor(), absl::nullopt);
  596. text_input()->SetGrammarFragmentAtCursor(sample_fragment);
  597. text_input()->SetSurroundingText(u"Sample surrouding text.",
  598. gfx::Range(2, 2));
  599. EXPECT_EQ(text_input()->GetGrammarFragmentAtCursor(), sample_fragment);
  600. }
  601. TEST_F(TextInputTest, ClearGrammarFragments) {
  602. std::u16string surrounding_text = u"Sample surrouding text.";
  603. text_input()->SetSurroundingText(surrounding_text, gfx::Range(2, 2));
  604. gfx::Range range(3, 8);
  605. EXPECT_CALL(*delegate(), ClearGrammarFragments(
  606. base::StringPiece16(surrounding_text), range))
  607. .Times(1);
  608. text_input()->ClearGrammarFragments(range);
  609. }
  610. TEST_F(TextInputTest, AddGrammarFragments) {
  611. std::u16string surrounding_text = u"Sample surrouding text.";
  612. text_input()->SetSurroundingText(surrounding_text, gfx::Range(2, 2));
  613. std::vector<ui::GrammarFragment> fragments = {
  614. ui::GrammarFragment(gfx::Range(0, 5), "one"),
  615. ui::GrammarFragment(gfx::Range(10, 16), "two"),
  616. };
  617. EXPECT_CALL(
  618. *delegate(),
  619. AddGrammarFragment(base::StringPiece16(surrounding_text), fragments[0]))
  620. .Times(1);
  621. EXPECT_CALL(
  622. *delegate(),
  623. AddGrammarFragment(base::StringPiece16(surrounding_text), fragments[1]))
  624. .Times(1);
  625. text_input()->AddGrammarFragments(fragments);
  626. }
  627. TEST_F(TextInputTest, GetAutocorrect) {
  628. std::u16string surrounding_text = u"Sample surrouding text.";
  629. text_input()->SetSurroundingText(surrounding_text, gfx::Range(2, 2));
  630. std::vector<ui::GrammarFragment> fragments = {
  631. ui::GrammarFragment(gfx::Range(0, 5), "one"),
  632. ui::GrammarFragment(gfx::Range(10, 16), "two"),
  633. };
  634. EXPECT_CALL(
  635. *delegate(),
  636. AddGrammarFragment(base::StringPiece16(surrounding_text), fragments[0]))
  637. .Times(1);
  638. EXPECT_CALL(
  639. *delegate(),
  640. AddGrammarFragment(base::StringPiece16(surrounding_text), fragments[1]))
  641. .Times(1);
  642. text_input()->AddGrammarFragments(fragments);
  643. }
  644. TEST_F(TextInputTest, EnsureCaretNotInRect) {
  645. const gfx::Rect bounds(10, 20, 300, 400);
  646. EXPECT_CALL(*delegate(), OnVirtualKeyboardOccludedBoundsChanged(bounds));
  647. text_input()->EnsureCaretNotInRect(bounds);
  648. }
  649. TEST_F(TextInputTest, OnKeyboardHidden) {
  650. const gfx::Rect bounds;
  651. EXPECT_CALL(*delegate(), OnVirtualKeyboardOccludedBoundsChanged(bounds));
  652. EXPECT_CALL(*delegate(), OnVirtualKeyboardVisibilityChanged(false));
  653. text_input()->OnKeyboardHidden();
  654. }
  655. } // anonymous namespace
  656. } // namespace exo