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::Extension;
21 using extensions::PermissionIDSet;
22 using extensions::PermissionMessage;
23 using extensions::PermissionMessages;
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 PermissionMessages permissions;
47 permissions.push_back(PermissionMessage(base::UTF8ToUTF16("warning 1"),
49 prompt->SetPermissions(permissions, type);
51 base::scoped_nsobject<ExtensionInstallViewController> controller(
52 [[ExtensionInstallViewController alloc] initWithProfile:profile()
57 [controller view]; // Force nib load.
59 // Test the right nib loaded.
60 EXPECT_NSEQ(@"ExtensionInstallPrompt", [controller nibName]);
62 // Check all the controls.
63 // Make sure everything is non-nil, and that the fields that are
64 // auto-translated don't start with a caret (that would indicate that they
65 // were not translated).
66 EXPECT_TRUE([controller iconView]);
67 EXPECT_TRUE([[controller iconView] image]);
69 EXPECT_TRUE([controller titleField]);
70 EXPECT_NE(0u, [[[controller titleField] stringValue] length]);
72 NSOutlineView* outlineView = [controller outlineView];
73 EXPECT_TRUE(outlineView);
74 EXPECT_EQ(2, [outlineView numberOfRows]);
75 EXPECT_NSEQ(base::SysUTF16ToNSString(prompt->GetPermission(0, type)),
76 [[outlineView dataSource] outlineView:outlineView
77 objectValueForTableColumn:nil
78 byItem:[outlineView itemAtRow:1]]);
80 EXPECT_TRUE([controller cancelButton]);
81 EXPECT_NE(0u, [[[controller cancelButton] stringValue] length]);
82 EXPECT_NE('^', [[[controller cancelButton] stringValue] characterAtIndex:0]);
84 EXPECT_TRUE([controller okButton]);
85 EXPECT_NE(0u, [[[controller okButton] stringValue] length]);
86 EXPECT_NE('^', [[[controller okButton] stringValue] characterAtIndex:0]);
88 // Test that cancel calls our delegate.
89 [controller cancel:nil];
90 EXPECT_EQ(1, delegate.abort_count());
91 EXPECT_EQ(0, delegate.proceed_count());
94 TEST_F(ExtensionInstallViewControllerTest, BasicsNormalOK) {
95 chrome::MockExtensionInstallPromptDelegate delegate;
97 scoped_refptr<ExtensionInstallPrompt::Prompt> prompt =
98 chrome::BuildExtensionInstallPrompt(extension_.get());
99 ExtensionInstallPrompt::PermissionsType type =
100 ExtensionInstallPrompt::PermissionsType::REGULAR_PERMISSIONS;
102 PermissionMessages permissions;
103 permissions.push_back(PermissionMessage(base::UTF8ToUTF16("warning 1"),
105 prompt->SetPermissions(permissions, type);
107 base::scoped_nsobject<ExtensionInstallViewController> controller(
108 [[ExtensionInstallViewController alloc] initWithProfile:profile()
113 [controller view]; // Force nib load.
116 EXPECT_EQ(0, delegate.abort_count());
117 EXPECT_EQ(1, delegate.proceed_count());
120 // Test that controls get repositioned when there are two warnings vs one
122 TEST_F(ExtensionInstallViewControllerTest, MultipleWarnings) {
123 chrome::MockExtensionInstallPromptDelegate delegate1;
124 chrome::MockExtensionInstallPromptDelegate delegate2;
126 scoped_refptr<ExtensionInstallPrompt::Prompt> one_warning_prompt =
127 chrome::BuildExtensionInstallPrompt(extension_.get());
128 ExtensionInstallPrompt::PermissionsType type =
129 ExtensionInstallPrompt::PermissionsType::REGULAR_PERMISSIONS;
131 PermissionMessages permissions;
132 permissions.push_back(PermissionMessage(base::UTF8ToUTF16("warning 1"),
134 one_warning_prompt->SetPermissions(permissions, type);
136 scoped_refptr<ExtensionInstallPrompt::Prompt> two_warnings_prompt =
137 chrome::BuildExtensionInstallPrompt(extension_.get());
138 permissions.push_back(PermissionMessage(base::UTF8ToUTF16("warning 2"),
140 two_warnings_prompt->SetPermissions(permissions, type);
142 base::scoped_nsobject<ExtensionInstallViewController> controller1(
143 [[ExtensionInstallViewController alloc]
144 initWithProfile:profile()
147 prompt:one_warning_prompt]);
149 [controller1 view]; // Force nib load.
151 base::scoped_nsobject<ExtensionInstallViewController> controller2(
152 [[ExtensionInstallViewController alloc]
153 initWithProfile:profile()
156 prompt:two_warnings_prompt]);
158 [controller2 view]; // Force nib load.
160 // Test control positioning. We don't test exact positioning because we don't
161 // want this to depend on string details and localization. But we do know the
162 // relative effect that adding a second warning should have on the layout.
163 ASSERT_LT([[controller1 view] frame].size.height,
164 [[controller2 view] frame].size.height);
166 ASSERT_LT([[controller1 view] frame].size.height,
167 [[controller2 view] frame].size.height);
170 // Test that we can load the skinny prompt correctly, and that the outlets are
172 TEST_F(ExtensionInstallViewControllerTest, BasicsSkinny) {
173 chrome::MockExtensionInstallPromptDelegate delegate;
175 // No warnings should trigger skinny prompt.
176 scoped_refptr<ExtensionInstallPrompt::Prompt> no_warnings_prompt =
177 chrome::BuildExtensionInstallPrompt(extension_.get());
179 base::scoped_nsobject<ExtensionInstallViewController> controller(
180 [[ExtensionInstallViewController alloc]
181 initWithProfile:profile()
184 prompt:no_warnings_prompt]);
186 [controller view]; // Force nib load.
188 // Test the right nib loaded.
189 EXPECT_NSEQ(@"ExtensionInstallPromptNoWarnings", [controller nibName]);
191 // Check all the controls.
192 // In the skinny prompt, only the icon, title and buttons are non-nill.
193 // Everything else is nil.
194 EXPECT_TRUE([controller iconView]);
195 EXPECT_TRUE([[controller iconView] image]);
197 EXPECT_TRUE([controller titleField]);
198 EXPECT_NE(0u, [[[controller titleField] stringValue] length]);
200 EXPECT_TRUE([controller cancelButton]);
201 EXPECT_NE(0u, [[[controller cancelButton] stringValue] length]);
202 EXPECT_NE('^', [[[controller cancelButton] stringValue] characterAtIndex:0]);
204 EXPECT_TRUE([controller okButton]);
205 EXPECT_NE(0u, [[[controller okButton] stringValue] length]);
206 EXPECT_NE('^', [[[controller okButton] stringValue] characterAtIndex:0]);
208 EXPECT_FALSE([controller outlineView]);
212 // Test that we can load the inline prompt correctly, and that the outlets are
214 TEST_F(ExtensionInstallViewControllerTest, BasicsInline) {
215 chrome::MockExtensionInstallPromptDelegate delegate;
217 // No warnings should trigger skinny prompt.
218 scoped_refptr<ExtensionInstallPrompt::Prompt> inline_prompt =
219 new ExtensionInstallPrompt::Prompt(
220 ExtensionInstallPrompt::INLINE_INSTALL_PROMPT);
221 inline_prompt->SetWebstoreData("1,000", true, 3.5, 200);
222 inline_prompt->set_extension(extension_.get());
223 inline_prompt->set_icon(chrome::LoadInstallPromptIcon());
225 base::scoped_nsobject<ExtensionInstallViewController> controller(
226 [[ExtensionInstallViewController alloc] initWithProfile:profile()
229 prompt:inline_prompt]);
231 [controller view]; // Force nib load.
233 // Test the right nib loaded.
234 EXPECT_NSEQ(@"ExtensionInstallPromptWebstoreData", [controller nibName]);
236 // Check all the controls.
237 EXPECT_TRUE([controller iconView]);
238 EXPECT_TRUE([[controller iconView] image]);
240 EXPECT_TRUE([controller titleField]);
241 EXPECT_NE(0u, [[[controller titleField] stringValue] length]);
243 EXPECT_TRUE([controller cancelButton]);
244 EXPECT_NE(0u, [[[controller cancelButton] stringValue] length]);
245 EXPECT_NE('^', [[[controller cancelButton] stringValue] characterAtIndex:0]);
247 EXPECT_TRUE([controller okButton]);
248 EXPECT_NE(0u, [[[controller okButton] stringValue] length]);
249 EXPECT_NE('^', [[[controller okButton] stringValue] characterAtIndex:0]);
251 EXPECT_TRUE([controller ratingStars]);
252 EXPECT_EQ(5u, [[[controller ratingStars] subviews] count]);
254 EXPECT_TRUE([controller ratingCountField]);
255 EXPECT_NE(0u, [[[controller ratingCountField] stringValue] length]);
257 EXPECT_TRUE([controller userCountField]);
258 EXPECT_NE(0u, [[[controller userCountField] stringValue] length]);
260 EXPECT_TRUE([controller storeLinkButton]);
261 EXPECT_NE(0u, [[[controller storeLinkButton] stringValue] length]);
263 [[[controller storeLinkButton] stringValue] characterAtIndex:0]);
265 // Though we have no permissions warnings, these should still be hooked up,
267 EXPECT_TRUE([controller outlineView]);
268 EXPECT_TRUE([[[controller outlineView] enclosingScrollView] isHidden]);
269 EXPECT_TRUE([controller warningsSeparator]);
270 EXPECT_TRUE([[controller warningsSeparator] isHidden]);
273 TEST_F(ExtensionInstallViewControllerTest, PostInstallPermissionsPrompt) {
274 chrome::MockExtensionInstallPromptDelegate delegate;
276 scoped_refptr<ExtensionInstallPrompt::Prompt> prompt =
277 chrome::BuildExtensionPostInstallPermissionsPrompt(extension_.get());
278 ExtensionInstallPrompt::PermissionsType type =
279 ExtensionInstallPrompt::PermissionsType::REGULAR_PERMISSIONS;
281 PermissionMessages permissions;
282 permissions.push_back(PermissionMessage(base::UTF8ToUTF16("warning 1"),
284 prompt->SetPermissions(permissions, type);
286 base::scoped_nsobject<ExtensionInstallViewController> controller(
287 [[ExtensionInstallViewController alloc] initWithProfile:profile()
292 [controller view]; // Force nib load.
294 EXPECT_TRUE([controller cancelButton]);
295 EXPECT_FALSE([controller okButton]);
297 [controller cancel:nil];
298 EXPECT_EQ(1, delegate.abort_count());
301 // Test that permission details show up.
302 TEST_F(ExtensionInstallViewControllerTest, PermissionsDetails) {
303 chrome::MockExtensionInstallPromptDelegate delegate;
305 scoped_refptr<ExtensionInstallPrompt::Prompt> prompt =
306 chrome::BuildExtensionInstallPrompt(extension_.get());
307 ExtensionInstallPrompt::PermissionsType type =
308 ExtensionInstallPrompt::PermissionsType::REGULAR_PERMISSIONS;
310 PermissionMessages permissions;
311 permissions.push_back(PermissionMessage(
312 base::UTF8ToUTF16("warning 1"),
314 std::vector<base::string16>(1, base::UTF8ToUTF16("Detail 1"))));
315 prompt->SetPermissions(permissions, type);
316 prompt->SetIsShowingDetails(
317 ExtensionInstallPrompt::PERMISSIONS_DETAILS, 0, true);
319 base::scoped_nsobject<ExtensionInstallViewController> controller(
320 [[ExtensionInstallViewController alloc] initWithProfile:profile()
325 [controller view]; // Force nib load.
327 NSOutlineView* outlineView = [controller outlineView];
328 EXPECT_TRUE(outlineView);
329 EXPECT_EQ(4, [outlineView numberOfRows]);
330 EXPECT_NSEQ(base::SysUTF16ToNSString(prompt->GetPermissionsDetails(0, type)),
331 [[outlineView dataSource] outlineView:outlineView
332 objectValueForTableColumn:nil
333 byItem:[outlineView itemAtRow:2]]);