1 // Copyright 2014 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 "chrome/browser/ui/cocoa/website_settings/permission_bubble_controller.h"
7 #include <Carbon/Carbon.h>
9 #include "base/mac/foundation_util.h"
10 #include "base/stl_util.h"
11 #include "base/strings/sys_string_conversions.h"
12 #include "base/strings/utf_string_conversions.h"
13 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
14 #include "chrome/browser/ui/cocoa/run_loop_testing.h"
15 #import "chrome/browser/ui/cocoa/website_settings/permission_bubble_cocoa.h"
16 #import "chrome/browser/ui/cocoa/website_settings/split_block_button.h"
17 #include "chrome/browser/ui/website_settings/mock_permission_bubble_request.h"
18 #include "chrome/grit/generated_resources.h"
19 #include "testing/gmock/include/gmock/gmock.h"
20 #include "ui/base/l10n/l10n_util.h"
21 #include "ui/base/l10n/l10n_util_mac.h"
22 #import "ui/events/test/cocoa_test_event_utils.h"
24 @class ConstrainedWindowButton;
26 @interface PermissionBubbleController (ExposedForTesting)
27 - (void)ok:(id)sender;
28 - (void)onAllow:(id)sender;
29 - (void)onBlock:(id)sender;
30 - (void)onCustomize:(id)sender;
31 - (void)onCheckboxChanged:(id)sender;
34 @interface SplitBlockButton (ExposedForTesting)
39 const char* const kPermissionA = "Permission A";
40 const char* const kPermissionB = "Permission B";
41 const char* const kPermissionC = "Permission C";
44 class PermissionBubbleControllerTest : public CocoaTest,
45 public PermissionBubbleView::Delegate {
48 MOCK_METHOD2(ToggleAccept, void(int, bool));
49 MOCK_METHOD0(SetCustomizationMode, void());
50 MOCK_METHOD0(Accept, void());
51 MOCK_METHOD0(Deny, void());
52 MOCK_METHOD0(Closing, void());
53 MOCK_METHOD1(SetView, void(PermissionBubbleView*));
55 virtual void SetUp() override {
57 bridge_.reset(new PermissionBubbleCocoa(nil));
58 AddRequest(kPermissionA);
59 controller_ = [[PermissionBubbleController alloc]
60 initWithParentWindow:test_window()
61 bridge:bridge_.get()];
64 virtual void TearDown() override {
66 chrome::testing::NSRunLoopRunAllPending();
67 STLDeleteElements(&requests_);
68 CocoaTest::TearDown();
71 void AddRequest(const std::string& title) {
72 MockPermissionBubbleRequest* request = new MockPermissionBubbleRequest(
74 l10n_util::GetStringUTF8(IDS_PERMISSION_ALLOW),
75 l10n_util::GetStringUTF8(IDS_PERMISSION_DENY));
76 requests_.push_back(request);
79 NSButton* FindButtonWithTitle(const std::string& title) {
80 return FindButtonWithTitle(base::SysUTF8ToNSString(title),
81 [ConstrainedWindowButton class]);
84 NSButton* FindButtonWithTitle(int title_id) {
85 return FindButtonWithTitle(l10n_util::GetNSString(title_id),
86 [ConstrainedWindowButton class]);
89 NSButton* FindMenuButtonWithTitle(int title_id) {
90 return FindButtonWithTitle(l10n_util::GetNSString(title_id),
91 [NSPopUpButton class]);
94 // IDS_PERMISSION_ALLOW and IDS_PERMISSION_DENY are used for two distinct
95 // UI elements, both of which derive from NSButton. So check the expected
96 // class, not just NSButton, as well as the title.
97 NSButton* FindButtonWithTitle(NSString* title, Class button_class) {
98 for (NSButton* view in [[controller_ bubble] subviews]) {
99 if ([view isKindOfClass:button_class] &&
100 [title isEqualToString:[view title]]) {
107 NSTextField* FindTextFieldWithString(const std::string& text) {
108 NSView* parent = base::mac::ObjCCastStrict<NSView>([controller_ bubble]);
109 return FindTextFieldWithString(parent, base::SysUTF8ToNSString(text));
112 NSTextField* FindTextFieldWithString(NSView* view, NSString* text) {
113 NSTextField* textField = nil;
114 for (NSView* child in [view subviews]) {
115 textField = base::mac::ObjCCast<NSTextField>(child);
116 if (![[textField stringValue] hasSuffix:text]) {
117 textField = FindTextFieldWithString(child, text);
125 void ChangePermissionMenuSelection(NSButton* menu_button, int next_title_id) {
126 NSMenu* menu = [base::mac::ObjCCastStrict<NSPopUpButton>(menu_button) menu];
127 NSString* next_title = l10n_util::GetNSString(next_title_id);
128 EXPECT_EQ([[menu itemWithTitle:[menu_button title]] state], NSOnState);
129 NSMenuItem* next_item = [menu itemWithTitle:next_title];
130 EXPECT_EQ([next_item state], NSOffState);
131 [menu performActionForItemAtIndex:[menu indexOfItem:next_item]];
135 PermissionBubbleController* controller_; // Weak; it deletes itself.
136 scoped_ptr<PermissionBubbleCocoa> bridge_;
137 std::vector<PermissionBubbleRequest*> requests_;
138 std::vector<bool> accept_states_;
141 TEST_F(PermissionBubbleControllerTest, ShowAndClose) {
142 EXPECT_FALSE([[controller_ window] isVisible]);
143 [controller_ showWindow:nil];
144 EXPECT_TRUE([[controller_ window] isVisible]);
147 TEST_F(PermissionBubbleControllerTest, ShowSinglePermission) {
148 [controller_ showAtAnchor:NSZeroPoint
150 forRequests:requests_
151 acceptStates:accept_states_];
153 EXPECT_TRUE(FindTextFieldWithString(kPermissionA));
154 EXPECT_TRUE(FindButtonWithTitle(IDS_PERMISSION_ALLOW));
155 EXPECT_TRUE(FindButtonWithTitle(IDS_PERMISSION_DENY));
156 EXPECT_FALSE(FindButtonWithTitle(IDS_OK));
159 TEST_F(PermissionBubbleControllerTest, ShowMultiplePermissions) {
160 AddRequest(kPermissionB);
161 AddRequest(kPermissionC);
163 accept_states_.push_back(true); // A
164 accept_states_.push_back(true); // B
165 accept_states_.push_back(true); // C
167 [controller_ showAtAnchor:NSZeroPoint
169 forRequests:requests_
170 acceptStates:accept_states_];
172 EXPECT_TRUE(FindTextFieldWithString(kPermissionA));
173 EXPECT_TRUE(FindTextFieldWithString(kPermissionB));
174 EXPECT_TRUE(FindTextFieldWithString(kPermissionC));
176 EXPECT_FALSE(FindButtonWithTitle(IDS_PERMISSION_ALLOW));
177 EXPECT_FALSE(FindButtonWithTitle(IDS_PERMISSION_DENY));
178 EXPECT_TRUE(FindButtonWithTitle(IDS_OK));
181 TEST_F(PermissionBubbleControllerTest, ShowMultiplePermissionsAllow) {
182 AddRequest(kPermissionB);
184 accept_states_.push_back(true); // A
185 accept_states_.push_back(true); // B
187 [controller_ showAtAnchor:NSZeroPoint
189 forRequests:requests_
190 acceptStates:accept_states_];
192 // Test that all menus have 'Allow' visible.
193 EXPECT_TRUE(FindMenuButtonWithTitle(IDS_PERMISSION_ALLOW));
194 EXPECT_FALSE(FindMenuButtonWithTitle(IDS_PERMISSION_DENY));
196 EXPECT_TRUE(FindButtonWithTitle(IDS_OK));
197 EXPECT_FALSE(FindButtonWithTitle(IDS_PERMISSION_ALLOW));
198 EXPECT_FALSE(FindButtonWithTitle(IDS_PERMISSION_DENY));
201 TEST_F(PermissionBubbleControllerTest, ShowMultiplePermissionsBlock) {
202 AddRequest(kPermissionB);
204 accept_states_.push_back(false); // A
205 accept_states_.push_back(false); // B
207 [controller_ showAtAnchor:NSZeroPoint
209 forRequests:requests_
210 acceptStates:accept_states_];
212 // Test that all menus have 'Block' visible.
213 EXPECT_TRUE(FindMenuButtonWithTitle(IDS_PERMISSION_DENY));
214 EXPECT_FALSE(FindMenuButtonWithTitle(IDS_PERMISSION_ALLOW));
216 EXPECT_TRUE(FindButtonWithTitle(IDS_OK));
217 EXPECT_FALSE(FindButtonWithTitle(IDS_PERMISSION_ALLOW));
218 EXPECT_FALSE(FindButtonWithTitle(IDS_PERMISSION_DENY));
221 TEST_F(PermissionBubbleControllerTest, ShowMultiplePermissionsMixed) {
222 AddRequest(kPermissionB);
223 AddRequest(kPermissionC);
225 accept_states_.push_back(false); // A
226 accept_states_.push_back(false); // B
227 accept_states_.push_back(true); // C
229 [controller_ showAtAnchor:NSZeroPoint
231 forRequests:requests_
232 acceptStates:accept_states_];
234 // Test that both 'allow' and 'deny' are visible.
235 EXPECT_TRUE(FindMenuButtonWithTitle(IDS_PERMISSION_DENY));
236 EXPECT_TRUE(FindMenuButtonWithTitle(IDS_PERMISSION_ALLOW));
238 EXPECT_TRUE(FindButtonWithTitle(IDS_OK));
239 EXPECT_FALSE(FindButtonWithTitle(IDS_PERMISSION_ALLOW));
240 EXPECT_FALSE(FindButtonWithTitle(IDS_PERMISSION_DENY));
243 TEST_F(PermissionBubbleControllerTest, OK) {
244 AddRequest(kPermissionB);
246 accept_states_.push_back(true); // A
247 accept_states_.push_back(true); // B
249 [controller_ showAtAnchor:NSZeroPoint
251 forRequests:requests_
252 acceptStates:accept_states_];
254 EXPECT_CALL(*this, Accept()).Times(1);
255 [FindButtonWithTitle(IDS_OK) performClick:nil];
258 TEST_F(PermissionBubbleControllerTest, Allow) {
259 [controller_ showAtAnchor:NSZeroPoint
261 forRequests:requests_
262 acceptStates:accept_states_];
264 EXPECT_CALL(*this, Accept()).Times(1);
265 [FindButtonWithTitle(IDS_PERMISSION_ALLOW) performClick:nil];
268 TEST_F(PermissionBubbleControllerTest, Deny) {
269 [controller_ showAtAnchor:NSZeroPoint
271 forRequests:requests_
272 acceptStates:accept_states_];
274 EXPECT_CALL(*this, Deny()).Times(1);
275 [FindButtonWithTitle(IDS_PERMISSION_DENY) performClick:nil];
278 TEST_F(PermissionBubbleControllerTest, ChangePermissionSelection) {
279 AddRequest(kPermissionB);
281 accept_states_.push_back(true); // A
282 accept_states_.push_back(false); // B
284 [controller_ showAtAnchor:NSZeroPoint
286 forRequests:requests_
287 acceptStates:accept_states_];
289 EXPECT_CALL(*this, ToggleAccept(0, false)).Times(1);
290 EXPECT_CALL(*this, ToggleAccept(1, true)).Times(1);
291 NSButton* menu_a = FindMenuButtonWithTitle(IDS_PERMISSION_ALLOW);
292 NSButton* menu_b = FindMenuButtonWithTitle(IDS_PERMISSION_DENY);
293 ChangePermissionMenuSelection(menu_a, IDS_PERMISSION_DENY);
294 ChangePermissionMenuSelection(menu_b, IDS_PERMISSION_ALLOW);
297 TEST_F(PermissionBubbleControllerTest, EscapeCloses) {
298 [controller_ showAtAnchor:NSZeroPoint
300 forRequests:requests_
301 acceptStates:accept_states_];
303 EXPECT_TRUE([[controller_ window] isVisible]);
304 [[controller_ window]
305 performKeyEquivalent:cocoa_test_event_utils::KeyEventWithKeyCode(
306 kVK_Escape, '\e', NSKeyDown, 0)];
307 EXPECT_FALSE([[controller_ window] isVisible]);