OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #import "chrome/browser/ui/cocoa/website_settings/website_settings_bubble_contro
ller.h" | |
6 | |
7 #include <stddef.h> | |
8 | |
9 #include "base/i18n/rtl.h" | |
10 #include "base/macros.h" | |
11 #include "base/strings/utf_string_conversions.h" | |
12 #include "chrome/browser/ui/cocoa/test/cocoa_test_helper.h" | |
13 #include "chrome/test/base/testing_profile.h" | |
14 #include "content/public/test/test_browser_thread_bundle.h" | |
15 #include "content/public/test/test_web_contents_factory.h" | |
16 #include "net/test/test_certificate_data.h" | |
17 #include "testing/gtest_mac.h" | |
18 | |
19 @interface WebsiteSettingsBubbleController (ExposedForTesting) | |
20 - (NSView*)permissionsView; | |
21 - (NSButton*)resetDecisionsButton; | |
22 - (NSButton*)connectionHelpButton; | |
23 @end | |
24 | |
25 @implementation WebsiteSettingsBubbleController (ExposedForTesting) | |
26 - (NSView*)permissionsView { | |
27 return permissionsView_; | |
28 } | |
29 - (NSButton*)resetDecisionsButton { | |
30 return resetDecisionsButton_; | |
31 } | |
32 - (NSButton*)connectionHelpButton { | |
33 | |
34 return connectionHelpButton_; | |
35 } | |
36 @end | |
37 | |
38 @interface WebsiteSettingsBubbleControllerForTesting | |
39 : WebsiteSettingsBubbleController { | |
40 @private | |
41 CGFloat defaultWindowWidth_; | |
42 } | |
43 @end | |
44 | |
45 @implementation WebsiteSettingsBubbleControllerForTesting | |
46 - (void)setDefaultWindowWidth:(CGFloat)width { | |
47 defaultWindowWidth_ = width; | |
48 } | |
49 - (CGFloat)defaultWindowWidth { | |
50 // If |defaultWindowWidth_| is 0, use the superclass implementation. | |
51 return defaultWindowWidth_ ? | |
52 defaultWindowWidth_ : [super defaultWindowWidth]; | |
53 } | |
54 @end | |
55 | |
56 namespace { | |
57 | |
58 // Indices of the menu items in the permission menu. | |
59 enum PermissionMenuIndices { | |
60 kMenuIndexContentSettingAllow = 0, | |
61 kMenuIndexContentSettingBlock, | |
62 kMenuIndexContentSettingDefault | |
63 }; | |
64 | |
65 const ContentSettingsType kTestPermissionTypes[] = { | |
66 CONTENT_SETTINGS_TYPE_IMAGES, | |
67 CONTENT_SETTINGS_TYPE_JAVASCRIPT, | |
68 CONTENT_SETTINGS_TYPE_PLUGINS, | |
69 CONTENT_SETTINGS_TYPE_POPUPS, | |
70 CONTENT_SETTINGS_TYPE_GEOLOCATION, | |
71 CONTENT_SETTINGS_TYPE_NOTIFICATIONS, | |
72 CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC | |
73 }; | |
74 | |
75 const ContentSetting kTestSettings[] = { | |
76 CONTENT_SETTING_DEFAULT, | |
77 CONTENT_SETTING_DEFAULT, | |
78 CONTENT_SETTING_ALLOW, | |
79 CONTENT_SETTING_BLOCK, | |
80 CONTENT_SETTING_ALLOW, | |
81 CONTENT_SETTING_BLOCK, | |
82 CONTENT_SETTING_BLOCK | |
83 }; | |
84 | |
85 const ContentSetting kTestDefaultSettings[] = { | |
86 CONTENT_SETTING_BLOCK, | |
87 CONTENT_SETTING_ASK | |
88 }; | |
89 | |
90 const content_settings::SettingSource kTestSettingSources[] = { | |
91 content_settings::SETTING_SOURCE_USER, | |
92 content_settings::SETTING_SOURCE_USER, | |
93 content_settings::SETTING_SOURCE_USER, | |
94 content_settings::SETTING_SOURCE_USER, | |
95 content_settings::SETTING_SOURCE_POLICY, | |
96 content_settings::SETTING_SOURCE_POLICY, | |
97 content_settings::SETTING_SOURCE_EXTENSION | |
98 }; | |
99 | |
100 class WebsiteSettingsBubbleControllerTest : public CocoaTest { | |
101 public: | |
102 WebsiteSettingsBubbleControllerTest() { | |
103 controller_ = nil; | |
104 } | |
105 | |
106 void TearDown() override { | |
107 [controller_ close]; | |
108 CocoaTest::TearDown(); | |
109 } | |
110 | |
111 protected: | |
112 WebsiteSettingsUIBridge* bridge_; // Weak, owned by controller. | |
113 | |
114 enum MatchType { | |
115 TEXT_EQUAL = 0, | |
116 TEXT_NOT_EQUAL | |
117 }; | |
118 | |
119 // Creates a new website settings bubble, with the given default width. | |
120 // If |default_width| is 0, the *default* default width will be used. | |
121 void CreateBubbleWithWidth(CGFloat default_width) { | |
122 bridge_ = new WebsiteSettingsUIBridge(nullptr); | |
123 | |
124 // The controller cleans up after itself when the window closes. | |
125 controller_ = [WebsiteSettingsBubbleControllerForTesting alloc]; | |
126 [controller_ setDefaultWindowWidth:default_width]; | |
127 [controller_ initWithParentWindow:test_window() | |
128 websiteSettingsUIBridge:bridge_ | |
129 webContents:web_contents_factory_.CreateWebContents( | |
130 &profile_) | |
131 url:GURL("https://www.google.com")]; | |
132 window_ = [controller_ window]; | |
133 [controller_ showWindow:nil]; | |
134 } | |
135 | |
136 void CreateBubble() { | |
137 CreateBubbleWithWidth(0.0); | |
138 } | |
139 | |
140 // Return a pointer to the first NSTextField found that either matches, or | |
141 // doesn't match, the given text. | |
142 NSTextField* FindTextField(MatchType match_type, NSString* text) { | |
143 // The window's only immediate child is an invisible view that has a flipped | |
144 // coordinate origin. It is into this that all views get placed. | |
145 NSArray* window_subviews = [[window_ contentView] subviews]; | |
146 EXPECT_EQ(1U, [window_subviews count]); | |
147 NSArray* bubble_subviews = [[window_subviews lastObject] subviews]; | |
148 NSArray* security_section_subviews = | |
149 [[bubble_subviews firstObject] subviews]; | |
150 | |
151 /** | |
152 *Expect 3 views: | |
153 * - the identity | |
154 * - identity status | |
155 * - security details link | |
156 */ | |
157 EXPECT_EQ(3U, [security_section_subviews count]); | |
158 | |
159 bool desired_result = match_type == TEXT_EQUAL; | |
160 for (NSView* view in security_section_subviews) { | |
161 if ([view isKindOfClass:[NSTextField class]]) { | |
162 NSTextField* text_field = static_cast<NSTextField*>(view); | |
163 if ([[text_field stringValue] isEqual:text] == desired_result) | |
164 return text_field; | |
165 } | |
166 } | |
167 return nil; | |
168 } | |
169 | |
170 NSMutableArray* FindAllSubviewsOfClass(NSView* parent_view, Class a_class) { | |
171 NSMutableArray* views = [NSMutableArray array]; | |
172 for (NSView* view in [parent_view subviews]) { | |
173 if ([view isKindOfClass:a_class]) | |
174 [views addObject:view]; | |
175 } | |
176 return views; | |
177 } | |
178 | |
179 // Sets up the dialog with some test permission settings. | |
180 void SetTestPermissions() { | |
181 // Create a list of 5 different permissions, corresponding to all the | |
182 // possible settings: | |
183 // - [allow, block, ask] by default | |
184 // - [block, allow] * [by user, by policy, by extension] | |
185 PermissionInfoList permission_info_list; | |
186 WebsiteSettingsUI::PermissionInfo info; | |
187 for (size_t i = 0; i < arraysize(kTestPermissionTypes); ++i) { | |
188 info.type = kTestPermissionTypes[i]; | |
189 info.setting = kTestSettings[i]; | |
190 if (info.setting == CONTENT_SETTING_DEFAULT) | |
191 info.default_setting = kTestDefaultSettings[i]; | |
192 info.source = kTestSettingSources[i]; | |
193 info.is_incognito = false; | |
194 permission_info_list.push_back(info); | |
195 } | |
196 ChosenObjectInfoList chosen_object_info_list; | |
197 bridge_->SetPermissionInfo(permission_info_list, | |
198 std::move(chosen_object_info_list)); | |
199 } | |
200 | |
201 content::TestBrowserThreadBundle thread_bundle_; | |
202 TestingProfile profile_; | |
203 content::TestWebContentsFactory web_contents_factory_; | |
204 | |
205 WebsiteSettingsBubbleControllerForTesting* controller_; // Weak, owns self. | |
206 NSWindow* window_; // Weak, owned by controller. | |
207 }; | |
208 | |
209 TEST_F(WebsiteSettingsBubbleControllerTest, ConnectionHelpButton) { | |
210 WebsiteSettingsUI::IdentityInfo info; | |
211 info.site_identity = std::string("example.com"); | |
212 info.identity_status = WebsiteSettings::SITE_IDENTITY_STATUS_UNKNOWN; | |
213 | |
214 CreateBubble(); | |
215 | |
216 bridge_->SetIdentityInfo(const_cast<WebsiteSettingsUI::IdentityInfo&>(info)); | |
217 | |
218 EXPECT_EQ([[controller_ connectionHelpButton] action], | |
219 @selector(openConnectionHelp:)); | |
220 } | |
221 | |
222 TEST_F(WebsiteSettingsBubbleControllerTest, ResetDecisionsButton) { | |
223 WebsiteSettingsUI::IdentityInfo info; | |
224 info.site_identity = std::string("example.com"); | |
225 info.identity_status = WebsiteSettings::SITE_IDENTITY_STATUS_UNKNOWN; | |
226 | |
227 CreateBubble(); | |
228 | |
229 // Set identity info, specifying that the button should not be shown. | |
230 info.show_ssl_decision_revoke_button = false; | |
231 bridge_->SetIdentityInfo(const_cast<WebsiteSettingsUI::IdentityInfo&>(info)); | |
232 EXPECT_EQ([controller_ resetDecisionsButton], nil); | |
233 | |
234 // Set identity info, specifying that the button should be shown. | |
235 info.certificate = net::X509Certificate::CreateFromBytes( | |
236 reinterpret_cast<const char*>(google_der), sizeof(google_der)); | |
237 info.show_ssl_decision_revoke_button = true; | |
238 bridge_->SetIdentityInfo(const_cast<WebsiteSettingsUI::IdentityInfo&>(info)); | |
239 EXPECT_NE([controller_ resetDecisionsButton], nil); | |
240 | |
241 // Check that clicking the button calls the right selector. | |
242 EXPECT_EQ([[controller_ resetDecisionsButton] action], | |
243 @selector(resetCertificateDecisions:)); | |
244 | |
245 // Since the bubble is only created once per identity, we only need to check | |
246 // the button is *added* when needed. So we don't check that it's removed | |
247 // when we set an identity with `show_ssl_decision_revoke_button == false` | |
248 // again. | |
249 } | |
250 | |
251 TEST_F(WebsiteSettingsBubbleControllerTest, SetPermissionInfo) { | |
252 CreateBubble(); | |
253 SetTestPermissions(); | |
254 | |
255 // There should be three subviews per permission. | |
256 NSArray* subviews = [[controller_ permissionsView] subviews]; | |
257 EXPECT_EQ(arraysize(kTestPermissionTypes) * 3 , [subviews count]); | |
258 | |
259 // Ensure that there is a distinct label for each permission. | |
260 NSMutableSet* labels = [NSMutableSet set]; | |
261 for (NSView* view in subviews) { | |
262 if ([view isKindOfClass:[NSTextField class]]) | |
263 [labels addObject:[static_cast<NSTextField*>(view) stringValue]]; | |
264 } | |
265 EXPECT_EQ(arraysize(kTestPermissionTypes), [labels count]); | |
266 | |
267 // Ensure that the button labels are distinct, and look for the correct | |
268 // number of disabled buttons. | |
269 int disabled_count = 0; | |
270 [labels removeAllObjects]; | |
271 for (NSView* view in subviews) { | |
272 if ([view isKindOfClass:[NSPopUpButton class]]) { | |
273 NSPopUpButton* button = static_cast<NSPopUpButton*>(view); | |
274 [labels addObject:[[button selectedCell] title]]; | |
275 | |
276 if (![button isEnabled]) | |
277 ++disabled_count; | |
278 } | |
279 } | |
280 EXPECT_EQ(arraysize(kTestPermissionTypes), [labels count]); | |
281 | |
282 // 3 of the buttons should be disabled -- the ones that have a setting source | |
283 // of SETTING_SOURCE_POLICY or SETTING_SOURCE_EXTENSION. | |
284 EXPECT_EQ(3, disabled_count); | |
285 } | |
286 | |
287 TEST_F(WebsiteSettingsBubbleControllerTest, WindowWidth) { | |
288 const CGFloat kBigEnoughBubbleWidth = 310; | |
289 // Creating a window that should fit everything. | |
290 CreateBubbleWithWidth(kBigEnoughBubbleWidth); | |
291 SetTestPermissions(); | |
292 | |
293 CGFloat window_width = NSWidth([[controller_ window] frame]); | |
294 | |
295 // Check the window was made bigger to fit the content. | |
296 EXPECT_EQ(kBigEnoughBubbleWidth, window_width); | |
297 | |
298 // Check that the window is wider than the right edge of all the permission | |
299 // popup buttons (LTR locales) or wider than the left edge (RTL locales). | |
300 bool is_rtl = base::i18n::IsRTL(); | |
301 for (NSView* view in [[controller_ permissionsView] subviews]) { | |
302 if (is_rtl) { | |
303 if ([view isKindOfClass:[NSPopUpButton class]]) { | |
304 NSPopUpButton* button = static_cast<NSPopUpButton*>(view); | |
305 EXPECT_GT(NSMinX([button frame]), 0); | |
306 } | |
307 if ([view isKindOfClass:[NSImageView class]]) { | |
308 NSImageView* icon = static_cast<NSImageView*>(view); | |
309 EXPECT_LT(NSMaxX([icon frame]), window_width); | |
310 } | |
311 } else { | |
312 if ([view isKindOfClass:[NSImageView class]]) { | |
313 NSImageView* icon = static_cast<NSImageView*>(view); | |
314 EXPECT_GT(NSMinX([icon frame]), 0); | |
315 } | |
316 if ([view isKindOfClass:[NSPopUpButton class]]) { | |
317 NSPopUpButton* button = static_cast<NSPopUpButton*>(view); | |
318 EXPECT_LT(NSMaxX([button frame]), window_width); | |
319 } | |
320 } | |
321 } | |
322 } | |
323 | |
324 } // namespace | |
OLD | NEW |