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 "chrome/browser/printing/print_dialog_cloud.h" 6 #include "chrome/browser/printing/print_dialog_cloud_internal.h" 7 8 #include <string> 9 #include <vector> 10 11 #include "base/file_path.h" 12 #include "base/file_util.h" 13 #include "base/memory/weak_ptr.h" 14 #include "base/path_service.h" 15 #include "base/string_util.h" 16 #include "base/utf_string_conversions.h" 17 #include "base/values.h" 18 #include "chrome/browser/printing/cloud_print/cloud_print_url.h" 19 #include "chrome/common/chrome_paths.h" 20 #include "chrome/common/url_constants.h" 21 #include "chrome/test/testing_profile.h" 22 #include "content/browser/browser_thread.h" 23 #include "content/common/notification_details.h" 24 #include "content/common/notification_source.h" 25 #include "content/common/notification_type.h" 26 #include "testing/gmock/include/gmock/gmock.h" 27 #include "testing/gtest/include/gtest/gtest.h" 28 29 using testing::A; 30 using testing::AtLeast; 31 using testing::Eq; 32 using testing::HasSubstr; 33 using testing::IsNull; 34 using testing::NotNull; 35 using testing::Return; 36 using testing::StrEq; 37 using testing::_; 38 39 static const char* const kPDFTestFile = "printing/cloud_print_unittest.pdf"; 40 static const char* const kEmptyPDFTestFile = 41 "printing/cloud_print_emptytest.pdf"; 42 static const char* const kMockJobTitle = "Mock Job Title"; 43 44 FilePath GetTestDataFileName() { 45 FilePath test_data_directory; 46 PathService::Get(chrome::DIR_TEST_DATA, &test_data_directory); 47 FilePath test_file = test_data_directory.AppendASCII(kPDFTestFile); 48 return test_file; 49 } 50 51 FilePath GetEmptyDataFileName() { 52 FilePath test_data_directory; 53 PathService::Get(chrome::DIR_TEST_DATA, &test_data_directory); 54 FilePath test_file = test_data_directory.AppendASCII(kEmptyPDFTestFile); 55 return test_file; 56 } 57 58 char* GetTestData() { 59 static std::string sTestFileData; 60 if (sTestFileData.empty()) { 61 FilePath test_file = GetTestDataFileName(); 62 file_util::ReadFileToString(test_file, &sTestFileData); 63 } 64 return &sTestFileData[0]; 65 } 66 67 MATCHER_P(StringValueEq, expected, "StringValue") { 68 if (expected->Equals(&arg)) 69 return true; 70 std::string expected_string, arg_string; 71 expected->GetAsString(&expected_string); 72 arg.GetAsString(&arg_string); 73 *result_listener << "'" << arg_string 74 << "' (expected '" << expected_string << "')"; 75 return false; 76 } 77 78 namespace internal_cloud_print_helpers { 79 80 class MockCloudPrintFlowHandler 81 : public CloudPrintFlowHandler, 82 public base::SupportsWeakPtr<MockCloudPrintFlowHandler> { 83 public: 84 explicit MockCloudPrintFlowHandler(const FilePath& path, 85 const string16& title, 86 const std::string& file_type) 87 : CloudPrintFlowHandler(path, title, file_type) {} 88 MOCK_METHOD0(DestructorCalled, void()); 89 MOCK_METHOD0(RegisterMessages, void()); 90 MOCK_METHOD3(Observe, 91 void(NotificationType type, 92 const NotificationSource& source, 93 const NotificationDetails& details)); 94 MOCK_METHOD1(SetDialogDelegate, 95 void(CloudPrintHtmlDialogDelegate* delegate)); 96 MOCK_METHOD0(CreateCloudPrintDataSender, 97 scoped_refptr<CloudPrintDataSender>()); 98 }; 99 100 class MockCloudPrintHtmlDialogDelegate : public CloudPrintHtmlDialogDelegate { 101 public: 102 MOCK_CONST_METHOD0(IsDialogModal, 103 bool()); 104 MOCK_CONST_METHOD0(GetDialogTitle, 105 std::wstring()); 106 MOCK_CONST_METHOD0(GetDialogContentURL, 107 GURL()); 108 MOCK_CONST_METHOD1(GetWebUIMessageHandlers, 109 void(std::vector<WebUIMessageHandler*>* handlers)); 110 MOCK_CONST_METHOD1(GetDialogSize, 111 void(gfx::Size* size)); 112 MOCK_CONST_METHOD0(GetDialogArgs, 113 std::string()); 114 MOCK_METHOD1(OnDialogClosed, 115 void(const std::string& json_retval)); 116 MOCK_METHOD2(OnCloseContents, 117 void(TabContents* source, bool *out_close_dialog)); 118 }; 119 120 } // namespace internal_cloud_print_helpers 121 122 using internal_cloud_print_helpers::CloudPrintDataSenderHelper; 123 using internal_cloud_print_helpers::CloudPrintDataSender; 124 125 class MockExternalHtmlDialogUI : public ExternalHtmlDialogUI { 126 public: 127 MOCK_METHOD1(RenderViewCreated, 128 void(RenderViewHost* render_view_host)); 129 }; 130 131 class MockCloudPrintDataSenderHelper : public CloudPrintDataSenderHelper { 132 public: 133 // TODO(scottbyer): At some point this probably wants to use a 134 // MockTabContents instead of NULL, and to pre-load it with a bunch 135 // of expects/results. 136 MockCloudPrintDataSenderHelper() : CloudPrintDataSenderHelper(NULL) {} 137 MOCK_METHOD1(CallJavascriptFunction, void(const std::wstring&)); 138 MOCK_METHOD2(CallJavascriptFunction, void(const std::wstring&, 139 const Value& arg1)); 140 MOCK_METHOD3(CallJavascriptFunction, void(const std::wstring&, 141 const Value& arg1, 142 const Value& arg2)); 143 }; 144 145 class CloudPrintURLTest : public testing::Test { 146 public: 147 CloudPrintURLTest() {} 148 149 protected: 150 virtual void SetUp() { 151 profile_.reset(new TestingProfile()); 152 } 153 154 scoped_ptr<Profile> profile_; 155 }; 156 157 TEST_F(CloudPrintURLTest, CheckDefaultURLs) { 158 std::string service_url = 159 CloudPrintURL(profile_.get()). 160 GetCloudPrintServiceURL().spec(); 161 EXPECT_THAT(service_url, HasSubstr("www.google.com")); 162 EXPECT_THAT(service_url, HasSubstr("cloudprint")); 163 164 std::string dialog_url = 165 CloudPrintURL(profile_.get()). 166 GetCloudPrintServiceDialogURL().spec(); 167 EXPECT_THAT(dialog_url, HasSubstr("www.google.com")); 168 EXPECT_THAT(dialog_url, HasSubstr("/cloudprint/")); 169 EXPECT_THAT(dialog_url, HasSubstr("/client/")); 170 EXPECT_THAT(dialog_url, Not(HasSubstr("cloudprint/cloudprint"))); 171 EXPECT_THAT(dialog_url, HasSubstr("/dialog.html")); 172 173 // Repeat to make sure there isn't a transient glitch. 174 dialog_url = 175 CloudPrintURL(profile_.get()). 176 GetCloudPrintServiceDialogURL().spec(); 177 EXPECT_THAT(dialog_url, HasSubstr("www.google.com")); 178 EXPECT_THAT(dialog_url, HasSubstr("/cloudprint/")); 179 EXPECT_THAT(dialog_url, HasSubstr("/client/")); 180 EXPECT_THAT(dialog_url, Not(HasSubstr("cloudprint/cloudprint"))); 181 EXPECT_THAT(dialog_url, HasSubstr("/dialog.html")); 182 183 std::string manage_url = 184 CloudPrintURL(profile_.get()). 185 GetCloudPrintServiceManageURL().spec(); 186 EXPECT_THAT(manage_url, HasSubstr("www.google.com")); 187 EXPECT_THAT(manage_url, HasSubstr("/cloudprint/")); 188 EXPECT_THAT(manage_url, Not(HasSubstr("/client/"))); 189 EXPECT_THAT(manage_url, Not(HasSubstr("cloudprint/cloudprint"))); 190 EXPECT_THAT(manage_url, HasSubstr("/manage")); 191 192 GURL learn_more_url = CloudPrintURL::GetCloudPrintLearnMoreURL(); 193 std::string learn_more_path = learn_more_url.spec(); 194 EXPECT_THAT(learn_more_path, HasSubstr("www.google.com")); 195 EXPECT_THAT(learn_more_path, HasSubstr("/support/")); 196 EXPECT_THAT(learn_more_path, HasSubstr("/cloudprint")); 197 EXPECT_TRUE(learn_more_url.has_path()); 198 EXPECT_FALSE(learn_more_url.has_query()); 199 200 GURL test_page_url = CloudPrintURL::GetCloudPrintTestPageURL(); 201 std::string test_page_path = test_page_url.spec(); 202 EXPECT_THAT(test_page_path, HasSubstr("www.google.com")); 203 EXPECT_THAT(test_page_path, HasSubstr("/landing/")); 204 EXPECT_THAT(test_page_path, HasSubstr("/cloudprint/")); 205 EXPECT_TRUE(test_page_url.has_path()); 206 EXPECT_TRUE(test_page_url.has_query()); 207 } 208 209 // Testing for CloudPrintDataSender needs a mock WebUI. 210 class CloudPrintDataSenderTest : public testing::Test { 211 public: 212 CloudPrintDataSenderTest() 213 : file_thread_(BrowserThread::FILE, &message_loop_), 214 io_thread_(BrowserThread::IO, &message_loop_) {} 215 216 protected: 217 virtual void SetUp() { 218 string16 mock_job_title(ASCIIToUTF16(kMockJobTitle)); 219 mock_helper_.reset(new MockCloudPrintDataSenderHelper); 220 print_data_sender_ = 221 new CloudPrintDataSender(mock_helper_.get(), 222 mock_job_title, 223 std::string("application/pdf")); 224 } 225 226 scoped_refptr<CloudPrintDataSender> print_data_sender_; 227 scoped_ptr<MockCloudPrintDataSenderHelper> mock_helper_; 228 229 MessageLoop message_loop_; 230 BrowserThread file_thread_; 231 BrowserThread io_thread_; 232 }; 233 234 // TODO(scottbyer): DISABLED until the binary test file can get 235 // checked in separate from the patch. 236 TEST_F(CloudPrintDataSenderTest, CanSend) { 237 StringValue mock_job_title(kMockJobTitle); 238 EXPECT_CALL(*mock_helper_, 239 CallJavascriptFunction(_, _, StringValueEq(&mock_job_title))). 240 WillOnce(Return()); 241 242 FilePath test_data_file_name = GetTestDataFileName(); 243 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, 244 NewRunnableMethod( 245 print_data_sender_.get(), 246 &CloudPrintDataSender::ReadPrintDataFile, 247 test_data_file_name)); 248 MessageLoop::current()->RunAllPending(); 249 } 250 251 TEST_F(CloudPrintDataSenderTest, BadFile) { 252 EXPECT_CALL(*mock_helper_, CallJavascriptFunction(_, _, _)).Times(0); 253 254 #if defined(OS_WIN) 255 FilePath bad_data_file_name(L"/some/file/that/isnot/there"); 256 #else 257 FilePath bad_data_file_name("/some/file/that/isnot/there"); 258 #endif 259 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, 260 NewRunnableMethod( 261 print_data_sender_.get(), 262 &CloudPrintDataSender::ReadPrintDataFile, 263 bad_data_file_name)); 264 MessageLoop::current()->RunAllPending(); 265 } 266 267 TEST_F(CloudPrintDataSenderTest, EmptyFile) { 268 EXPECT_CALL(*mock_helper_, CallJavascriptFunction(_, _, _)).Times(0); 269 270 FilePath empty_data_file_name = GetEmptyDataFileName(); 271 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, 272 NewRunnableMethod( 273 print_data_sender_.get(), 274 &CloudPrintDataSender::ReadPrintDataFile, 275 empty_data_file_name)); 276 MessageLoop::current()->RunAllPending(); 277 } 278 279 // Testing for CloudPrintFlowHandler needs a mock 280 // CloudPrintHtmlDialogDelegate, mock CloudPrintDataSender, and a mock 281 // WebUI. 282 283 // Testing for CloudPrintHtmlDialogDelegate needs a mock 284 // CloudPrintFlowHandler. 285 286 using internal_cloud_print_helpers::MockCloudPrintFlowHandler; 287 using internal_cloud_print_helpers::CloudPrintHtmlDialogDelegate; 288 289 class CloudPrintHtmlDialogDelegateTest : public testing::Test { 290 public: 291 CloudPrintHtmlDialogDelegateTest() 292 : ui_thread_(BrowserThread::UI, &message_loop_) {} 293 294 protected: 295 virtual void SetUp() { 296 FilePath mock_path; 297 string16 mock_title; 298 std::string mock_file_type; 299 MockCloudPrintFlowHandler* handler = 300 new MockCloudPrintFlowHandler(mock_path, mock_title, mock_file_type); 301 mock_flow_handler_ = handler->AsWeakPtr(); 302 EXPECT_CALL(*mock_flow_handler_.get(), SetDialogDelegate(_)); 303 EXPECT_CALL(*mock_flow_handler_.get(), SetDialogDelegate(NULL)); 304 delegate_.reset(new CloudPrintHtmlDialogDelegate( 305 mock_flow_handler_.get(), 100, 100, std::string(), true)); 306 } 307 308 virtual void TearDown() { 309 delegate_.reset(); 310 if (mock_flow_handler_) 311 delete mock_flow_handler_.get(); 312 } 313 314 MessageLoopForUI message_loop_; 315 BrowserThread ui_thread_; 316 base::WeakPtr<MockCloudPrintFlowHandler> mock_flow_handler_; 317 scoped_ptr<CloudPrintHtmlDialogDelegate> delegate_; 318 }; 319 320 TEST_F(CloudPrintHtmlDialogDelegateTest, BasicChecks) { 321 EXPECT_TRUE(delegate_->IsDialogModal()); 322 EXPECT_THAT(delegate_->GetDialogContentURL().spec(), 323 StrEq(chrome::kCloudPrintResourcesURL)); 324 EXPECT_TRUE(delegate_->GetDialogTitle().empty()); 325 326 bool close_dialog = false; 327 delegate_->OnCloseContents(NULL, &close_dialog); 328 EXPECT_TRUE(close_dialog); 329 } 330 331 TEST_F(CloudPrintHtmlDialogDelegateTest, OwnedFlowDestroyed) { 332 delegate_.reset(); 333 EXPECT_THAT(mock_flow_handler_.get(), IsNull()); 334 } 335 336 TEST_F(CloudPrintHtmlDialogDelegateTest, UnownedFlowLetGo) { 337 std::vector<WebUIMessageHandler*> handlers; 338 delegate_->GetWebUIMessageHandlers(&handlers); 339 delegate_.reset(); 340 EXPECT_THAT(mock_flow_handler_.get(), NotNull()); 341 } 342 343 // Testing for ExternalHtmlDialogUI needs a mock TabContents, mock 344 // CloudPrintHtmlDialogDelegate (provided through the mock 345 // tab_contents) 346 347 // Testing for PrintDialogCloud needs a mock Browser. 348