| OLD | NEW |
| (Empty) |
| 1 // Copyright 2015 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 #include "chrome/browser/ui/views/page_info/website_settings_popup_view.h" | |
| 6 | |
| 7 #include "base/macros.h" | |
| 8 #include "base/strings/utf_string_conversions.h" | |
| 9 #include "chrome/browser/ui/exclusive_access/exclusive_access_manager.h" | |
| 10 #include "chrome/browser/ui/views/page_info/chosen_object_row.h" | |
| 11 #include "chrome/browser/ui/views/page_info/permission_selector_row.h" | |
| 12 #include "chrome/browser/usb/usb_chooser_context.h" | |
| 13 #include "chrome/browser/usb/usb_chooser_context_factory.h" | |
| 14 #include "chrome/test/base/testing_profile.h" | |
| 15 #include "content/public/browser/ssl_status.h" | |
| 16 #include "content/public/test/test_browser_thread_bundle.h" | |
| 17 #include "content/public/test/test_web_contents_factory.h" | |
| 18 #include "device/base/mock_device_client.h" | |
| 19 #include "device/usb/mock_usb_device.h" | |
| 20 #include "device/usb/mock_usb_service.h" | |
| 21 #include "testing/gtest/include/gtest/gtest.h" | |
| 22 #include "ui/events/event_utils.h" | |
| 23 #include "ui/views/controls/button/menu_button.h" | |
| 24 #include "ui/views/controls/combobox/combobox.h" | |
| 25 #include "ui/views/controls/label.h" | |
| 26 #include "ui/views/test/scoped_views_test_helper.h" | |
| 27 | |
| 28 const char* kUrl = "http://www.example.com/index.html"; | |
| 29 | |
| 30 namespace test { | |
| 31 | |
| 32 class WebsiteSettingsPopupViewTestApi { | |
| 33 public: | |
| 34 WebsiteSettingsPopupViewTestApi(gfx::NativeView parent, | |
| 35 Profile* profile, | |
| 36 content::WebContents* web_contents) | |
| 37 : view_(nullptr), | |
| 38 parent_(parent), | |
| 39 profile_(profile), | |
| 40 web_contents_(web_contents) { | |
| 41 CreateView(); | |
| 42 } | |
| 43 | |
| 44 void CreateView() { | |
| 45 if (view_) | |
| 46 view_->GetWidget()->CloseNow(); | |
| 47 | |
| 48 security_state::SecurityInfo security_info; | |
| 49 views::View* anchor_view = nullptr; | |
| 50 view_ = | |
| 51 new WebsiteSettingsPopupView(anchor_view, parent_, profile_, | |
| 52 web_contents_, GURL(kUrl), security_info); | |
| 53 } | |
| 54 | |
| 55 WebsiteSettingsPopupView* view() { return view_; } | |
| 56 views::View* permissions_view() { return view_->permissions_view_; } | |
| 57 | |
| 58 PermissionSelectorRow* GetPermissionSelectorAt(int index) { | |
| 59 return view_->selector_rows_[index].get(); | |
| 60 } | |
| 61 | |
| 62 // Returns the permission label text of the |index|th permission selector row. | |
| 63 // This function returns an empty string if the permission selector row's | |
| 64 // |label_| element isn't actually a |views::Label|. | |
| 65 base::string16 GetPermissionLabelTextAt(int index) { | |
| 66 views::View* view = GetPermissionSelectorAt(index)->label_; | |
| 67 if (view->GetClassName() == views::Label::kViewClassName) | |
| 68 return static_cast<views::Label*>(view)->text(); | |
| 69 return base::string16(); | |
| 70 } | |
| 71 | |
| 72 base::string16 GetPermissionButtonTextAt(int index) { | |
| 73 views::View* view = GetPermissionSelectorAt(index)->button(); | |
| 74 if (view->GetClassName() == views::MenuButton::kViewClassName) { | |
| 75 return static_cast<views::MenuButton*>(view)->GetText(); | |
| 76 } else if (view->GetClassName() == views::Combobox::kViewClassName) { | |
| 77 views::Combobox* combobox = static_cast<views::Combobox*>(view); | |
| 78 return combobox->GetTextForRow(combobox->GetSelectedRow()); | |
| 79 } else { | |
| 80 NOTREACHED() << "Unknown class " << view->GetClassName(); | |
| 81 return base::string16(); | |
| 82 } | |
| 83 } | |
| 84 | |
| 85 // Simulates recreating the dialog with a new PermissionInfoList. | |
| 86 void SetPermissionInfo(const PermissionInfoList& list) { | |
| 87 for (const WebsiteSettingsPopupView::PermissionInfo& info : list) | |
| 88 view_->presenter_->OnSitePermissionChanged(info.type, info.setting); | |
| 89 CreateView(); | |
| 90 } | |
| 91 | |
| 92 private: | |
| 93 WebsiteSettingsPopupView* view_; // Weak. Owned by its Widget. | |
| 94 | |
| 95 // For recreating the view. | |
| 96 gfx::NativeView parent_; | |
| 97 Profile* profile_; | |
| 98 content::WebContents* web_contents_; | |
| 99 | |
| 100 DISALLOW_COPY_AND_ASSIGN(WebsiteSettingsPopupViewTestApi); | |
| 101 }; | |
| 102 | |
| 103 } // namespace test | |
| 104 | |
| 105 namespace { | |
| 106 | |
| 107 // Helper class that wraps a TestingProfile and a TestWebContents for a test | |
| 108 // harness. Inspired by RenderViewHostTestHarness, but doesn't use inheritance | |
| 109 // so the helper can be composed with other helpers in the test harness. | |
| 110 class ScopedWebContentsTestHelper { | |
| 111 public: | |
| 112 ScopedWebContentsTestHelper() { | |
| 113 web_contents_ = factory_.CreateWebContents(&profile_); | |
| 114 } | |
| 115 | |
| 116 Profile* profile() { return &profile_; } | |
| 117 content::WebContents* web_contents() { return web_contents_; } | |
| 118 | |
| 119 private: | |
| 120 content::TestBrowserThreadBundle thread_bundle_; | |
| 121 TestingProfile profile_; | |
| 122 content::TestWebContentsFactory factory_; | |
| 123 content::WebContents* web_contents_; // Weak. Owned by factory_. | |
| 124 | |
| 125 DISALLOW_COPY_AND_ASSIGN(ScopedWebContentsTestHelper); | |
| 126 }; | |
| 127 | |
| 128 class WebsiteSettingsPopupViewTest : public testing::Test { | |
| 129 public: | |
| 130 WebsiteSettingsPopupViewTest() {} | |
| 131 | |
| 132 // testing::Test: | |
| 133 void SetUp() override { | |
| 134 views::Widget::InitParams parent_params; | |
| 135 parent_params.context = views_helper_.GetContext(); | |
| 136 parent_window_ = new views::Widget(); | |
| 137 parent_window_->Init(parent_params); | |
| 138 | |
| 139 content::WebContents* web_contents = web_contents_helper_.web_contents(); | |
| 140 TabSpecificContentSettings::CreateForWebContents(web_contents); | |
| 141 api_.reset(new test::WebsiteSettingsPopupViewTestApi( | |
| 142 parent_window_->GetNativeView(), web_contents_helper_.profile(), | |
| 143 web_contents)); | |
| 144 } | |
| 145 | |
| 146 void TearDown() override { parent_window_->CloseNow(); } | |
| 147 | |
| 148 protected: | |
| 149 device::MockDeviceClient device_client_; | |
| 150 ScopedWebContentsTestHelper web_contents_helper_; | |
| 151 views::ScopedViewsTestHelper views_helper_; | |
| 152 | |
| 153 views::Widget* parent_window_ = nullptr; // Weak. Owned by the NativeWidget. | |
| 154 std::unique_ptr<test::WebsiteSettingsPopupViewTestApi> api_; | |
| 155 | |
| 156 private: | |
| 157 DISALLOW_COPY_AND_ASSIGN(WebsiteSettingsPopupViewTest); | |
| 158 }; | |
| 159 | |
| 160 } // namespace | |
| 161 | |
| 162 // TODO(ellyjones): re-enable this test for OSX. | |
| 163 // This test exercises PermissionSelectorRow in a way that it is not used in | |
| 164 // practice. In practice, every setting in PermissionSelectorRow starts off | |
| 165 // "set", so there is always one option checked in the resulting MenuModel. This | |
| 166 // test creates settings that are left at their defaults, leading to zero | |
| 167 // checked options, and checks that the text on the MenuButtons is right. Since | |
| 168 // the Comboboxes the MacViews version of this dialog uses don't have separate | |
| 169 // text, this test doesn't work. | |
| 170 #if defined(OS_MACOSX) | |
| 171 #define MAYBE_SetPermissionInfo DISABLED_SetPermissionInfo | |
| 172 #else | |
| 173 #define MAYBE_SetPermissionInfo SetPermissionInfo | |
| 174 #endif | |
| 175 | |
| 176 // Each permission selector row is like this: [icon] [label] [selector] | |
| 177 constexpr int kViewsPerPermissionRow = 3; | |
| 178 | |
| 179 // Test UI construction and reconstruction via | |
| 180 // WebsiteSettingsPopupView::SetPermissionInfo(). | |
| 181 TEST_F(WebsiteSettingsPopupViewTest, MAYBE_SetPermissionInfo) { | |
| 182 PermissionInfoList list(1); | |
| 183 list.back().type = CONTENT_SETTINGS_TYPE_GEOLOCATION; | |
| 184 list.back().source = content_settings::SETTING_SOURCE_USER; | |
| 185 list.back().is_incognito = false; | |
| 186 list.back().setting = CONTENT_SETTING_DEFAULT; | |
| 187 | |
| 188 const int kExpectedChildren = | |
| 189 kViewsPerPermissionRow * | |
| 190 (ExclusiveAccessManager::IsSimplifiedFullscreenUIEnabled() ? 11 : 13); | |
| 191 EXPECT_EQ(kExpectedChildren, api_->permissions_view()->child_count()); | |
| 192 | |
| 193 list.back().setting = CONTENT_SETTING_ALLOW; | |
| 194 api_->SetPermissionInfo(list); | |
| 195 EXPECT_EQ(kExpectedChildren, api_->permissions_view()->child_count()); | |
| 196 | |
| 197 PermissionSelectorRow* selector = api_->GetPermissionSelectorAt(0); | |
| 198 EXPECT_TRUE(selector); | |
| 199 | |
| 200 // Verify labels match the settings on the PermissionInfoList. | |
| 201 EXPECT_EQ(base::ASCIIToUTF16("Location"), api_->GetPermissionLabelTextAt(0)); | |
| 202 EXPECT_EQ(base::ASCIIToUTF16("Allow"), api_->GetPermissionButtonTextAt(0)); | |
| 203 | |
| 204 // Verify calling SetPermisisonInfo() directly updates the UI. | |
| 205 list.back().setting = CONTENT_SETTING_BLOCK; | |
| 206 api_->SetPermissionInfo(list); | |
| 207 EXPECT_EQ(base::ASCIIToUTF16("Block"), api_->GetPermissionButtonTextAt(0)); | |
| 208 | |
| 209 // Simulate a user selection via the UI. Note this will also cover logic in | |
| 210 // WebsiteSettings to update the pref. | |
| 211 list.back().setting = CONTENT_SETTING_ALLOW; | |
| 212 api_->GetPermissionSelectorAt(0)->PermissionChanged(list.back()); | |
| 213 EXPECT_EQ(kExpectedChildren, api_->permissions_view()->child_count()); | |
| 214 EXPECT_EQ(base::ASCIIToUTF16("Allow"), api_->GetPermissionButtonTextAt(0)); | |
| 215 | |
| 216 // Setting to the default via the UI should keep the button around. | |
| 217 list.back().setting = CONTENT_SETTING_ASK; | |
| 218 api_->GetPermissionSelectorAt(0)->PermissionChanged(list.back()); | |
| 219 EXPECT_EQ(kExpectedChildren, api_->permissions_view()->child_count()); | |
| 220 EXPECT_EQ(base::ASCIIToUTF16("Ask"), api_->GetPermissionButtonTextAt(0)); | |
| 221 | |
| 222 // However, since the setting is now default, recreating the dialog with those | |
| 223 // settings should omit the permission from the UI. | |
| 224 api_->SetPermissionInfo(list); | |
| 225 EXPECT_EQ(kExpectedChildren, api_->permissions_view()->child_count()); | |
| 226 } | |
| 227 | |
| 228 // Test UI construction and reconstruction with USB devices. | |
| 229 TEST_F(WebsiteSettingsPopupViewTest, SetPermissionInfoWithUsbDevice) { | |
| 230 const int kExpectedChildren = | |
| 231 kViewsPerPermissionRow * | |
| 232 (ExclusiveAccessManager::IsSimplifiedFullscreenUIEnabled() ? 11 : 13); | |
| 233 EXPECT_EQ(kExpectedChildren, api_->permissions_view()->child_count()); | |
| 234 | |
| 235 const GURL origin = GURL(kUrl).GetOrigin(); | |
| 236 scoped_refptr<device::UsbDevice> device = | |
| 237 new device::MockUsbDevice(0, 0, "Google", "Gizmo", "1234567890"); | |
| 238 device_client_.usb_service()->AddDevice(device); | |
| 239 UsbChooserContext* store = | |
| 240 UsbChooserContextFactory::GetForProfile(web_contents_helper_.profile()); | |
| 241 store->GrantDevicePermission(origin, origin, device->guid()); | |
| 242 | |
| 243 PermissionInfoList list; | |
| 244 api_->SetPermissionInfo(list); | |
| 245 EXPECT_EQ(kExpectedChildren + 1, api_->permissions_view()->child_count()); | |
| 246 | |
| 247 ChosenObjectRow* object_view = static_cast<ChosenObjectRow*>( | |
| 248 api_->permissions_view()->child_at(kExpectedChildren)); | |
| 249 EXPECT_EQ(3, object_view->child_count()); | |
| 250 | |
| 251 const int kLabelIndex = 1; | |
| 252 views::Label* label = | |
| 253 static_cast<views::Label*>(object_view->child_at(kLabelIndex)); | |
| 254 EXPECT_EQ(base::ASCIIToUTF16("Gizmo"), label->text()); | |
| 255 | |
| 256 const int kButtonIndex = 2; | |
| 257 views::Button* button = | |
| 258 static_cast<views::Button*>(object_view->child_at(kButtonIndex)); | |
| 259 | |
| 260 const ui::MouseEvent event(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), | |
| 261 ui::EventTimeForNow(), 0, 0); | |
| 262 views::ButtonListener* button_listener = | |
| 263 static_cast<views::ButtonListener*>(object_view); | |
| 264 button_listener->ButtonPressed(button, event); | |
| 265 api_->SetPermissionInfo(list); | |
| 266 EXPECT_EQ(kExpectedChildren, api_->permissions_view()->child_count()); | |
| 267 EXPECT_FALSE(store->HasDevicePermission(origin, origin, device)); | |
| 268 } | |
| OLD | NEW |