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 "base/mac/foundation_util.h"
8 #include "base/stl_util.h"
9 #include "base/strings/sys_string_conversions.h"
10 #include "base/strings/utf_string_conversions.h"
11 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
12 #include "chrome/browser/ui/cocoa/run_loop_testing.h"
13 #import "chrome/browser/ui/cocoa/website_settings/permission_bubble_cocoa.h"
14 #import "chrome/browser/ui/cocoa/website_settings/split_block_button.h"
15 #include "chrome/browser/ui/website_settings/mock_permission_bubble_request.h"
16 #include "chrome/grit/generated_resources.h"
17 #include "testing/gmock/include/gmock/gmock.h"
18 #include "ui/base/l10n/l10n_util.h"
19 #include "ui/base/l10n/l10n_util_mac.h"
20 #import "ui/events/test/cocoa_test_event_utils.h"
22 @class ConstrainedWindowButton;
24 @interface PermissionBubbleController (ExposedForTesting)
25 - (void)ok:(id)sender;
26 - (void)onAllow:(id)sender;
27 - (void)onBlock:(id)sender;
28 - (void)onCustomize:(id)sender;
29 - (void)onCheckboxChanged:(id)sender;
32 @interface SplitBlockButton (ExposedForTesting)
37 const char* const kPermissionA = "Permission A";
38 const char* const kPermissionB = "Permission B";
39 const char* const kPermissionC = "Permission C";
42 class PermissionBubbleControllerTest : public CocoaTest,
43 public PermissionBubbleView::Delegate {
46 MOCK_METHOD2(ToggleAccept, void(int, bool));
47 MOCK_METHOD0(SetCustomizationMode, void());
48 MOCK_METHOD0(Accept, void());
49 MOCK_METHOD0(Deny, void());
50 MOCK_METHOD0(Closing, void());
51 MOCK_METHOD1(SetView, void(PermissionBubbleView*));
53 virtual void SetUp() override {
55 bridge_.reset(new PermissionBubbleCocoa(nil));
56 AddRequest(kPermissionA);
57 controller_ = [[PermissionBubbleController alloc]
58 initWithParentWindow:test_window()
59 bridge:bridge_.get()];
62 virtual void TearDown() override {
64 chrome::testing::NSRunLoopRunAllPending();
65 STLDeleteElements(&requests_);
66 CocoaTest::TearDown();
69 void AddRequest(const std::string& title) {
70 MockPermissionBubbleRequest* request = new MockPermissionBubbleRequest(
72 l10n_util::GetStringUTF8(IDS_PERMISSION_ALLOW),
73 l10n_util::GetStringUTF8(IDS_PERMISSION_DENY));
74 requests_.push_back(request);
77 NSButton* FindButtonWithTitle(const std::string& title) {
78 return FindButtonWithTitle(base::SysUTF8ToNSString(title),
79 [ConstrainedWindowButton class]);
82 NSButton* FindButtonWithTitle(int title_id) {
83 return FindButtonWithTitle(l10n_util::GetNSString(title_id),
84 [ConstrainedWindowButton class]);
87 NSButton* FindMenuButtonWithTitle(int title_id) {
88 return FindButtonWithTitle(l10n_util::GetNSString(title_id),
89 [NSPopUpButton class]);
92 // IDS_PERMISSION_ALLOW and IDS_PERMISSION_DENY are used for two distinct
93 // UI elements, both of which derive from NSButton. So check the expected
94 // class, not just NSButton, as well as the title.
95 NSButton* FindButtonWithTitle(NSString* title, Class button_class) {
96 for (NSButton* view in [[controller_ bubble] subviews]) {
97 if ([view isKindOfClass:button_class] &&
98 [title isEqualToString:[view title]]) {
105 NSTextField* FindTextFieldWithString(const std::string& text) {
106 NSView* parent = base::mac::ObjCCastStrict<NSView>([controller_ bubble]);
107 return FindTextFieldWithString(parent, base::SysUTF8ToNSString(text));
110 NSTextField* FindTextFieldWithString(NSView* view, NSString* text) {
111 NSTextField* textField = nil;
112 for (NSView* child in [view subviews]) {
113 textField = base::mac::ObjCCast<NSTextField>(child);
114 if (![[textField stringValue] hasSuffix:text]) {
115 textField = FindTextFieldWithString(child, text);
123 void ChangePermissionMenuSelection(NSButton* menu_button, int next_title_id) {
124 NSMenu* menu = [base::mac::ObjCCastStrict<NSPopUpButton>(menu_button) menu];
125 NSString* next_title = l10n_util::GetNSString(next_title_id);
126 EXPECT_EQ([[menu itemWithTitle:[menu_button title]] state], NSOnState);
127 NSMenuItem* next_item = [menu itemWithTitle:next_title];
128 EXPECT_EQ([next_item state], NSOffState);
129 [menu performActionForItemAtIndex:[menu indexOfItem:next_item]];
133 PermissionBubbleController* controller_; // Weak; it deletes itself.
134 scoped_ptr<PermissionBubbleCocoa> bridge_;
135 std::vector<PermissionBubbleRequest*> requests_;
136 std::vector<bool> accept_states_;
139 TEST_F(PermissionBubbleControllerTest, ShowAndClose) {
140 EXPECT_FALSE([[controller_ window] isVisible]);
141 [controller_ showWindow:nil];
142 EXPECT_TRUE([[controller_ window] isVisible]);
145 TEST_F(PermissionBubbleControllerTest, ShowSinglePermission) {
146 [controller_ showAtAnchor:NSZeroPoint
148 forRequests:requests_
149 acceptStates:accept_states_];
151 EXPECT_TRUE(FindTextFieldWithString(kPermissionA));
152 EXPECT_TRUE(FindButtonWithTitle(IDS_PERMISSION_ALLOW));
153 EXPECT_TRUE(FindButtonWithTitle(IDS_PERMISSION_DENY));
154 EXPECT_FALSE(FindButtonWithTitle(IDS_OK));
157 TEST_F(PermissionBubbleControllerTest, ShowMultiplePermissions) {
158 AddRequest(kPermissionB);
159 AddRequest(kPermissionC);
161 accept_states_.push_back(true); // A
162 accept_states_.push_back(true); // B
163 accept_states_.push_back(true); // C
165 [controller_ showAtAnchor:NSZeroPoint
167 forRequests:requests_
168 acceptStates:accept_states_];
170 EXPECT_TRUE(FindTextFieldWithString(kPermissionA));
171 EXPECT_TRUE(FindTextFieldWithString(kPermissionB));
172 EXPECT_TRUE(FindTextFieldWithString(kPermissionC));
174 EXPECT_FALSE(FindButtonWithTitle(IDS_PERMISSION_ALLOW));
175 EXPECT_FALSE(FindButtonWithTitle(IDS_PERMISSION_DENY));
176 EXPECT_TRUE(FindButtonWithTitle(IDS_OK));
179 TEST_F(PermissionBubbleControllerTest, ShowMultiplePermissionsAllow) {
180 AddRequest(kPermissionB);
182 accept_states_.push_back(true); // A
183 accept_states_.push_back(true); // B
185 [controller_ showAtAnchor:NSZeroPoint
187 forRequests:requests_
188 acceptStates:accept_states_];
190 // Test that all menus have 'Allow' visible.
191 EXPECT_TRUE(FindMenuButtonWithTitle(IDS_PERMISSION_ALLOW));
192 EXPECT_FALSE(FindMenuButtonWithTitle(IDS_PERMISSION_DENY));
194 EXPECT_TRUE(FindButtonWithTitle(IDS_OK));
195 EXPECT_FALSE(FindButtonWithTitle(IDS_PERMISSION_ALLOW));
196 EXPECT_FALSE(FindButtonWithTitle(IDS_PERMISSION_DENY));
199 TEST_F(PermissionBubbleControllerTest, ShowMultiplePermissionsBlock) {
200 AddRequest(kPermissionB);
202 accept_states_.push_back(false); // A
203 accept_states_.push_back(false); // B
205 [controller_ showAtAnchor:NSZeroPoint
207 forRequests:requests_
208 acceptStates:accept_states_];
210 // Test that all menus have 'Block' visible.
211 EXPECT_TRUE(FindMenuButtonWithTitle(IDS_PERMISSION_DENY));
212 EXPECT_FALSE(FindMenuButtonWithTitle(IDS_PERMISSION_ALLOW));
214 EXPECT_TRUE(FindButtonWithTitle(IDS_OK));
215 EXPECT_FALSE(FindButtonWithTitle(IDS_PERMISSION_ALLOW));
216 EXPECT_FALSE(FindButtonWithTitle(IDS_PERMISSION_DENY));
219 TEST_F(PermissionBubbleControllerTest, ShowMultiplePermissionsMixed) {
220 AddRequest(kPermissionB);
221 AddRequest(kPermissionC);
223 accept_states_.push_back(false); // A
224 accept_states_.push_back(false); // B
225 accept_states_.push_back(true); // C
227 [controller_ showAtAnchor:NSZeroPoint
229 forRequests:requests_
230 acceptStates:accept_states_];
232 // Test that both 'allow' and 'deny' are visible.
233 EXPECT_TRUE(FindMenuButtonWithTitle(IDS_PERMISSION_DENY));
234 EXPECT_TRUE(FindMenuButtonWithTitle(IDS_PERMISSION_ALLOW));
236 EXPECT_TRUE(FindButtonWithTitle(IDS_OK));
237 EXPECT_FALSE(FindButtonWithTitle(IDS_PERMISSION_ALLOW));
238 EXPECT_FALSE(FindButtonWithTitle(IDS_PERMISSION_DENY));
241 TEST_F(PermissionBubbleControllerTest, OK) {
242 AddRequest(kPermissionB);
244 accept_states_.push_back(true); // A
245 accept_states_.push_back(true); // B
247 [controller_ showAtAnchor:NSZeroPoint
249 forRequests:requests_
250 acceptStates:accept_states_];
252 EXPECT_CALL(*this, Closing()).Times(1);
253 [FindButtonWithTitle(IDS_OK) performClick:nil];
256 TEST_F(PermissionBubbleControllerTest, Allow) {
257 [controller_ showAtAnchor:NSZeroPoint
259 forRequests:requests_
260 acceptStates:accept_states_];
262 EXPECT_CALL(*this, Accept()).Times(1);
263 [FindButtonWithTitle(IDS_PERMISSION_ALLOW) performClick:nil];
266 TEST_F(PermissionBubbleControllerTest, Deny) {
267 [controller_ showAtAnchor:NSZeroPoint
269 forRequests:requests_
270 acceptStates:accept_states_];
272 EXPECT_CALL(*this, Deny()).Times(1);
273 [FindButtonWithTitle(IDS_PERMISSION_DENY) performClick:nil];
276 TEST_F(PermissionBubbleControllerTest, ChangePermissionSelection) {
277 AddRequest(kPermissionB);
279 accept_states_.push_back(true); // A
280 accept_states_.push_back(false); // B
282 [controller_ showAtAnchor:NSZeroPoint
284 forRequests:requests_
285 acceptStates:accept_states_];
287 EXPECT_CALL(*this, ToggleAccept(0, false)).Times(1);
288 EXPECT_CALL(*this, ToggleAccept(1, true)).Times(1);
289 NSButton* menu_a = FindMenuButtonWithTitle(IDS_PERMISSION_ALLOW);
290 NSButton* menu_b = FindMenuButtonWithTitle(IDS_PERMISSION_DENY);
291 ChangePermissionMenuSelection(menu_a, IDS_PERMISSION_DENY);
292 ChangePermissionMenuSelection(menu_b, IDS_PERMISSION_ALLOW);