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