Add ICU message format support
[chromium-blink-merge.git] / content / browser / renderer_host / text_input_client_mac_unittest.mm
blob2479255ba1c0ae30221d5bca85a5d31380a2500c
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.
5 #import "content/browser/renderer_host/text_input_client_mac.h"
7 #include "base/bind.h"
8 #include "base/message_loop/message_loop.h"
9 #include "base/threading/thread.h"
10 #include "content/browser/renderer_host/render_process_host_impl.h"
11 #include "content/browser/renderer_host/render_widget_host_delegate.h"
12 #include "content/browser/renderer_host/render_widget_host_impl.h"
13 #include "content/browser/renderer_host/text_input_client_message_filter.h"
14 #include "content/common/text_input_client_messages.h"
15 #include "content/public/test/mock_render_process_host.h"
16 #include "content/public/test/test_browser_context.h"
17 #include "ipc/ipc_test_sink.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19 #include "testing/gtest_mac.h"
21 namespace content {
23 namespace {
24 const int64 kTaskDelayMs = 200;
26 class MockRenderWidgetHostDelegate : public RenderWidgetHostDelegate {
27  public:
28   MockRenderWidgetHostDelegate() {}
29   ~MockRenderWidgetHostDelegate() override {}
31  private:
32   void Cut() override {}
33   void Copy() override {}
34   void Paste() override {}
35   void SelectAll() override {}
38 // This test does not test the WebKit side of the dictionary system (which
39 // performs the actual data fetching), but rather this just tests that the
40 // service's signaling system works.
41 class TextInputClientMacTest : public testing::Test {
42  public:
43   TextInputClientMacTest()
44       : browser_context_(),
45         process_factory_(),
46         delegate_(),
47         widget_(&delegate_,
48                 process_factory_.CreateRenderProcessHost(
49                     &browser_context_, NULL),
50                 MSG_ROUTING_NONE, false),
51         thread_("TextInputClientMacTestThread") {}
53   // Accessor for the TextInputClientMac instance.
54   TextInputClientMac* service() {
55     return TextInputClientMac::GetInstance();
56   }
58   // Helper method to post a task on the testing thread's MessageLoop after
59   // a short delay.
60   void PostTask(const tracked_objects::Location& from_here,
61                 const base::Closure& task) {
62     PostTask(from_here, task, base::TimeDelta::FromMilliseconds(kTaskDelayMs));
63   }
65   void PostTask(const tracked_objects::Location& from_here,
66                 const base::Closure& task,
67                 const base::TimeDelta delay) {
68     thread_.message_loop()->PostDelayedTask(from_here, task, delay);
69   }
71   RenderWidgetHostImpl* widget() {
72     return &widget_;
73   }
75   IPC::TestSink& ipc_sink() {
76     return static_cast<MockRenderProcessHost*>(widget()->GetProcess())->sink();
77   }
79  private:
80   friend class ScopedTestingThread;
82   base::MessageLoopForUI message_loop_;
83   TestBrowserContext browser_context_;
85   // Gets deleted when the last RWH in the "process" gets destroyed.
86   MockRenderProcessHostFactory process_factory_;
87   MockRenderWidgetHostDelegate delegate_;
88   RenderWidgetHostImpl widget_;
90   base::Thread thread_;
93 ////////////////////////////////////////////////////////////////////////////////
95 // Helper class that Start()s and Stop()s a thread according to the scope of the
96 // object.
97 class ScopedTestingThread {
98  public:
99   ScopedTestingThread(TextInputClientMacTest* test) : thread_(test->thread_) {
100     thread_.Start();
101   }
102   ~ScopedTestingThread() {
103     thread_.Stop();
104   }
106  private:
107   base::Thread& thread_;
110 // Adapter for OnMessageReceived to ignore return type so it can be posted
111 // to a MessageLoop.
112 void CallOnMessageReceived(scoped_refptr<TextInputClientMessageFilter> filter,
113                            const IPC::Message& message) {
114   filter->OnMessageReceived(message);
117 }  // namespace
119 // Test Cases //////////////////////////////////////////////////////////////////
121 TEST_F(TextInputClientMacTest, GetCharacterIndex) {
122   ScopedTestingThread thread(this);
123   const NSUInteger kSuccessValue = 42;
125   PostTask(FROM_HERE,
126            base::Bind(&TextInputClientMac::SetCharacterIndexAndSignal,
127                       base::Unretained(service()), kSuccessValue));
128   NSUInteger index = service()->GetCharacterIndexAtPoint(
129       widget(), gfx::Point(2, 2));
131   EXPECT_EQ(1U, ipc_sink().message_count());
132   EXPECT_TRUE(ipc_sink().GetUniqueMessageMatching(
133       TextInputClientMsg_CharacterIndexForPoint::ID));
134   EXPECT_EQ(kSuccessValue, index);
137 TEST_F(TextInputClientMacTest, TimeoutCharacterIndex) {
138   NSUInteger index = service()->GetCharacterIndexAtPoint(
139       widget(), gfx::Point(2, 2));
140   EXPECT_EQ(1U, ipc_sink().message_count());
141   EXPECT_TRUE(ipc_sink().GetUniqueMessageMatching(
142       TextInputClientMsg_CharacterIndexForPoint::ID));
143   EXPECT_EQ(NSNotFound, index);
146 TEST_F(TextInputClientMacTest, NotFoundCharacterIndex) {
147   ScopedTestingThread thread(this);
148   const NSUInteger kPreviousValue = 42;
149   const size_t kNotFoundValue = static_cast<size_t>(-1);
151   // Set an arbitrary value to ensure the index is not |NSNotFound|.
152   PostTask(FROM_HERE,
153            base::Bind(&TextInputClientMac::SetCharacterIndexAndSignal,
154                       base::Unretained(service()), kPreviousValue));
156   scoped_refptr<TextInputClientMessageFilter> filter(
157       new TextInputClientMessageFilter(widget()->GetProcess()->GetID()));
158   scoped_ptr<IPC::Message> message(
159       new TextInputClientReplyMsg_GotCharacterIndexForPoint(
160           widget()->GetRoutingID(), kNotFoundValue));
161   // Set |WTF::notFound| to the index |kTaskDelayMs| after the previous
162   // setting.
163   PostTask(FROM_HERE,
164            base::Bind(&CallOnMessageReceived, filter, *message),
165            base::TimeDelta::FromMilliseconds(kTaskDelayMs) * 2);
167   NSUInteger index = service()->GetCharacterIndexAtPoint(
168       widget(), gfx::Point(2, 2));
169   EXPECT_EQ(kPreviousValue, index);
170   index = service()->GetCharacterIndexAtPoint(widget(), gfx::Point(2, 2));
171   EXPECT_EQ(NSNotFound, index);
173   EXPECT_EQ(2U, ipc_sink().message_count());
174   for (size_t i = 0; i < ipc_sink().message_count(); ++i) {
175     const IPC::Message* ipc_message = ipc_sink().GetMessageAt(i);
176     EXPECT_EQ(ipc_message->type(),
177               TextInputClientMsg_CharacterIndexForPoint::ID);
178   }
181 TEST_F(TextInputClientMacTest, GetRectForRange) {
182   ScopedTestingThread thread(this);
183   const NSRect kSuccessValue = NSMakeRect(42, 43, 44, 45);
185   PostTask(FROM_HERE,
186            base::Bind(&TextInputClientMac::SetFirstRectAndSignal,
187                       base::Unretained(service()), kSuccessValue));
188   NSRect rect = service()->GetFirstRectForRange(widget(), NSMakeRange(0, 32));
190   EXPECT_EQ(1U, ipc_sink().message_count());
191   EXPECT_TRUE(ipc_sink().GetUniqueMessageMatching(
192       TextInputClientMsg_FirstRectForCharacterRange::ID));
193   EXPECT_NSEQ(kSuccessValue, rect);
196 TEST_F(TextInputClientMacTest, TimeoutRectForRange) {
197   NSRect rect = service()->GetFirstRectForRange(widget(), NSMakeRange(0, 32));
198   EXPECT_EQ(1U, ipc_sink().message_count());
199   EXPECT_TRUE(ipc_sink().GetUniqueMessageMatching(
200       TextInputClientMsg_FirstRectForCharacterRange::ID));
201   EXPECT_NSEQ(NSZeroRect, rect);
204 TEST_F(TextInputClientMacTest, GetSubstring) {
205   ScopedTestingThread thread(this);
206   NSDictionary* attributes =
207       [NSDictionary dictionaryWithObject:[NSColor purpleColor]
208                                   forKey:NSForegroundColorAttributeName];
209   base::scoped_nsobject<NSMutableAttributedString> kSuccessValue(
210       [[NSMutableAttributedString alloc]
211           initWithString:@"Barney is a purple dinosaur"
212               attributes:attributes]);
214   PostTask(FROM_HERE,
215            base::Bind(&TextInputClientMac::SetSubstringAndSignal,
216                       base::Unretained(service()),
217                       base::Unretained(kSuccessValue.get())));
218   NSAttributedString* string = service()->GetAttributedSubstringFromRange(
219       widget(), NSMakeRange(0, 32));
221   EXPECT_NSEQ(kSuccessValue, string);
222   EXPECT_NE(kSuccessValue.get(), string);  // |string| should be a copy.
223   EXPECT_EQ(1U, ipc_sink().message_count());
224   EXPECT_TRUE(ipc_sink().GetUniqueMessageMatching(
225       TextInputClientMsg_StringForRange::ID));
228 TEST_F(TextInputClientMacTest, TimeoutSubstring) {
229   NSAttributedString* string = service()->GetAttributedSubstringFromRange(
230       widget(), NSMakeRange(0, 32));
231   EXPECT_EQ(nil, string);
232   EXPECT_EQ(1U, ipc_sink().message_count());
233   EXPECT_TRUE(ipc_sink().GetUniqueMessageMatching(
234       TextInputClientMsg_StringForRange::ID));
237 }  // namespace content