1 // Copyright (c) 2011 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 "base/memory/scoped_nsobject.h" 6 #include "base/string_util.h" 7 #include "base/string_number_conversions.h" 8 #include "base/sys_string_conversions.h" 9 #include "base/utf_string_conversions.h" 10 #include "chrome/browser/page_info_model.h" 11 #import "chrome/browser/ui/cocoa/hyperlink_button_cell.h" 12 #import "chrome/browser/ui/cocoa/page_info_bubble_controller.h" 13 #include "chrome/browser/ui/cocoa/browser_test_helper.h" 14 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h" 15 #include "grit/generated_resources.h" 16 #include "ui/base/l10n/l10n_util.h" 17 18 namespace { 19 20 class FakeModel : public PageInfoModel { 21 public: 22 FakeModel() : PageInfoModel() {} 23 24 void AddSection(SectionStateIcon icon_id, 25 const string16& headline, 26 const string16& description, 27 SectionInfoType type) { 28 sections_.push_back(SectionInfo( 29 icon_id, headline, description, type)); 30 } 31 }; 32 33 class FakeBridge : public PageInfoModel::PageInfoModelObserver { 34 public: 35 void ModelChanged() {} 36 }; 37 38 class PageInfoBubbleControllerTest : public CocoaTest { 39 public: 40 PageInfoBubbleControllerTest() { 41 controller_ = nil; 42 model_ = new FakeModel(); 43 } 44 45 virtual void TearDown() { 46 [controller_ close]; 47 CocoaTest::TearDown(); 48 } 49 50 void CreateBubble() { 51 // The controller cleans up after itself when the window closes. 52 controller_ = 53 [[PageInfoBubbleController alloc] initWithPageInfoModel:model_ 54 modelObserver:NULL 55 parentWindow:test_window()]; 56 window_ = [controller_ window]; 57 [controller_ showWindow:nil]; 58 } 59 60 // Checks the controller's window for the requisite subviews in the given 61 // numbers. 62 void CheckWindow(int text_count, 63 int image_count, 64 int spacer_count, 65 int button_count) { 66 // All windows have the help center link and a spacer for it. 67 int link_count = 1; 68 ++spacer_count; 69 70 // The window's only immediate child is an invisible view that has a flipped 71 // coordinate origin. It is into this that all views get placed. 72 NSArray* windowSubviews = [[window_ contentView] subviews]; 73 EXPECT_EQ(1U, [windowSubviews count]); 74 NSArray* subviews = [[windowSubviews lastObject] subviews]; 75 76 for (NSView* view in subviews) { 77 if ([view isKindOfClass:[NSTextField class]]) { 78 --text_count; 79 } else if ([view isKindOfClass:[NSImageView class]]) { 80 --image_count; 81 } else if ([view isKindOfClass:[NSBox class]]) { 82 --spacer_count; 83 } else if ([view isKindOfClass:[NSButton class]]) { 84 NSButton* button = static_cast<NSButton*>(view); 85 // Every window should have a single link button to the help page. 86 if ([[button cell] isKindOfClass:[HyperlinkButtonCell class]]) { 87 --link_count; 88 CheckButton(button, @selector(showHelpPage:)); 89 } else { 90 --button_count; 91 CheckButton(button, @selector(showCertWindow:)); 92 } 93 } else { 94 ADD_FAILURE() << "Unknown subview: " << [[view description] UTF8String]; 95 } 96 } 97 EXPECT_EQ(0, text_count); 98 EXPECT_EQ(0, image_count); 99 EXPECT_EQ(0, spacer_count); 100 EXPECT_EQ(0, button_count); 101 EXPECT_EQ(0, link_count); 102 EXPECT_EQ([window_ delegate], controller_); 103 } 104 105 // Checks that a button is hooked up correctly. 106 void CheckButton(NSButton* button, SEL action) { 107 EXPECT_EQ(action, [button action]); 108 EXPECT_EQ(controller_, [button target]); 109 EXPECT_TRUE([button stringValue]); 110 } 111 112 BrowserTestHelper helper_; 113 114 PageInfoBubbleController* controller_; // Weak, owns self. 115 FakeModel* model_; // Weak, owned by controller. 116 NSWindow* window_; // Weak, owned by controller. 117 }; 118 119 120 TEST_F(PageInfoBubbleControllerTest, NoHistoryNoSecurity) { 121 model_->AddSection(PageInfoModel::ICON_STATE_ERROR, 122 string16(), 123 l10n_util::GetStringUTF16(IDS_PAGE_INFO_SECURITY_TAB_UNKNOWN_PARTY), 124 PageInfoModel::SECTION_INFO_IDENTITY); 125 model_->AddSection(PageInfoModel::ICON_STATE_ERROR, 126 string16(), 127 l10n_util::GetStringFUTF16( 128 IDS_PAGE_INFO_SECURITY_TAB_NOT_ENCRYPTED_CONNECTION_TEXT, 129 ASCIIToUTF16("google.com")), 130 PageInfoModel::SECTION_INFO_CONNECTION); 131 132 CreateBubble(); 133 CheckWindow(/*text=*/2, /*image=*/2, /*spacer=*/1, /*button=*/0); 134 } 135 136 137 TEST_F(PageInfoBubbleControllerTest, HistoryNoSecurity) { 138 model_->AddSection(PageInfoModel::ICON_STATE_ERROR, 139 string16(), 140 l10n_util::GetStringUTF16(IDS_PAGE_INFO_SECURITY_TAB_UNKNOWN_PARTY), 141 PageInfoModel::SECTION_INFO_IDENTITY); 142 model_->AddSection(PageInfoModel::ICON_STATE_ERROR, 143 string16(), 144 l10n_util::GetStringFUTF16( 145 IDS_PAGE_INFO_SECURITY_TAB_NOT_ENCRYPTED_CONNECTION_TEXT, 146 ASCIIToUTF16("google.com")), 147 PageInfoModel::SECTION_INFO_CONNECTION); 148 149 // In practice, the history information comes later because it's queried 150 // asynchronously, so replicate the double-build here. 151 CreateBubble(); 152 153 model_->AddSection(PageInfoModel::ICON_STATE_ERROR, 154 l10n_util::GetStringUTF16(IDS_PAGE_INFO_SITE_INFO_TITLE), 155 l10n_util::GetStringUTF16( 156 IDS_PAGE_INFO_SECURITY_TAB_FIRST_VISITED_TODAY), 157 PageInfoModel::SECTION_INFO_FIRST_VISIT); 158 159 [controller_ performLayout]; 160 161 CheckWindow(/*text=*/4, /*image=*/3, /*spacer=*/2, /*button=*/0); 162 } 163 164 165 TEST_F(PageInfoBubbleControllerTest, NoHistoryMixedSecurity) { 166 model_->AddSection(PageInfoModel::ICON_STATE_OK, 167 string16(), 168 l10n_util::GetStringFUTF16( 169 IDS_PAGE_INFO_SECURITY_TAB_SECURE_IDENTITY, 170 ASCIIToUTF16("Goat Security Systems")), 171 PageInfoModel::SECTION_INFO_IDENTITY); 172 173 // This string is super long and the text should overflow the default clip 174 // region (kImageSize). 175 string16 description = l10n_util::GetStringFUTF16( 176 IDS_PAGE_INFO_SECURITY_TAB_ENCRYPTED_SENTENCE_LINK, 177 l10n_util::GetStringFUTF16( 178 IDS_PAGE_INFO_SECURITY_TAB_ENCRYPTED_CONNECTION_TEXT, 179 ASCIIToUTF16("chrome.google.com"), 180 base::IntToString16(1024)), 181 l10n_util::GetStringUTF16( 182 IDS_PAGE_INFO_SECURITY_TAB_ENCRYPTED_INSECURE_CONTENT_WARNING)); 183 184 model_->AddSection(PageInfoModel::ICON_STATE_OK, 185 string16(), 186 description, 187 PageInfoModel::SECTION_INFO_CONNECTION); 188 189 CreateBubble(); 190 [controller_ setCertID:1]; 191 [controller_ performLayout]; 192 193 CheckWindow(/*text=*/2, /*image=*/2, /*spacer=*/1, /*button=*/1); 194 195 // Look for the over-sized box. 196 NSString* targetDesc = base::SysUTF16ToNSString(description); 197 NSArray* subviews = [[window_ contentView] subviews]; 198 for (NSView* subview in subviews) { 199 if ([subview isKindOfClass:[NSTextField class]]) { 200 NSTextField* desc = static_cast<NSTextField*>(subview); 201 if ([[desc stringValue] isEqualToString:targetDesc]) { 202 // Typical box frame is ~55px, make sure this is extra large. 203 EXPECT_LT(75, NSHeight([desc frame])); 204 } 205 } 206 } 207 } 208 209 } // namespace 210