Ignore non-active fullscreen windows for shelf state.
[chromium-blink-merge.git] / content / browser / renderer_host / text_input_client_mac_unittest.mm
blob0993018e8f4b808146184898397936b311fc332a
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   virtual ~MockRenderWidgetHostDelegate() {}
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       : message_loop_(base::MessageLoop::TYPE_UI),
39         browser_context_(),
40         process_factory_(),
41         delegate_(),
42         widget_(&delegate_,
43                 process_factory_.CreateRenderProcessHost(
44                     &browser_context_, NULL),
45                 MSG_ROUTING_NONE, false),
46         thread_("TextInputClientMacTestThread") {}
48   // Accessor for the TextInputClientMac instance.
49   TextInputClientMac* service() {
50     return TextInputClientMac::GetInstance();
51   }
53   // Helper method to post a task on the testing thread's MessageLoop after
54   // a short delay.
55   void PostTask(const tracked_objects::Location& from_here,
56                 const base::Closure& task) {
57     PostTask(from_here, task, base::TimeDelta::FromMilliseconds(kTaskDelayMs));
58   }
60   void PostTask(const tracked_objects::Location& from_here,
61                 const base::Closure& task,
62                 const base::TimeDelta delay) {
63     thread_.message_loop()->PostDelayedTask(from_here, task, delay);
64   }
66   RenderWidgetHostImpl* widget() {
67     return &widget_;
68   }
70   IPC::TestSink& ipc_sink() {
71     return static_cast<MockRenderProcessHost*>(widget()->GetProcess())->sink();
72   }
74  private:
75   friend class ScopedTestingThread;
77   base::MessageLoop message_loop_;
78   TestBrowserContext browser_context_;
80   // Gets deleted when the last RWH in the "process" gets destroyed.
81   MockRenderProcessHostFactory process_factory_;
82   MockRenderWidgetHostDelegate delegate_;
83   RenderWidgetHostImpl widget_;
85   base::Thread thread_;
88 ////////////////////////////////////////////////////////////////////////////////
90 // Helper class that Start()s and Stop()s a thread according to the scope of the
91 // object.
92 class ScopedTestingThread {
93  public:
94   ScopedTestingThread(TextInputClientMacTest* test) : thread_(test->thread_) {
95     thread_.Start();
96   }
97   ~ScopedTestingThread() {
98     thread_.Stop();
99   }
101  private:
102   base::Thread& thread_;
105 // Adapter for OnMessageReceived to ignore return type so it can be posted
106 // to a MessageLoop.
107 void CallOnMessageReceived(scoped_refptr<TextInputClientMessageFilter> filter,
108                            const IPC::Message& message,
109                            bool* message_was_ok) {
110   filter->OnMessageReceived(message, message_was_ok);
113 }  // namespace
115 // Test Cases //////////////////////////////////////////////////////////////////
117 TEST_F(TextInputClientMacTest, GetCharacterIndex) {
118   ScopedTestingThread thread(this);
119   const NSUInteger kSuccessValue = 42;
121   PostTask(FROM_HERE,
122            base::Bind(&TextInputClientMac::SetCharacterIndexAndSignal,
123                       base::Unretained(service()), kSuccessValue));
124   NSUInteger index = service()->GetCharacterIndexAtPoint(
125       widget(), gfx::Point(2, 2));
127   EXPECT_EQ(1U, ipc_sink().message_count());
128   EXPECT_TRUE(ipc_sink().GetUniqueMessageMatching(
129       TextInputClientMsg_CharacterIndexForPoint::ID));
130   EXPECT_EQ(kSuccessValue, index);
133 TEST_F(TextInputClientMacTest, TimeoutCharacterIndex) {
134   NSUInteger index = service()->GetCharacterIndexAtPoint(
135       widget(), gfx::Point(2, 2));
136   EXPECT_EQ(1U, ipc_sink().message_count());
137   EXPECT_TRUE(ipc_sink().GetUniqueMessageMatching(
138       TextInputClientMsg_CharacterIndexForPoint::ID));
139   EXPECT_EQ(NSNotFound, index);
142 TEST_F(TextInputClientMacTest, NotFoundCharacterIndex) {
143   ScopedTestingThread thread(this);
144   const NSUInteger kPreviousValue = 42;
145   const size_t kNotFoundValue = static_cast<size_t>(-1);
147   // Set an arbitrary value to ensure the index is not |NSNotFound|.
148   PostTask(FROM_HERE,
149            base::Bind(&TextInputClientMac::SetCharacterIndexAndSignal,
150                       base::Unretained(service()), kPreviousValue));
152   scoped_refptr<TextInputClientMessageFilter> filter(
153       new TextInputClientMessageFilter(widget()->GetProcess()->GetID()));
154   scoped_ptr<IPC::Message> message(
155       new TextInputClientReplyMsg_GotCharacterIndexForPoint(
156           widget()->GetRoutingID(), kNotFoundValue));
157   bool message_ok = true;
158   // Set |WTF::notFound| to the index |kTaskDelayMs| after the previous
159   // setting.
160   PostTask(FROM_HERE,
161            base::Bind(&CallOnMessageReceived, filter, *message, &message_ok),
162            base::TimeDelta::FromMilliseconds(kTaskDelayMs) * 2);
164   NSUInteger index = service()->GetCharacterIndexAtPoint(
165       widget(), gfx::Point(2, 2));
166   EXPECT_EQ(kPreviousValue, index);
167   index = service()->GetCharacterIndexAtPoint(widget(), gfx::Point(2, 2));
168   EXPECT_EQ(NSNotFound, index);
170   EXPECT_EQ(2U, ipc_sink().message_count());
171   for (size_t i = 0; i < ipc_sink().message_count(); ++i) {
172     const IPC::Message* ipc_message = ipc_sink().GetMessageAt(i);
173     EXPECT_EQ(ipc_message->type(),
174               TextInputClientMsg_CharacterIndexForPoint::ID);
175   }
178 TEST_F(TextInputClientMacTest, GetRectForRange) {
179   ScopedTestingThread thread(this);
180   const NSRect kSuccessValue = NSMakeRect(42, 43, 44, 45);
182   PostTask(FROM_HERE,
183            base::Bind(&TextInputClientMac::SetFirstRectAndSignal,
184                       base::Unretained(service()), kSuccessValue));
185   NSRect rect = service()->GetFirstRectForRange(widget(), NSMakeRange(0, 32));
187   EXPECT_EQ(1U, ipc_sink().message_count());
188   EXPECT_TRUE(ipc_sink().GetUniqueMessageMatching(
189       TextInputClientMsg_FirstRectForCharacterRange::ID));
190   EXPECT_TRUE(NSEqualRects(kSuccessValue, rect));
193 TEST_F(TextInputClientMacTest, TimeoutRectForRange) {
194   NSRect rect = service()->GetFirstRectForRange(widget(), NSMakeRange(0, 32));
195   EXPECT_EQ(1U, ipc_sink().message_count());
196   EXPECT_TRUE(ipc_sink().GetUniqueMessageMatching(
197       TextInputClientMsg_FirstRectForCharacterRange::ID));
198   EXPECT_TRUE(NSEqualRects(NSZeroRect, rect));
201 TEST_F(TextInputClientMacTest, GetSubstring) {
202   ScopedTestingThread thread(this);
203   NSDictionary* attributes =
204       [NSDictionary dictionaryWithObject:[NSColor purpleColor]
205                                   forKey:NSForegroundColorAttributeName];
206   base::scoped_nsobject<NSAttributedString> kSuccessValue(
207       [[NSAttributedString alloc] initWithString:@"Barney is a purple dinosaur"
208                                       attributes:attributes]);
210   PostTask(FROM_HERE,
211            base::Bind(&TextInputClientMac::SetSubstringAndSignal,
212                       base::Unretained(service()),
213                       base::Unretained(kSuccessValue.get())));
214   NSAttributedString* string = service()->GetAttributedSubstringFromRange(
215       widget(), NSMakeRange(0, 32));
217   EXPECT_NSEQ(kSuccessValue, string);
218   EXPECT_NE(kSuccessValue.get(), string);  // |string| should be a copy.
219   EXPECT_EQ(1U, ipc_sink().message_count());
220   EXPECT_TRUE(ipc_sink().GetUniqueMessageMatching(
221       TextInputClientMsg_StringForRange::ID));
224 TEST_F(TextInputClientMacTest, TimeoutSubstring) {
225   NSAttributedString* string = service()->GetAttributedSubstringFromRange(
226       widget(), NSMakeRange(0, 32));
227   EXPECT_EQ(nil, string);
228   EXPECT_EQ(1U, ipc_sink().message_count());
229   EXPECT_TRUE(ipc_sink().GetUniqueMessageMatching(
230       TextInputClientMsg_StringForRange::ID));
233 }  // namespace content