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/render_widget_host_view_mac_editcommand_helper.h"
6
7#import <Cocoa/Cocoa.h>
8
9#include "base/mac/scoped_nsautorelease_pool.h"
10#include "base/message_loop/message_loop.h"
11#include "content/browser/compositor/test/no_transport_image_transport_factory.h"
12#include "content/browser/gpu/compositor_util.h"
13#include "content/browser/renderer_host/render_widget_host_delegate.h"
14#include "content/browser/renderer_host/render_widget_host_impl.h"
15#include "content/common/input_messages.h"
16#include "content/public/test/mock_render_process_host.h"
17#include "content/public/test/test_browser_context.h"
18#include "testing/gmock/include/gmock/gmock.h"
19#include "testing/gtest/include/gtest/gtest.h"
20#include "testing/platform_test.h"
21#include "ui/base/layout.h"
22
23using content::RenderWidgetHostViewMac;
24
25// Bare bones obj-c class for testing purposes.
26@interface RenderWidgetHostViewMacEditCommandHelperTestClass : NSObject
27@end
28
29@implementation RenderWidgetHostViewMacEditCommandHelperTestClass
30@end
31
32// Class that owns a RenderWidgetHostViewMac.
33@interface RenderWidgetHostViewMacOwner :
34    NSObject<RenderWidgetHostViewMacOwner> {
35  RenderWidgetHostViewMac* rwhvm_;
36}
37
38- (id)initWithRenderWidgetHostViewMac:(RenderWidgetHostViewMac*)rwhvm;
39@end
40
41@implementation RenderWidgetHostViewMacOwner
42
43- (id)initWithRenderWidgetHostViewMac:(RenderWidgetHostViewMac*)rwhvm {
44  if ((self = [super init])) {
45    rwhvm_ = rwhvm;
46  }
47  return self;
48}
49
50- (RenderWidgetHostViewMac*)renderWidgetHostViewMac {
51  return rwhvm_;
52}
53
54@end
55
56namespace content {
57namespace {
58
59// Returns true if all the edit command names in the array are present in
60// test_obj.  edit_commands is a list of NSStrings, selector names are formed
61// by appending a trailing ':' to the string.
62bool CheckObjectRespondsToEditCommands(NSArray* edit_commands, id test_obj) {
63  for (NSString* edit_command_name in edit_commands) {
64    NSString* sel_str = [edit_command_name stringByAppendingString:@":"];
65    if (![test_obj respondsToSelector:NSSelectorFromString(sel_str)]) {
66      return false;
67    }
68  }
69  return true;
70}
71
72class MockRenderWidgetHostDelegate : public RenderWidgetHostDelegate {
73 public:
74  MockRenderWidgetHostDelegate() {}
75  virtual ~MockRenderWidgetHostDelegate() {}
76};
77
78// Create a RenderWidget for which we can filter messages.
79class RenderWidgetHostEditCommandCounter : public RenderWidgetHostImpl {
80 public:
81  RenderWidgetHostEditCommandCounter(
82      RenderWidgetHostDelegate* delegate,
83      RenderProcessHost* process,
84      int routing_id)
85    : RenderWidgetHostImpl(delegate, process, routing_id, false),
86      edit_command_message_count_(0) {
87  }
88
89  virtual bool Send(IPC::Message* message) OVERRIDE {
90    if (message->type() == InputMsg_ExecuteEditCommand::ID)
91      edit_command_message_count_++;
92    return RenderWidgetHostImpl::Send(message);
93  }
94
95  unsigned int edit_command_message_count_;
96};
97
98class RenderWidgetHostViewMacEditCommandHelperTest : public PlatformTest {
99 protected:
100  virtual void SetUp() {
101    if (IsDelegatedRendererEnabled()) {
102      ImageTransportFactory::InitializeForUnitTests(
103          scoped_ptr<ImageTransportFactory>(
104              new NoTransportImageTransportFactory));
105    }
106  }
107  virtual void TearDown() {
108    if (IsDelegatedRendererEnabled())
109      ImageTransportFactory::Terminate();
110  }
111};
112
113}  // namespace
114
115// Tests that editing commands make it through the pipeline all the way to
116// RenderWidgetHost.
117TEST_F(RenderWidgetHostViewMacEditCommandHelperTest,
118       TestEditingCommandDelivery) {
119  MockRenderWidgetHostDelegate delegate;
120  TestBrowserContext browser_context;
121  MockRenderProcessHost process_host(&browser_context);
122
123  // Populates |g_supported_scale_factors|.
124  std::vector<ui::ScaleFactor> supported_factors;
125  supported_factors.push_back(ui::SCALE_FACTOR_100P);
126  ui::test::ScopedSetSupportedScaleFactors scoped_supported(supported_factors);
127
128  RenderWidgetHostEditCommandCounter* render_widget =
129      new RenderWidgetHostEditCommandCounter(
130          &delegate, &process_host, MSG_ROUTING_NONE);
131
132  base::mac::ScopedNSAutoreleasePool pool;
133
134  // Owned by its |cocoa_view()|, i.e. |rwhv_cocoa|.
135  RenderWidgetHostViewMac* rwhv_mac = new RenderWidgetHostViewMac(
136      render_widget);
137  base::scoped_nsobject<RenderWidgetHostViewCocoa> rwhv_cocoa(
138      [rwhv_mac->cocoa_view() retain]);
139
140  RenderWidgetHostViewMacEditCommandHelper helper;
141  NSArray* edit_command_strings = helper.GetEditSelectorNames();
142  RenderWidgetHostViewMacOwner* rwhwvm_owner =
143      [[[RenderWidgetHostViewMacOwner alloc]
144          initWithRenderWidgetHostViewMac:rwhv_mac] autorelease];
145
146  helper.AddEditingSelectorsToClass([rwhwvm_owner class]);
147
148  for (NSString* edit_command_name in edit_command_strings) {
149    NSString* sel_str = [edit_command_name stringByAppendingString:@":"];
150    [rwhwvm_owner performSelector:NSSelectorFromString(sel_str) withObject:nil];
151  }
152
153  size_t num_edit_commands = [edit_command_strings count];
154  EXPECT_EQ(render_widget->edit_command_message_count_, num_edit_commands);
155  rwhv_cocoa.reset();
156  pool.Recycle();
157
158  {
159    // The |render_widget|'s process needs to be deleted within |message_loop|.
160    base::MessageLoop message_loop;
161    delete render_widget;
162  }
163}
164
165// Test RenderWidgetHostViewMacEditCommandHelper::AddEditingSelectorsToClass
166TEST_F(RenderWidgetHostViewMacEditCommandHelperTest,
167       TestAddEditingSelectorsToClass) {
168  RenderWidgetHostViewMacEditCommandHelper helper;
169  NSArray* edit_command_strings = helper.GetEditSelectorNames();
170  ASSERT_GT([edit_command_strings count], 0U);
171
172  // Create a class instance and add methods to the class.
173  RenderWidgetHostViewMacEditCommandHelperTestClass* test_obj =
174      [[[RenderWidgetHostViewMacEditCommandHelperTestClass alloc] init]
175          autorelease];
176
177  // Check that edit commands aren't already attached to the object.
178  ASSERT_FALSE(CheckObjectRespondsToEditCommands(edit_command_strings,
179      test_obj));
180
181  helper.AddEditingSelectorsToClass([test_obj class]);
182
183  // Check that all edit commands where added.
184  ASSERT_TRUE(CheckObjectRespondsToEditCommands(edit_command_strings,
185      test_obj));
186
187  // AddEditingSelectorsToClass() should be idempotent.
188  helper.AddEditingSelectorsToClass([test_obj class]);
189
190  // Check that all edit commands are still there.
191  ASSERT_TRUE(CheckObjectRespondsToEditCommands(edit_command_strings,
192      test_obj));
193}
194
195// Test RenderWidgetHostViewMacEditCommandHelper::IsMenuItemEnabled.
196TEST_F(RenderWidgetHostViewMacEditCommandHelperTest, TestMenuItemEnabling) {
197  RenderWidgetHostViewMacEditCommandHelper helper;
198  RenderWidgetHostViewMacOwner* rwhvm_owner =
199      [[[RenderWidgetHostViewMacOwner alloc] init] autorelease];
200
201  // The select all menu should always be enabled.
202  SEL select_all = NSSelectorFromString(@"selectAll:");
203  ASSERT_TRUE(helper.IsMenuItemEnabled(select_all, rwhvm_owner));
204
205  // Random selectors should be enabled by the function.
206  SEL garbage_selector = NSSelectorFromString(@"randomGarbageSelector:");
207  ASSERT_FALSE(helper.IsMenuItemEnabled(garbage_selector, rwhvm_owner));
208
209  // TODO(jeremy): Currently IsMenuItemEnabled just returns true for all edit
210  // selectors.  Once we go past that we should do more extensive testing here.
211}
212
213}  // namespace content
214