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.
5 #import <Cocoa/Cocoa.h>
7 #import "base/mac/scoped_nsobject.h"
8 #include "base/strings/sys_string_conversions.h"
9 #include "base/strings/utf_string_conversions.h"
10 #import "chrome/browser/extensions/extension_install_prompt.h"
11 #include "chrome/browser/ui/browser.h"
12 #include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
13 #import "chrome/browser/ui/cocoa/extensions/extension_install_prompt_test_utils.h"
14 #import "chrome/browser/ui/cocoa/extensions/extension_install_view_controller.h"
15 #include "extensions/common/extension.h"
16 #include "extensions/common/permissions/permission_message_provider.h"
17 #include "testing/gtest/include/gtest/gtest.h"
18 #import "testing/gtest_mac.h"
20 using extensions::CoalescedPermissionMessage;
21 using extensions::CoalescedPermissionMessages;
22 using extensions::Extension;
23 using extensions::PermissionIDSet;
25 // Base class for our tests.
26 class ExtensionInstallViewControllerTest : public CocoaProfileTest {
28 ExtensionInstallViewControllerTest() {
29 extension_ = chrome::LoadInstallPromptExtension();
33 scoped_refptr<extensions::Extension> extension_;
36 // Test that we can load the two kinds of prompts correctly, that the outlets
37 // are hooked up, and that the dialog calls cancel when cancel is pressed.
38 TEST_F(ExtensionInstallViewControllerTest, BasicsNormalCancel) {
39 chrome::MockExtensionInstallPromptDelegate delegate;
41 scoped_refptr<ExtensionInstallPrompt::Prompt> prompt =
42 chrome::BuildExtensionInstallPrompt(extension_.get());
43 ExtensionInstallPrompt::PermissionsType type =
44 ExtensionInstallPrompt::PermissionsType::REGULAR_PERMISSIONS;
46 CoalescedPermissionMessages permissions;
47 permissions.push_back(
48 CoalescedPermissionMessage(base::UTF8ToUTF16("warning 1"),
50 prompt->SetPermissions(permissions, type);
52 base::scoped_nsobject<ExtensionInstallViewController> controller(
53 [[ExtensionInstallViewController alloc] initWithProfile:profile()
58 [controller view]; // Force nib load.
60 // Test the right nib loaded.
61 EXPECT_NSEQ(@"ExtensionInstallPrompt", [controller nibName]);
63 // Check all the controls.
64 // Make sure everything is non-nil, and that the fields that are
65 // auto-translated don't start with a caret (that would indicate that they
66 // were not translated).
67 EXPECT_TRUE([controller iconView]);
68 EXPECT_TRUE([[controller iconView] image]);
70 EXPECT_TRUE([controller titleField]);
71 EXPECT_NE(0u, [[[controller titleField] stringValue] length]);
73 NSOutlineView* outlineView = [controller outlineView];
74 EXPECT_TRUE(outlineView);
75 EXPECT_EQ(2, [outlineView numberOfRows]);
76 EXPECT_NSEQ(base::SysUTF16ToNSString(prompt->GetPermission(0, type)),
77 [[outlineView dataSource] outlineView:outlineView
78 objectValueForTableColumn:nil
79 byItem:[outlineView itemAtRow:1]]);
81 EXPECT_TRUE([controller cancelButton]);
82 EXPECT_NE(0u, [[[controller cancelButton] stringValue] length]);
83 EXPECT_NE('^', [[[controller cancelButton] stringValue] characterAtIndex:0]);
85 EXPECT_TRUE([controller okButton]);
86 EXPECT_NE(0u, [[[controller okButton] stringValue] length]);
87 EXPECT_NE('^', [[[controller okButton] stringValue] characterAtIndex:0]);
89 // Test that cancel calls our delegate.
90 [controller cancel:nil];
91 EXPECT_EQ(1, delegate.abort_count());
92 EXPECT_EQ(0, delegate.proceed_count());
95 TEST_F(ExtensionInstallViewControllerTest, BasicsNormalOK) {
96 chrome::MockExtensionInstallPromptDelegate delegate;
98 scoped_refptr<ExtensionInstallPrompt::Prompt> prompt =
99 chrome::BuildExtensionInstallPrompt(extension_.get());
100 ExtensionInstallPrompt::PermissionsType type =
101 ExtensionInstallPrompt::PermissionsType::REGULAR_PERMISSIONS;
103 CoalescedPermissionMessages permissions;
104 permissions.push_back(
105 CoalescedPermissionMessage(base::UTF8ToUTF16("warning 1"),
107 prompt->SetPermissions(permissions, type);
109 base::scoped_nsobject<ExtensionInstallViewController> controller(
110 [[ExtensionInstallViewController alloc] initWithProfile:profile()
115 [controller view]; // Force nib load.
118 EXPECT_EQ(0, delegate.abort_count());
119 EXPECT_EQ(1, delegate.proceed_count());
122 // Test that controls get repositioned when there are two warnings vs one
124 TEST_F(ExtensionInstallViewControllerTest, MultipleWarnings) {
125 chrome::MockExtensionInstallPromptDelegate delegate1;
126 chrome::MockExtensionInstallPromptDelegate delegate2;
128 scoped_refptr<ExtensionInstallPrompt::Prompt> one_warning_prompt =
129 chrome::BuildExtensionInstallPrompt(extension_.get());
130 ExtensionInstallPrompt::PermissionsType type =
131 ExtensionInstallPrompt::PermissionsType::REGULAR_PERMISSIONS;
133 CoalescedPermissionMessages permissions;
134 permissions.push_back(
135 CoalescedPermissionMessage(base::UTF8ToUTF16("warning 1"),
137 one_warning_prompt->SetPermissions(permissions, type);
139 scoped_refptr<ExtensionInstallPrompt::Prompt> two_warnings_prompt =
140 chrome::BuildExtensionInstallPrompt(extension_.get());
141 permissions.push_back(
142 CoalescedPermissionMessage(base::UTF8ToUTF16("warning 2"),
144 two_warnings_prompt->SetPermissions(permissions, type);
146 base::scoped_nsobject<ExtensionInstallViewController> controller1(
147 [[ExtensionInstallViewController alloc]
148 initWithProfile:profile()
151 prompt:one_warning_prompt]);
153 [controller1 view]; // Force nib load.
155 base::scoped_nsobject<ExtensionInstallViewController> controller2(
156 [[ExtensionInstallViewController alloc]
157 initWithProfile:profile()
160 prompt:two_warnings_prompt]);
162 [controller2 view]; // Force nib load.
164 // Test control positioning. We don't test exact positioning because we don't
165 // want this to depend on string details and localization. But we do know the
166 // relative effect that adding a second warning should have on the layout.
167 ASSERT_LT([[controller1 view] frame].size.height,
168 [[controller2 view] frame].size.height);
170 ASSERT_LT([[controller1 view] frame].size.height,
171 [[controller2 view] frame].size.height);
174 // Test that we can load the skinny prompt correctly, and that the outlets are
176 TEST_F(ExtensionInstallViewControllerTest, BasicsSkinny) {
177 chrome::MockExtensionInstallPromptDelegate delegate;
179 // No warnings should trigger skinny prompt.
180 scoped_refptr<ExtensionInstallPrompt::Prompt> no_warnings_prompt =
181 chrome::BuildExtensionInstallPrompt(extension_.get());
183 base::scoped_nsobject<ExtensionInstallViewController> controller(
184 [[ExtensionInstallViewController alloc]
185 initWithProfile:profile()
188 prompt:no_warnings_prompt]);
190 [controller view]; // Force nib load.
192 // Test the right nib loaded.
193 EXPECT_NSEQ(@"ExtensionInstallPromptNoWarnings", [controller nibName]);
195 // Check all the controls.
196 // In the skinny prompt, only the icon, title and buttons are non-nill.
197 // Everything else is nil.
198 EXPECT_TRUE([controller iconView]);
199 EXPECT_TRUE([[controller iconView] image]);
201 EXPECT_TRUE([controller titleField]);
202 EXPECT_NE(0u, [[[controller titleField] stringValue] length]);
204 EXPECT_TRUE([controller cancelButton]);
205 EXPECT_NE(0u, [[[controller cancelButton] stringValue] length]);
206 EXPECT_NE('^', [[[controller cancelButton] stringValue] characterAtIndex:0]);
208 EXPECT_TRUE([controller okButton]);
209 EXPECT_NE(0u, [[[controller okButton] stringValue] length]);
210 EXPECT_NE('^', [[[controller okButton] stringValue] characterAtIndex:0]);
212 EXPECT_FALSE([controller outlineView]);
216 // Test that we can load the inline prompt correctly, and that the outlets are
218 TEST_F(ExtensionInstallViewControllerTest, BasicsInline) {
219 chrome::MockExtensionInstallPromptDelegate delegate;
221 // No warnings should trigger skinny prompt.
222 scoped_refptr<ExtensionInstallPrompt::Prompt> inline_prompt =
223 new ExtensionInstallPrompt::Prompt(
224 ExtensionInstallPrompt::INLINE_INSTALL_PROMPT);
225 inline_prompt->SetWebstoreData("1,000", true, 3.5, 200);
226 inline_prompt->set_extension(extension_.get());
227 inline_prompt->set_icon(chrome::LoadInstallPromptIcon());
229 base::scoped_nsobject<ExtensionInstallViewController> controller(
230 [[ExtensionInstallViewController alloc] initWithProfile:profile()
233 prompt:inline_prompt]);
235 [controller view]; // Force nib load.
237 // Test the right nib loaded.
238 EXPECT_NSEQ(@"ExtensionInstallPromptWebstoreData", [controller nibName]);
240 // Check all the controls.
241 EXPECT_TRUE([controller iconView]);
242 EXPECT_TRUE([[controller iconView] image]);
244 EXPECT_TRUE([controller titleField]);
245 EXPECT_NE(0u, [[[controller titleField] stringValue] length]);
247 EXPECT_TRUE([controller cancelButton]);
248 EXPECT_NE(0u, [[[controller cancelButton] stringValue] length]);
249 EXPECT_NE('^', [[[controller cancelButton] stringValue] characterAtIndex:0]);
251 EXPECT_TRUE([controller okButton]);
252 EXPECT_NE(0u, [[[controller okButton] stringValue] length]);
253 EXPECT_NE('^', [[[controller okButton] stringValue] characterAtIndex:0]);
255 EXPECT_TRUE([controller ratingStars]);
256 EXPECT_EQ(5u, [[[controller ratingStars] subviews] count]);
258 EXPECT_TRUE([controller ratingCountField]);
259 EXPECT_NE(0u, [[[controller ratingCountField] stringValue] length]);
261 EXPECT_TRUE([controller userCountField]);
262 EXPECT_NE(0u, [[[controller userCountField] stringValue] length]);
264 EXPECT_TRUE([controller storeLinkButton]);
265 EXPECT_NE(0u, [[[controller storeLinkButton] stringValue] length]);
267 [[[controller storeLinkButton] stringValue] characterAtIndex:0]);
269 // Though we have no permissions warnings, these should still be hooked up,
271 EXPECT_TRUE([controller outlineView]);
272 EXPECT_TRUE([[[controller outlineView] enclosingScrollView] isHidden]);
273 EXPECT_TRUE([controller warningsSeparator]);
274 EXPECT_TRUE([[controller warningsSeparator] isHidden]);
277 TEST_F(ExtensionInstallViewControllerTest, PostInstallPermissionsPrompt) {
278 chrome::MockExtensionInstallPromptDelegate delegate;
280 scoped_refptr<ExtensionInstallPrompt::Prompt> prompt =
281 chrome::BuildExtensionPostInstallPermissionsPrompt(extension_.get());
282 ExtensionInstallPrompt::PermissionsType type =
283 ExtensionInstallPrompt::PermissionsType::REGULAR_PERMISSIONS;
285 CoalescedPermissionMessages permissions;
286 permissions.push_back(
287 CoalescedPermissionMessage(base::UTF8ToUTF16("warning 1"),
289 prompt->SetPermissions(permissions, type);
291 base::scoped_nsobject<ExtensionInstallViewController> controller(
292 [[ExtensionInstallViewController alloc] initWithProfile:profile()
297 [controller view]; // Force nib load.
299 EXPECT_TRUE([controller cancelButton]);
300 EXPECT_FALSE([controller okButton]);
302 [controller cancel:nil];
303 EXPECT_EQ(1, delegate.abort_count());
306 // Test that permission details show up.
307 TEST_F(ExtensionInstallViewControllerTest, PermissionsDetails) {
308 chrome::MockExtensionInstallPromptDelegate delegate;
310 scoped_refptr<ExtensionInstallPrompt::Prompt> prompt =
311 chrome::BuildExtensionInstallPrompt(extension_.get());
312 ExtensionInstallPrompt::PermissionsType type =
313 ExtensionInstallPrompt::PermissionsType::REGULAR_PERMISSIONS;
315 CoalescedPermissionMessages permissions;
316 permissions.push_back(CoalescedPermissionMessage(
317 base::UTF8ToUTF16("warning 1"),
319 std::vector<base::string16>(1, base::UTF8ToUTF16("Detail 1"))));
320 prompt->SetPermissions(permissions, type);
321 prompt->SetIsShowingDetails(
322 ExtensionInstallPrompt::PERMISSIONS_DETAILS, 0, true);
324 base::scoped_nsobject<ExtensionInstallViewController> controller(
325 [[ExtensionInstallViewController alloc] initWithProfile:profile()
330 [controller view]; // Force nib load.
332 NSOutlineView* outlineView = [controller outlineView];
333 EXPECT_TRUE(outlineView);
334 EXPECT_EQ(4, [outlineView numberOfRows]);
335 EXPECT_NSEQ(base::SysUTF16ToNSString(prompt->GetPermissionsDetails(0, type)),
336 [[outlineView dataSource] outlineView:outlineView
337 objectValueForTableColumn:nil
338 byItem:[outlineView itemAtRow:2]]);