Home | History | Annotate | Download | only in input_method
      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 "base/bind_helpers.h"
      6 #include "chrome/browser/extensions/extension_browsertest.h"
      7 #include "chrome/browser/extensions/extension_test_message_listener.h"
      8 #include "chrome/common/extensions/background_info.h"
      9 #include "chromeos/dbus/dbus_thread_manager.h"
     10 #include "chromeos/dbus/ibus/mock_ibus_client.h"
     11 #include "chromeos/dbus/ibus/mock_ibus_engine_factory_service.h"
     12 #include "chromeos/dbus/ibus/mock_ibus_engine_service.h"
     13 #include "chromeos/dbus/mock_dbus_thread_manager_without_gmock.h"
     14 #include "chromeos/ime/input_method_descriptor.h"
     15 #include "chromeos/ime/input_method_manager.h"
     16 #include "content/public/test/browser_test_utils.h"
     17 #include "content/public/test/test_utils.h"
     18 #include "dbus/mock_bus.h"
     19 
     20 namespace chromeos {
     21 namespace input_method {
     22 namespace {
     23 
     24 const char kIdentityIMEID[] =
     25     "_ext_ime_iafoklpfplgfnoimmaejoeondnjnlcfpIdentityIME";
     26 const char kToUpperIMEID[] =
     27     "_ext_ime_iafoklpfplgfnoimmaejoeondnjnlcfpToUpperIME";
     28 const char kAPIArgumentIMEID[] =
     29     "_ext_ime_iafoklpfplgfnoimmaejoeondnjnlcfpAPIArgumentIME";
     30 
     31 const uint32 kAltKeyMask = 1 << 3;
     32 const uint32 kCtrlKeyMask = 1 << 2;
     33 const uint32 kShiftKeyMask = 1 << 0;
     34 const uint32 kCapsLockMask = 1 << 1;
     35 
     36 // InputMethod extension should work on 1)normal extension, 2)normal extension
     37 // in incognito mode 3)component extension.
     38 enum TestType {
     39   kTestTypeNormal = 0,
     40   kTestTypeIncognito = 1,
     41   kTestTypeComponent = 2,
     42 };
     43 
     44 void OnRegisterComponent(const IBusComponent& ibus_component,
     45                          const IBusClient::RegisterComponentCallback& callback,
     46                          const IBusClient::ErrorCallback& error_callback) {
     47   callback.Run();
     48 }
     49 
     50 class InputMethodEngineIBusBrowserTest
     51     : public ExtensionBrowserTest,
     52       public ::testing::WithParamInterface<TestType> {
     53  public:
     54   InputMethodEngineIBusBrowserTest()
     55       : ExtensionBrowserTest(),
     56         mock_dbus_thread_manager_(NULL) {}
     57   virtual ~InputMethodEngineIBusBrowserTest() {}
     58 
     59   virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
     60     mock_dbus_thread_manager_ = new MockDBusThreadManagerWithoutGMock();
     61     DBusThreadManager::InitializeForTesting(mock_dbus_thread_manager_);
     62     ExtensionBrowserTest::SetUpInProcessBrowserTestFixture();
     63   }
     64 
     65   virtual void TearDownInProcessBrowserTestFixture() OVERRIDE {
     66     DBusThreadManager::Shutdown();
     67     extension_ = NULL;
     68   }
     69 
     70  protected:
     71   void LoadTestInputMethod() {
     72     MockIBusClient* ibus_client = mock_dbus_thread_manager_->mock_ibus_client();
     73     ibus_client->set_register_component_handler(
     74         base::Bind(&OnRegisterComponent));
     75 
     76     // This will load "chrome/test/data/extensions/input_ime"
     77     ExtensionTestMessageListener ime_ready_listener("ReadyToUseImeEvent",
     78                                                     false);
     79     extension_ = LoadExtensionWithType("input_ime", GetParam());
     80     ASSERT_TRUE(extension_);
     81     ASSERT_TRUE(ime_ready_listener.WaitUntilSatisfied());
     82 
     83     // The reason why not EXPECT_EQ is that extension will be reloaded in the
     84     // case of incognito mode switching. Thus registeration will be happend
     85     // multiple times. Calling at least once per engine is sufficient for IBus
     86     // component. Here, there is two engine, thus expectation is at least 4
     87     // times.
     88     EXPECT_LE(3, ibus_client->register_component_call_count());
     89 
     90     // Extension IMEs are not enabled by default.
     91     std::vector<std::string> extension_ime_ids;
     92     extension_ime_ids.push_back(kIdentityIMEID);
     93     extension_ime_ids.push_back(kToUpperIMEID);
     94     extension_ime_ids.push_back(kAPIArgumentIMEID);
     95     InputMethodManager::Get()->SetEnabledExtensionImes(&extension_ime_ids);
     96 
     97     InputMethodDescriptors extension_imes;
     98     InputMethodManager::Get()->GetInputMethodExtensions(&extension_imes);
     99 
    100     // Test IME has two input methods, thus InputMethodManager should have two
    101     // extension IME.
    102     // Note: Even extension is loaded by LoadExtensionAsComponent as above, the
    103     // IME does not managed by ComponentExtensionIMEManager or it's id won't
    104     // start with __comp__. The component extension IME is whitelisted and
    105     // managed by ComponentExtensionIMEManager, but its framework is same as
    106     // normal extension IME.
    107     EXPECT_EQ(3U, extension_imes.size());
    108   }
    109 
    110   const extensions::Extension* LoadExtensionWithType(
    111       const std::string& extension_name, TestType type) {
    112     switch (type) {
    113       case kTestTypeNormal:
    114         return LoadExtension(test_data_dir_.AppendASCII(extension_name));
    115       case kTestTypeIncognito:
    116         return LoadExtensionIncognito(
    117             test_data_dir_.AppendASCII(extension_name));
    118       case kTestTypeComponent:
    119         return LoadExtensionAsComponent(
    120             test_data_dir_.AppendASCII(extension_name));
    121     }
    122     NOTREACHED();
    123     return NULL;
    124   }
    125 
    126   const extensions::Extension* extension_;
    127   MockDBusThreadManagerWithoutGMock* mock_dbus_thread_manager_;
    128   scoped_refptr<dbus::MockBus> mock_bus_;
    129 };
    130 
    131 class KeyEventDoneCallback {
    132  public:
    133   explicit KeyEventDoneCallback(bool expected_argument)
    134       : expected_argument_(expected_argument),
    135         is_called_(false) {}
    136   ~KeyEventDoneCallback() {}
    137 
    138   void Run(bool consumed) {
    139     if (consumed == expected_argument_) {
    140       base::MessageLoop::current()->Quit();
    141       is_called_ = true;
    142     }
    143   }
    144 
    145   void WaitUntilCalled() {
    146     while (!is_called_)
    147       content::RunMessageLoop();
    148   }
    149 
    150  private:
    151   bool expected_argument_;
    152   bool is_called_;
    153 
    154   DISALLOW_COPY_AND_ASSIGN(KeyEventDoneCallback);
    155 };
    156 
    157 INSTANTIATE_TEST_CASE_P(InputMethodEngineIBusBrowserTest,
    158                         InputMethodEngineIBusBrowserTest,
    159                         ::testing::Values(kTestTypeNormal));
    160 INSTANTIATE_TEST_CASE_P(InputMethodEngineIBusIncognitoBrowserTest,
    161                         InputMethodEngineIBusBrowserTest,
    162                         ::testing::Values(kTestTypeIncognito));
    163 INSTANTIATE_TEST_CASE_P(InputMethodEngineIBusComponentExtensionBrowserTest,
    164                         InputMethodEngineIBusBrowserTest,
    165                         ::testing::Values(kTestTypeComponent));
    166 
    167 IN_PROC_BROWSER_TEST_P(InputMethodEngineIBusBrowserTest,
    168                        BasicScenarioTest) {
    169   LoadTestInputMethod();
    170 
    171   MockIBusEngineFactoryService* factory_service =
    172       mock_dbus_thread_manager_->mock_ibus_engine_factory_service();
    173   factory_service->CallCreateEngine(kIdentityIMEID);
    174 
    175   MockIBusEngineService* engine_service =
    176       mock_dbus_thread_manager_->mock_ibus_engine_service();
    177   IBusEngineHandlerInterface* engine_handler = engine_service->GetEngine();
    178   ASSERT_TRUE(engine_handler);
    179 
    180   // onActivate event should be fired if Enable function is called.
    181   ExtensionTestMessageListener activated_listener("onActivate", false);
    182   engine_handler->Enable();
    183   ASSERT_TRUE(activated_listener.WaitUntilSatisfied());
    184   ASSERT_TRUE(activated_listener.was_satisfied());
    185 
    186   // onFocus event should be fired if FocusIn function is called.
    187   ExtensionTestMessageListener focus_listener("onFocus", false);;
    188   engine_handler->FocusIn();
    189   ASSERT_TRUE(focus_listener.WaitUntilSatisfied());
    190   ASSERT_TRUE(focus_listener.was_satisfied());
    191 
    192   // onKeyEvent should be fired if ProcessKeyEvent is called.
    193   KeyEventDoneCallback callback(false);  // EchoBackIME doesn't consume keys.
    194   ExtensionTestMessageListener keyevent_listener("onKeyEvent", false);
    195   engine_handler->ProcessKeyEvent(0x61,  // KeySym for 'a'.
    196                                   0x26,  // KeyCode for 'a'.
    197                                   0,  // No modifiers.
    198                                   base::Bind(&KeyEventDoneCallback::Run,
    199                                              base::Unretained(&callback)));
    200   ASSERT_TRUE(keyevent_listener.WaitUntilSatisfied());
    201   ASSERT_TRUE(keyevent_listener.was_satisfied());
    202   callback.WaitUntilCalled();
    203 
    204   // onSurroundingTextChange should be fired if SetSurroundingText is called.
    205   ExtensionTestMessageListener surrounding_text_listener(
    206       "onSurroundingTextChanged", false);
    207   engine_handler->SetSurroundingText("text",  // Surrounding text.
    208                                      0,  // focused position.
    209                                      1);  // anchor position.
    210   ASSERT_TRUE(surrounding_text_listener.WaitUntilSatisfied());
    211   ASSERT_TRUE(surrounding_text_listener.was_satisfied());
    212 
    213   // onMenuItemActivated should be fired if PropertyActivate is called.
    214   ExtensionTestMessageListener property_listener("onMenuItemActivated", false);
    215   engine_handler->PropertyActivate("property_name",
    216                                    ibus::IBUS_PROPERTY_STATE_CHECKED);
    217   ASSERT_TRUE(property_listener.WaitUntilSatisfied());
    218   ASSERT_TRUE(property_listener.was_satisfied());
    219 
    220   // onReset should be fired if Reset is called.
    221   ExtensionTestMessageListener reset_listener("onReset", false);
    222   engine_handler->Reset();
    223   ASSERT_TRUE(reset_listener.WaitUntilSatisfied());
    224   ASSERT_TRUE(reset_listener.was_satisfied());
    225 
    226   // onBlur should be fired if FocusOut is called.
    227   ExtensionTestMessageListener blur_listener("onBlur", false);
    228   engine_handler->FocusOut();
    229   ASSERT_TRUE(blur_listener.WaitUntilSatisfied());
    230   ASSERT_TRUE(blur_listener.was_satisfied());
    231 
    232   // onDeactivated should be fired if Disable is called.
    233   ExtensionTestMessageListener disabled_listener("onDeactivated", false);
    234   engine_handler->Disable();
    235   ASSERT_TRUE(disabled_listener.WaitUntilSatisfied());
    236   ASSERT_TRUE(disabled_listener.was_satisfied());
    237 }
    238 
    239 IN_PROC_BROWSER_TEST_P(InputMethodEngineIBusBrowserTest,
    240                        APIArgumentTest) {
    241   LoadTestInputMethod();
    242 
    243   MockIBusEngineFactoryService* factory_service =
    244       mock_dbus_thread_manager_->mock_ibus_engine_factory_service();
    245   factory_service->CallCreateEngine(kAPIArgumentIMEID);
    246 
    247   MockIBusEngineService* engine_service =
    248       mock_dbus_thread_manager_->mock_ibus_engine_service();
    249   IBusEngineHandlerInterface* engine_handler = engine_service->GetEngine();
    250   ASSERT_TRUE(engine_handler);
    251 
    252   extensions::ExtensionHost* host = FindHostWithPath(
    253       extensions::ExtensionSystem::Get(profile())->process_manager(),
    254       extensions::BackgroundInfo::GetBackgroundURL(extension_).path(),
    255       1);
    256 
    257   engine_handler->Enable();
    258   engine_handler->FocusIn();
    259 
    260   {
    261     SCOPED_TRACE("KeyDown, Ctrl:No, alt:No, Shift:No, Caps:No");
    262     KeyEventDoneCallback callback(false);
    263     const std::string expected_value =
    264         "onKeyEvent:keydown:a:KeyA:false:false:false:false";
    265     ExtensionTestMessageListener keyevent_listener(expected_value, false);
    266 
    267     engine_handler->ProcessKeyEvent(0x61,  // KeySym for 'a'.
    268                                     0x26,  // KeyCode for 'a'.
    269                                     0,  // No modifiers.
    270                                     base::Bind(&KeyEventDoneCallback::Run,
    271                                                base::Unretained(&callback)));
    272     ASSERT_TRUE(keyevent_listener.WaitUntilSatisfied());
    273     EXPECT_TRUE(keyevent_listener.was_satisfied());
    274     callback.WaitUntilCalled();
    275   }
    276   {
    277     SCOPED_TRACE("KeyDown, Ctrl:Yes, alt:No, Shift:No, Caps:No");
    278     KeyEventDoneCallback callback(false);
    279     const std::string expected_value =
    280         "onKeyEvent:keydown:a:KeyA:true:false:false:false";
    281     ExtensionTestMessageListener keyevent_listener(expected_value, false);
    282 
    283     engine_handler->ProcessKeyEvent(0x61,  // KeySym for 'a'.
    284                                     0x26,  // KeyCode for 'a'.
    285                                     kCtrlKeyMask,
    286                                     base::Bind(&KeyEventDoneCallback::Run,
    287                                                base::Unretained(&callback)));
    288     ASSERT_TRUE(keyevent_listener.WaitUntilSatisfied());
    289     EXPECT_TRUE(keyevent_listener.was_satisfied());
    290     callback.WaitUntilCalled();
    291   }
    292   {
    293     SCOPED_TRACE("KeyDown, Ctrl:No, alt:Yes, Shift:No, Caps:No");
    294     KeyEventDoneCallback callback(false);
    295     const std::string expected_value =
    296         "onKeyEvent:keydown:a:KeyA:false:true:false:false";
    297     ExtensionTestMessageListener keyevent_listener(expected_value, false);
    298 
    299     engine_handler->ProcessKeyEvent(0x61,  // KeySym for 'a'.
    300                                     0x26,  // KeyCode for 'a'.
    301                                     kAltKeyMask,
    302                                     base::Bind(&KeyEventDoneCallback::Run,
    303                                                base::Unretained(&callback)));
    304     ASSERT_TRUE(keyevent_listener.WaitUntilSatisfied());
    305     EXPECT_TRUE(keyevent_listener.was_satisfied());
    306     callback.WaitUntilCalled();
    307   }
    308   {
    309     SCOPED_TRACE("KeyDown, Ctrl:No, alt:No, Shift:Yes, Caps:No");
    310     KeyEventDoneCallback callback(false);
    311     const std::string expected_value =
    312         "onKeyEvent:keydown:a:KeyA:false:false:true:false";
    313     ExtensionTestMessageListener keyevent_listener(expected_value, false);
    314 
    315     engine_handler->ProcessKeyEvent(0x61,  // KeySym for 'a'.
    316                                     0x26,  // KeyCode for 'a'.
    317                                     kShiftKeyMask,
    318                                     base::Bind(&KeyEventDoneCallback::Run,
    319                                                base::Unretained(&callback)));
    320     ASSERT_TRUE(keyevent_listener.WaitUntilSatisfied());
    321     EXPECT_TRUE(keyevent_listener.was_satisfied());
    322     callback.WaitUntilCalled();
    323   }
    324   {
    325     SCOPED_TRACE("KeyDown, Ctrl:No, alt:No, Shift:No, Caps:Yes");
    326     KeyEventDoneCallback callback(false);
    327     const std::string expected_value =
    328         "onKeyEvent:keydown:a:KeyA:false:false:false:true";
    329     ExtensionTestMessageListener keyevent_listener(expected_value, false);
    330 
    331     engine_handler->ProcessKeyEvent(0x61,  // KeySym for 'a'.
    332                                     0x26,  // KeyCode for 'a'.
    333                                     kCapsLockMask,
    334                                     base::Bind(&KeyEventDoneCallback::Run,
    335                                                base::Unretained(&callback)));
    336     ASSERT_TRUE(keyevent_listener.WaitUntilSatisfied());
    337     EXPECT_TRUE(keyevent_listener.was_satisfied());
    338     callback.WaitUntilCalled();
    339   }
    340   {
    341     SCOPED_TRACE("KeyDown, Ctrl:Yes, alt:Yes, Shift:No, Caps:No");
    342     KeyEventDoneCallback callback(false);
    343     const std::string expected_value =
    344         "onKeyEvent:keydown:a:KeyA:true:true:false:false";
    345     ExtensionTestMessageListener keyevent_listener(expected_value, false);
    346 
    347     engine_handler->ProcessKeyEvent(0x61,  // KeySym for 'a'.
    348                                     0x26,  // KeyCode for 'a'.
    349                                     kAltKeyMask | kCtrlKeyMask,
    350                                     base::Bind(&KeyEventDoneCallback::Run,
    351                                                base::Unretained(&callback)));
    352     ASSERT_TRUE(keyevent_listener.WaitUntilSatisfied());
    353     EXPECT_TRUE(keyevent_listener.was_satisfied());
    354     callback.WaitUntilCalled();
    355   }
    356   {
    357     SCOPED_TRACE("KeyDown, Ctrl:No, alt:No, Shift:Yes, Caps:Yes");
    358     KeyEventDoneCallback callback(false);
    359     const std::string expected_value =
    360         "onKeyEvent:keydown:a:KeyA:false:false:true:true";
    361     ExtensionTestMessageListener keyevent_listener(expected_value, false);
    362 
    363     engine_handler->ProcessKeyEvent(0x61,  // KeySym for 'a'.
    364                                     0x26,  // KeyCode for 'a'.
    365                                     kShiftKeyMask | kCapsLockMask,
    366                                     base::Bind(&KeyEventDoneCallback::Run,
    367                                                base::Unretained(&callback)));
    368     ASSERT_TRUE(keyevent_listener.WaitUntilSatisfied());
    369     EXPECT_TRUE(keyevent_listener.was_satisfied());
    370     callback.WaitUntilCalled();
    371   }
    372   // TODO(nona): Add browser tests for other API as well.
    373   {
    374     SCOPED_TRACE("commitText test");
    375     const char commit_text_test_script[] =
    376         "chrome.input.ime.commitText({"
    377         "  contextID: engineBridge.getFocusedContextID().contextID,"
    378         "  text:'COMMIT_TEXT'"
    379         "});";
    380 
    381     engine_service->Clear();
    382     ASSERT_TRUE(content::ExecuteScript(host->host_contents(),
    383                                        commit_text_test_script));
    384     EXPECT_EQ(1, engine_service->commit_text_call_count());
    385     EXPECT_EQ("COMMIT_TEXT", engine_service->last_commit_text());
    386   }
    387   {
    388     SCOPED_TRACE("setComposition test");
    389     const char set_composition_test_script[] =
    390         "chrome.input.ime.setComposition({"
    391         "  contextID: engineBridge.getFocusedContextID().contextID,"
    392         "  text:'COMPOSITION_TEXT',"
    393         "  cursor:4,"
    394         "  segments : [{"
    395         "    start: 0,"
    396         "    end: 5,"
    397         "    style: 'underline'"
    398         "  },{"
    399         "    start: 6,"
    400         "    end: 10,"
    401         "    style: 'doubleUnderline'"
    402         "  }]"
    403         "});";
    404 
    405     engine_service->Clear();
    406     ASSERT_TRUE(content::ExecuteScript(host->host_contents(),
    407                                        set_composition_test_script));
    408     EXPECT_EQ(1, engine_service->update_preedit_call_count());
    409 
    410     EXPECT_EQ(4U, engine_service->last_update_preedit_arg().cursor_pos);
    411     EXPECT_TRUE(engine_service->last_update_preedit_arg().is_visible);
    412 
    413     const IBusText& ibus_text =
    414         engine_service->last_update_preedit_arg().ibus_text;
    415     EXPECT_EQ("COMPOSITION_TEXT", ibus_text.text());
    416     const std::vector<IBusText::UnderlineAttribute>& underlines =
    417         ibus_text.underline_attributes();
    418 
    419     ASSERT_EQ(2U, underlines.size());
    420     EXPECT_EQ(IBusText::IBUS_TEXT_UNDERLINE_SINGLE, underlines[0].type);
    421     EXPECT_EQ(0U, underlines[0].start_index);
    422     EXPECT_EQ(5U, underlines[0].end_index);
    423 
    424     EXPECT_EQ(IBusText::IBUS_TEXT_UNDERLINE_DOUBLE, underlines[1].type);
    425     EXPECT_EQ(6U, underlines[1].start_index);
    426     EXPECT_EQ(10U, underlines[1].end_index);
    427   }
    428   {
    429     SCOPED_TRACE("clearComposition test");
    430     const char commite_text_test_script[] =
    431         "chrome.input.ime.clearComposition({"
    432         "  contextID: engineBridge.getFocusedContextID().contextID,"
    433         "});";
    434 
    435     engine_service->Clear();
    436     ASSERT_TRUE(content::ExecuteScript(host->host_contents(),
    437                                        commite_text_test_script));
    438     EXPECT_EQ(1, engine_service->update_preedit_call_count());
    439     EXPECT_FALSE(engine_service->last_update_preedit_arg().is_visible);
    440     const IBusText& ibus_text =
    441         engine_service->last_update_preedit_arg().ibus_text;
    442     EXPECT_TRUE(ibus_text.text().empty());
    443   }
    444   {
    445     SCOPED_TRACE("setCandidateWindowProperties:visibility test");
    446     const char set_candidate_window_properties_test_script[] =
    447         "chrome.input.ime.setCandidateWindowProperties({"
    448         "  engineID: engineBridge.getActiveEngineID(),"
    449         "  properties: {"
    450         "    visible: true,"
    451         "  }"
    452         "});";
    453     engine_service->Clear();
    454     ASSERT_TRUE(content::ExecuteScript(
    455         host->host_contents(),
    456         set_candidate_window_properties_test_script));
    457     EXPECT_EQ(1, engine_service->update_lookup_table_call_count());
    458     EXPECT_TRUE(engine_service->last_update_lookup_table_arg().is_visible);
    459   }
    460   {
    461     SCOPED_TRACE("setCandidateWindowProperties:cursor_visibility test");
    462     const char set_candidate_window_properties_test_script[] =
    463         "chrome.input.ime.setCandidateWindowProperties({"
    464         "  engineID: engineBridge.getActiveEngineID(),"
    465         "  properties: {"
    466         "    cursorVisible: true,"
    467         "  }"
    468         "});";
    469     engine_service->Clear();
    470     ASSERT_TRUE(content::ExecuteScript(
    471         host->host_contents(),
    472         set_candidate_window_properties_test_script));
    473     EXPECT_EQ(1, engine_service->update_lookup_table_call_count());
    474 
    475     // window visibility is kept as before.
    476     EXPECT_TRUE(engine_service->last_update_lookup_table_arg().is_visible);
    477 
    478     const IBusLookupTable& table =
    479         engine_service->last_update_lookup_table_arg().lookup_table;
    480     EXPECT_TRUE(table.is_cursor_visible());
    481   }
    482   {
    483     SCOPED_TRACE("setCandidateWindowProperties:vertical test");
    484     const char set_candidate_window_properties_test_script[] =
    485         "chrome.input.ime.setCandidateWindowProperties({"
    486         "  engineID: engineBridge.getActiveEngineID(),"
    487         "  properties: {"
    488         "    vertical: true,"
    489         "  }"
    490         "});";
    491     engine_service->Clear();
    492     ASSERT_TRUE(content::ExecuteScript(
    493         host->host_contents(),
    494         set_candidate_window_properties_test_script));
    495     EXPECT_EQ(1, engine_service->update_lookup_table_call_count());
    496 
    497     // window visibility is kept as before.
    498     EXPECT_TRUE(engine_service->last_update_lookup_table_arg().is_visible);
    499 
    500     const IBusLookupTable& table =
    501         engine_service->last_update_lookup_table_arg().lookup_table;
    502 
    503     // cursor visibility is kept as before.
    504     EXPECT_TRUE(table.is_cursor_visible());
    505 
    506     EXPECT_EQ(IBusLookupTable::VERTICAL, table.orientation());
    507   }
    508   {
    509     SCOPED_TRACE("setCandidateWindowProperties:pageSize test");
    510     const char set_candidate_window_properties_test_script[] =
    511         "chrome.input.ime.setCandidateWindowProperties({"
    512         "  engineID: engineBridge.getActiveEngineID(),"
    513         "  properties: {"
    514         "    pageSize: 7,"
    515         "  }"
    516         "});";
    517     engine_service->Clear();
    518     ASSERT_TRUE(content::ExecuteScript(
    519         host->host_contents(),
    520         set_candidate_window_properties_test_script));
    521     EXPECT_EQ(1, engine_service->update_lookup_table_call_count());
    522 
    523     // window visibility is kept as before.
    524     EXPECT_TRUE(engine_service->last_update_lookup_table_arg().is_visible);
    525 
    526     const IBusLookupTable& table =
    527         engine_service->last_update_lookup_table_arg().lookup_table;
    528 
    529     // cursor visibility is kept as before.
    530     EXPECT_TRUE(table.is_cursor_visible());
    531 
    532     // oritantation is kept as before.
    533     EXPECT_EQ(IBusLookupTable::VERTICAL, table.orientation());
    534 
    535     EXPECT_EQ(7U, table.page_size());
    536   }
    537   {
    538     SCOPED_TRACE("setCandidateWindowProperties:auxTextVisibility test");
    539     const char set_candidate_window_properties_test_script[] =
    540         "chrome.input.ime.setCandidateWindowProperties({"
    541         "  engineID: engineBridge.getActiveEngineID(),"
    542         "  properties: {"
    543         "    auxiliaryTextVisible: true"
    544         "  }"
    545         "});";
    546     engine_service->Clear();
    547     ASSERT_TRUE(content::ExecuteScript(
    548         host->host_contents(),
    549         set_candidate_window_properties_test_script));
    550     EXPECT_EQ(1, engine_service->update_auxiliary_text_call_count());
    551     EXPECT_TRUE(engine_service->last_update_aux_text_arg().is_visible);
    552   }
    553   {
    554     SCOPED_TRACE("setCandidateWindowProperties:auxText test");
    555     const char set_candidate_window_properties_test_script[] =
    556         "chrome.input.ime.setCandidateWindowProperties({"
    557         "  engineID: engineBridge.getActiveEngineID(),"
    558         "  properties: {"
    559         "    auxiliaryText: 'AUXILIARY_TEXT'"
    560         "  }"
    561         "});";
    562     engine_service->Clear();
    563     ASSERT_TRUE(content::ExecuteScript(
    564         host->host_contents(),
    565         set_candidate_window_properties_test_script));
    566     EXPECT_EQ(1, engine_service->update_auxiliary_text_call_count());
    567 
    568     // aux text visibility is kept as before.
    569     EXPECT_TRUE(engine_service->last_update_aux_text_arg().is_visible);
    570 
    571     EXPECT_EQ("AUXILIARY_TEXT",
    572               engine_service->last_update_aux_text_arg().ibus_text.text());
    573   }
    574   {
    575     SCOPED_TRACE("setCandidates test");
    576     const char set_candidates_test_script[] =
    577         "chrome.input.ime.setCandidates({"
    578         "  contextID: engineBridge.getFocusedContextID().contextID,"
    579         "  candidates: [{"
    580         "    candidate: 'CANDIDATE_1',"
    581         "    id: 1,"
    582         "    },{"
    583         "    candidate: 'CANDIDATE_2',"
    584         "    id: 2,"
    585         "    label: 'LABEL_2',"
    586         "    },{"
    587         "    candidate: 'CANDIDATE_3',"
    588         "    id: 3,"
    589         "    label: 'LABEL_3',"
    590         "    annotation: 'ANNOTACTION_3'"
    591         "    },{"
    592         "    candidate: 'CANDIDATE_4',"
    593         "    id: 4,"
    594         "    label: 'LABEL_4',"
    595         "    annotation: 'ANNOTACTION_4',"
    596         "    usage: {"
    597         "      title: 'TITLE_4',"
    598         "      body: 'BODY_4'"
    599         "    }"
    600         "  }]"
    601         "});";
    602     engine_service->Clear();
    603     ASSERT_TRUE(content::ExecuteScript(host->host_contents(),
    604                                        set_candidates_test_script));
    605 
    606     // window visibility is kept as before.
    607     EXPECT_TRUE(engine_service->last_update_lookup_table_arg().is_visible);
    608 
    609     const IBusLookupTable& table =
    610         engine_service->last_update_lookup_table_arg().lookup_table;
    611 
    612     // cursor visibility is kept as before.
    613     EXPECT_TRUE(table.is_cursor_visible());
    614 
    615     // oritantation is kept as before.
    616     EXPECT_EQ(IBusLookupTable::VERTICAL, table.orientation());
    617 
    618     // page size is kept as before.
    619     EXPECT_EQ(7U, table.page_size());
    620 
    621     ASSERT_EQ(4U, table.candidates().size());
    622 
    623     EXPECT_EQ("CANDIDATE_1", table.candidates().at(0).value);
    624 
    625     EXPECT_EQ("CANDIDATE_2", table.candidates().at(1).value);
    626     EXPECT_EQ("LABEL_2", table.candidates().at(1).label);
    627 
    628     EXPECT_EQ("CANDIDATE_3", table.candidates().at(2).value);
    629     EXPECT_EQ("LABEL_3", table.candidates().at(2).label);
    630     EXPECT_EQ("ANNOTACTION_3", table.candidates().at(2).annotation);
    631 
    632     EXPECT_EQ("CANDIDATE_4", table.candidates().at(3).value);
    633     EXPECT_EQ("LABEL_4", table.candidates().at(3).label);
    634     EXPECT_EQ("ANNOTACTION_4", table.candidates().at(3).annotation);
    635     EXPECT_EQ("TITLE_4", table.candidates().at(3).description_title);
    636     EXPECT_EQ("BODY_4", table.candidates().at(3).description_body);
    637   }
    638   {
    639     SCOPED_TRACE("setCursorPosition test");
    640     const char set_cursor_position_test_script[] =
    641         "chrome.input.ime.setCursorPosition({"
    642         "  contextID: engineBridge.getFocusedContextID().contextID,"
    643         "  candidateID: 2"
    644         "});";
    645     engine_service->Clear();
    646     ASSERT_TRUE(content::ExecuteScript(
    647         host->host_contents(), set_cursor_position_test_script));
    648     EXPECT_EQ(1, engine_service->update_lookup_table_call_count());
    649 
    650     // window visibility is kept as before.
    651     EXPECT_TRUE(engine_service->last_update_lookup_table_arg().is_visible);
    652 
    653     const IBusLookupTable& table =
    654         engine_service->last_update_lookup_table_arg().lookup_table;
    655 
    656     // cursor visibility is kept as before.
    657     EXPECT_TRUE(table.is_cursor_visible());
    658 
    659     // oritantation is kept as before.
    660     EXPECT_EQ(IBusLookupTable::VERTICAL, table.orientation());
    661 
    662     // page size is kept as before.
    663     EXPECT_EQ(7U, table.page_size());
    664 
    665     // candidates are same as before.
    666     ASSERT_EQ(4U, table.candidates().size());
    667 
    668     // Candidate ID == 2 is 1 in index.
    669     EXPECT_EQ(1U, table.cursor_position());
    670   }
    671   {
    672     SCOPED_TRACE("setMenuItem test");
    673     const char set_menu_item_test_script[] =
    674         "chrome.input.ime.setMenuItems({"
    675         "  engineID: engineBridge.getActiveEngineID(),"
    676         "  items: [{"
    677         "    id: 'ID0',"
    678         "  },{"
    679         "    id: 'ID1',"
    680         "    label: 'LABEL1',"
    681         "  },{"
    682         "    id: 'ID2',"
    683         "    label: 'LABEL2',"
    684         "    style: 'radio',"
    685         "  },{"
    686         "    id: 'ID3',"
    687         "    label: 'LABEL3',"
    688         "    style: 'check',"
    689         "    visible: true,"
    690         "  },{"
    691         "    id: 'ID4',"
    692         "    label: 'LABEL4',"
    693         "    style: 'separator',"
    694         "    visible: true,"
    695         "    checked: true"
    696         "  }]"
    697         "});";
    698     engine_service->Clear();
    699     ASSERT_TRUE(content::ExecuteScript(
    700         host->host_contents(), set_menu_item_test_script));
    701     EXPECT_EQ(1, engine_service->register_properties_call_count());
    702 
    703     const IBusPropertyList& props =
    704         engine_service->last_registered_properties();
    705     ASSERT_EQ(5U, props.size());
    706 
    707     EXPECT_EQ("ID0", props[0]->key());
    708     EXPECT_EQ("ID1", props[1]->key());
    709     EXPECT_EQ("ID2", props[2]->key());
    710     EXPECT_EQ("ID3", props[3]->key());
    711     EXPECT_EQ("ID4", props[4]->key());
    712 
    713     EXPECT_EQ("LABEL1", props[1]->label());
    714     EXPECT_EQ("LABEL2", props[2]->label());
    715     EXPECT_EQ("LABEL3", props[3]->label());
    716     EXPECT_EQ("LABEL4", props[4]->label());
    717 
    718     EXPECT_EQ(IBusProperty::IBUS_PROPERTY_TYPE_RADIO, props[2]->type());
    719     EXPECT_EQ(IBusProperty::IBUS_PROPERTY_TYPE_TOGGLE, props[3]->type());
    720     EXPECT_EQ(IBusProperty::IBUS_PROPERTY_TYPE_SEPARATOR, props[4]->type());
    721 
    722     EXPECT_TRUE(props[3]->visible());
    723     EXPECT_TRUE(props[4]->visible());
    724 
    725     EXPECT_TRUE(props[4]->checked());
    726   }
    727   {
    728     SCOPED_TRACE("deleteSurroundingText test");
    729     const char delete_surrounding_text_test_script[] =
    730         "chrome.input.ime.deleteSurroundingText({"
    731         "  engineID: engineBridge.getActiveEngineID(),"
    732         "  contextID: engineBridge.getFocusedContextID().contextID,"
    733         "  offset: 5,"
    734         "  length: 3"
    735         "});";
    736     engine_service->Clear();
    737     ASSERT_TRUE(content::ExecuteScript(
    738         host->host_contents(), delete_surrounding_text_test_script));
    739 
    740     EXPECT_EQ(1, engine_service->delete_surrounding_text_call_count());
    741     EXPECT_EQ(5, engine_service->last_delete_surrounding_text_arg().offset);
    742     EXPECT_EQ(3U, engine_service->last_delete_surrounding_text_arg().length);
    743   }
    744 }
    745 
    746 }  // namespace
    747 }  // namespace input_method
    748 }  // namespace chromeos
    749