Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / content / browser / renderer_host / text_input_client_mac_unittest.mm
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 #import "content/browser/renderer_host/text_input_client_mac.h"
6
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"
20
21 namespace content {
22
23 namespace {
24 const int64 kTaskDelayMs = 200;
25
26 class MockRenderWidgetHostDelegate : public RenderWidgetHostDelegate {
27  public:
28   MockRenderWidgetHostDelegate() {}
29   ~MockRenderWidgetHostDelegate() override {}
30 };
31
32 // This test does not test the WebKit side of the dictionary system (which
33 // performs the actual data fetching), but rather this just tests that the
34 // service's signaling system works.
35 class TextInputClientMacTest : public testing::Test {
36  public:
37   TextInputClientMacTest()
38       : browser_context_(),
39         process_factory_(),
40         delegate_(),
41         widget_(&delegate_,
42                 process_factory_.CreateRenderProcessHost(
43                     &browser_context_, NULL),
44                 MSG_ROUTING_NONE, false),
45         thread_("TextInputClientMacTestThread") {}
46
47   // Accessor for the TextInputClientMac instance.
48   TextInputClientMac* service() {
49     return TextInputClientMac::GetInstance();
50   }
51
52   // Helper method to post a task on the testing thread's MessageLoop after
53   // a short delay.
54   void PostTask(const tracked_objects::Location& from_here,
55                 const base::Closure& task) {
56     PostTask(from_here, task, base::TimeDelta::FromMilliseconds(kTaskDelayMs));
57   }
58
59   void PostTask(const tracked_objects::Location& from_here,
60                 const base::Closure& task,
61                 const base::TimeDelta delay) {
62     thread_.message_loop()->PostDelayedTask(from_here, task, delay);
63   }
64
65   RenderWidgetHostImpl* widget() {
66     return &widget_;
67   }
68
69   IPC::TestSink& ipc_sink() {
70     return static_cast<MockRenderProcessHost*>(widget()->GetProcess())->sink();
71   }
72
73  private:
74   friend class ScopedTestingThread;
75
76   base::MessageLoopForUI message_loop_;
77   TestBrowserContext browser_context_;
78
79   // Gets deleted when the last RWH in the "process" gets destroyed.
80   MockRenderProcessHostFactory process_factory_;
81   MockRenderWidgetHostDelegate delegate_;
82   RenderWidgetHostImpl widget_;
83
84   base::Thread thread_;
85 };
86
87 ////////////////////////////////////////////////////////////////////////////////
88
89 // Helper class that Start()s and Stop()s a thread according to the scope of the
90 // object.
91 class ScopedTestingThread {
92  public:
93   ScopedTestingThread(TextInputClientMacTest* test) : thread_(test->thread_) {
94     thread_.Start();
95   }
96   ~ScopedTestingThread() {
97     thread_.Stop();
98   }
99
100  private:
101   base::Thread& thread_;
102 };
103
104 // Adapter for OnMessageReceived to ignore return type so it can be posted
105 // to a MessageLoop.
106 void CallOnMessageReceived(scoped_refptr<TextInputClientMessageFilter> filter,
107                            const IPC::Message& message) {
108   filter->OnMessageReceived(message);
109 }
110
111 }  // namespace
112
113 // Test Cases //////////////////////////////////////////////////////////////////
114
115 TEST_F(TextInputClientMacTest, GetCharacterIndex) {
116   ScopedTestingThread thread(this);
117   const NSUInteger kSuccessValue = 42;
118
119   PostTask(FROM_HERE,
120            base::Bind(&TextInputClientMac::SetCharacterIndexAndSignal,
121                       base::Unretained(service()), kSuccessValue));
122   NSUInteger index = service()->GetCharacterIndexAtPoint(
123       widget(), gfx::Point(2, 2));
124
125   EXPECT_EQ(1U, ipc_sink().message_count());
126   EXPECT_TRUE(ipc_sink().GetUniqueMessageMatching(
127       TextInputClientMsg_CharacterIndexForPoint::ID));
128   EXPECT_EQ(kSuccessValue, index);
129 }
130
131 TEST_F(TextInputClientMacTest, TimeoutCharacterIndex) {
132   NSUInteger index = service()->GetCharacterIndexAtPoint(
133       widget(), gfx::Point(2, 2));
134   EXPECT_EQ(1U, ipc_sink().message_count());
135   EXPECT_TRUE(ipc_sink().GetUniqueMessageMatching(
136       TextInputClientMsg_CharacterIndexForPoint::ID));
137   EXPECT_EQ(NSNotFound, index);
138 }
139
140 TEST_F(TextInputClientMacTest, NotFoundCharacterIndex) {
141   ScopedTestingThread thread(this);
142   const NSUInteger kPreviousValue = 42;
143   const size_t kNotFoundValue = static_cast<size_t>(-1);
144
145   // Set an arbitrary value to ensure the index is not |NSNotFound|.
146   PostTask(FROM_HERE,
147            base::Bind(&TextInputClientMac::SetCharacterIndexAndSignal,
148                       base::Unretained(service()), kPreviousValue));
149
150   scoped_refptr<TextInputClientMessageFilter> filter(
151       new TextInputClientMessageFilter(widget()->GetProcess()->GetID()));
152   scoped_ptr<IPC::Message> message(
153       new TextInputClientReplyMsg_GotCharacterIndexForPoint(
154           widget()->GetRoutingID(), kNotFoundValue));
155   // Set |WTF::notFound| to the index |kTaskDelayMs| after the previous
156   // setting.
157   PostTask(FROM_HERE,
158            base::Bind(&CallOnMessageReceived, filter, *message),
159            base::TimeDelta::FromMilliseconds(kTaskDelayMs) * 2);
160
161   NSUInteger index = service()->GetCharacterIndexAtPoint(
162       widget(), gfx::Point(2, 2));
163   EXPECT_EQ(kPreviousValue, index);
164   index = service()->GetCharacterIndexAtPoint(widget(), gfx::Point(2, 2));
165   EXPECT_EQ(NSNotFound, index);
166
167   EXPECT_EQ(2U, ipc_sink().message_count());
168   for (size_t i = 0; i < ipc_sink().message_count(); ++i) {
169     const IPC::Message* ipc_message = ipc_sink().GetMessageAt(i);
170     EXPECT_EQ(ipc_message->type(),
171               TextInputClientMsg_CharacterIndexForPoint::ID);
172   }
173 }
174
175 TEST_F(TextInputClientMacTest, GetRectForRange) {
176   ScopedTestingThread thread(this);
177   const NSRect kSuccessValue = NSMakeRect(42, 43, 44, 45);
178
179   PostTask(FROM_HERE,
180            base::Bind(&TextInputClientMac::SetFirstRectAndSignal,
181                       base::Unretained(service()), kSuccessValue));
182   NSRect rect = service()->GetFirstRectForRange(widget(), NSMakeRange(0, 32));
183
184   EXPECT_EQ(1U, ipc_sink().message_count());
185   EXPECT_TRUE(ipc_sink().GetUniqueMessageMatching(
186       TextInputClientMsg_FirstRectForCharacterRange::ID));
187   EXPECT_TRUE(NSEqualRects(kSuccessValue, rect));
188 }
189
190 TEST_F(TextInputClientMacTest, TimeoutRectForRange) {
191   NSRect rect = service()->GetFirstRectForRange(widget(), NSMakeRange(0, 32));
192   EXPECT_EQ(1U, ipc_sink().message_count());
193   EXPECT_TRUE(ipc_sink().GetUniqueMessageMatching(
194       TextInputClientMsg_FirstRectForCharacterRange::ID));
195   EXPECT_TRUE(NSEqualRects(NSZeroRect, rect));
196 }
197
198 TEST_F(TextInputClientMacTest, GetSubstring) {
199   ScopedTestingThread thread(this);
200   NSDictionary* attributes =
201       [NSDictionary dictionaryWithObject:[NSColor purpleColor]
202                                   forKey:NSForegroundColorAttributeName];
203   base::scoped_nsobject<NSAttributedString> kSuccessValue(
204       [[NSAttributedString alloc] initWithString:@"Barney is a purple dinosaur"
205                                       attributes:attributes]);
206
207   PostTask(FROM_HERE,
208            base::Bind(&TextInputClientMac::SetSubstringAndSignal,
209                       base::Unretained(service()),
210                       base::Unretained(kSuccessValue.get())));
211   NSAttributedString* string = service()->GetAttributedSubstringFromRange(
212       widget(), NSMakeRange(0, 32));
213
214   EXPECT_NSEQ(kSuccessValue, string);
215   EXPECT_NE(kSuccessValue.get(), string);  // |string| should be a copy.
216   EXPECT_EQ(1U, ipc_sink().message_count());
217   EXPECT_TRUE(ipc_sink().GetUniqueMessageMatching(
218       TextInputClientMsg_StringForRange::ID));
219 }
220
221 TEST_F(TextInputClientMacTest, TimeoutSubstring) {
222   NSAttributedString* string = service()->GetAttributedSubstringFromRange(
223       widget(), NSMakeRange(0, 32));
224   EXPECT_EQ(nil, string);
225   EXPECT_EQ(1U, ipc_sink().message_count());
226   EXPECT_TRUE(ipc_sink().GetUniqueMessageMatching(
227       TextInputClientMsg_StringForRange::ID));
228 }
229
230 }  // namespace content