| Index: blimp/engine/feature/engine_render_widget_feature_unittest.cc | 
| diff --git a/blimp/engine/feature/engine_render_widget_feature_unittest.cc b/blimp/engine/feature/engine_render_widget_feature_unittest.cc | 
| index ad23d639374dd86f575fff0e26b1c2ae6dd5227f..3d9c91a6cd202f07fb40c53b43be435bb18f22db 100644 | 
| --- a/blimp/engine/feature/engine_render_widget_feature_unittest.cc | 
| +++ b/blimp/engine/feature/engine_render_widget_feature_unittest.cc | 
| @@ -5,6 +5,7 @@ | 
| #include "base/logging.h" | 
| #include "base/memory/scoped_ptr.h" | 
| #include "base/numerics/safe_conversions.h" | 
| +#include "base/strings/utf_string_conversions.h" | 
| #include "blimp/common/create_blimp_message.h" | 
| #include "blimp/common/proto/blimp_message.pb.h" | 
| #include "blimp/common/proto/compositor.pb.h" | 
| @@ -18,6 +19,7 @@ | 
| #include "testing/gmock/include/gmock/gmock.h" | 
| #include "testing/gtest/include/gtest/gtest.h" | 
| #include "third_party/WebKit/public/web/WebInputEvent.h" | 
| +#include "ui/base/ime/text_input_client.h" | 
|  | 
| using testing::_; | 
| using testing::InSequence; | 
| @@ -97,6 +99,55 @@ class MockRenderWidgetHost | 
| bool Send(IPC::Message* msg) override { return false; } | 
| }; | 
|  | 
| +class MockTextInputClient : public ui::TextInputClient { | 
| +  ui::TextInputType text_input_type_; | 
| + | 
| + public: | 
| +  MockTextInputClient() : text_input_type_(ui::TEXT_INPUT_TYPE_TEXT) {} | 
| +  ~MockTextInputClient() override {} | 
| + | 
| +  void SetCompositionText(const ui::CompositionText& composition) override {} | 
| +  void ConfirmCompositionText() override {} | 
| +  void ClearCompositionText() override {} | 
| +  void InsertText(const base::string16& text) override {} | 
| +  void InsertChar(const ui::KeyEvent& event) override {} | 
| +  ui::TextInputType GetTextInputType() const override { | 
| +    return text_input_type_; | 
| +  } | 
| +  ui::TextInputMode GetTextInputMode() const override { | 
| +    return ui::TEXT_INPUT_MODE_DEFAULT; | 
| +  } | 
| +  int GetTextInputFlags() const override { return 0; } | 
| +  bool CanComposeInline() const override { return false; } | 
| +  gfx::Rect GetCaretBounds() const override { return gfx::Rect(); } | 
| +  bool GetCompositionCharacterBounds(uint32_t index, | 
| +                                     gfx::Rect* rect) const override { | 
| +    return false; | 
| +  } | 
| +  bool HasCompositionText() const override { return false; } | 
| +  bool GetTextRange(gfx::Range* range) const override { return false; } | 
| +  bool GetCompositionTextRange(gfx::Range* range) const override { | 
| +    return false; | 
| +  } | 
| +  bool GetSelectionRange(gfx::Range* range) const override { return false; } | 
| +  bool SetSelectionRange(const gfx::Range& range) override { return false; } | 
| +  bool DeleteRange(const gfx::Range& range) override { return false; } | 
| +  void OnInputMethodChanged() override {} | 
| +  bool ChangeTextDirectionAndLayoutAlignment( | 
| +      base::i18n::TextDirection direction) override { | 
| +    return false; | 
| +  } | 
| +  void ExtendSelectionAndDelete(size_t before, size_t after) override {} | 
| +  void EnsureCaretInRect(const gfx::Rect& rect) override {} | 
| +  bool IsEditCommandEnabled(int command_id) override { return false; } | 
| +  void SetEditCommandForNextKeyEvent(int command_id) override {} | 
| +  bool GetTextFromRange(const gfx::Range& range, | 
| +                        base::string16* text) const override { | 
| +    *text = base::string16(base::ASCIIToUTF16("green apple")); | 
| +    return false; | 
| +  } | 
| +}; | 
| + | 
| MATCHER_P(CompMsgEquals, contents, "") { | 
| if (contents.size() != arg.size()) | 
| return false; | 
| @@ -124,6 +175,24 @@ MATCHER_P3(BlimpRWMsgEquals, tab_id, rw_id, message_type, "") { | 
| arg.render_widget().type() == message_type; | 
| } | 
|  | 
| +MATCHER_P2(BlimpImeMsgEquals, tab_id, message_type, "") { | 
| +  return arg.target_tab_id() == tab_id && arg.ime().type() == message_type; | 
| +} | 
| + | 
| +MATCHER_P5(BlimpImeMsgEquals, | 
| +           tab_id, | 
| +           rwid, | 
| +           message_type, | 
| +           text, | 
| +           text_input_type, | 
| +           "") { | 
| +  return arg.target_tab_id() == tab_id && | 
| +         arg.ime().render_widget_id() == rwid && | 
| +         arg.ime().type() == message_type && | 
| +         arg.ime().ime_text().compare(text) == 0 && | 
| +         arg.ime().text_input_type() == text_input_type; | 
| +} | 
| + | 
| void SendInputMessage(BlimpMessageProcessor* processor, | 
| int tab_id, | 
| int rw_id) { | 
| @@ -167,6 +236,8 @@ class EngineRenderWidgetFeatureTest : public testing::Test { | 
| compositor_message_sender_ = new MockBlimpMessageProcessor; | 
| feature_.set_compositor_message_sender( | 
| make_scoped_ptr(compositor_message_sender_)); | 
| +    ime_message_sender_ = new MockBlimpMessageProcessor; | 
| +    feature_.set_ime_message_sender(make_scoped_ptr(ime_message_sender_)); | 
| feature_.SetDelegate(1, &delegate1_); | 
| feature_.SetDelegate(2, &delegate2_); | 
| } | 
| @@ -174,10 +245,12 @@ class EngineRenderWidgetFeatureTest : public testing::Test { | 
| protected: | 
| MockBlimpMessageProcessor* render_widget_message_sender_; | 
| MockBlimpMessageProcessor* compositor_message_sender_; | 
| +  MockBlimpMessageProcessor* ime_message_sender_; | 
| MockRenderWidgetHost render_widget_host1_; | 
| MockRenderWidgetHost render_widget_host2_; | 
| MockHostRenderWidgetMessageDelegate delegate1_; | 
| MockHostRenderWidgetMessageDelegate delegate2_; | 
| +  MockTextInputClient text_input_client_; | 
| EngineRenderWidgetFeature feature_; | 
| }; | 
|  | 
| @@ -213,6 +286,22 @@ TEST_F(EngineRenderWidgetFeatureTest, DelegateCallsOK) { | 
| SendCompositorMessage(&feature_, 2, 2, payload); | 
| } | 
|  | 
| +TEST_F(EngineRenderWidgetFeatureTest, ImeRequestSentCorrectly) { | 
| +  EXPECT_CALL( | 
| +      *ime_message_sender_, | 
| +      MockableProcessMessage(BlimpImeMsgEquals(2, 1, ImeMessage::SHOW_IME, | 
| +                                               std::string("green apple"), 1), | 
| +                             _)); | 
| + | 
| +  EXPECT_CALL( | 
| +      *ime_message_sender_, | 
| +      MockableProcessMessage(BlimpImeMsgEquals(2, ImeMessage::HIDE_IME), _)); | 
| + | 
| +  feature_.OnRenderWidgetCreated(2, &render_widget_host1_); | 
| +  feature_.SendShowImeRequest(2, &render_widget_host1_, &text_input_client_); | 
| +  feature_.SendHideImeRequest(2, &render_widget_host1_); | 
| +} | 
| + | 
| TEST_F(EngineRenderWidgetFeatureTest, DropsStaleMessages) { | 
| InSequence sequence; | 
| std::vector<uint8_t> payload = { 'f', 'u', 'n' }; | 
|  |