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 29using testing::A; 30using testing::AtLeast; 31using testing::Eq; 32using testing::HasSubstr; 33using testing::IsNull; 34using testing::NotNull; 35using testing::Return; 36using testing::StrEq; 37using testing::_; 38 39static const char* const kPDFTestFile = "printing/cloud_print_unittest.pdf"; 40static const char* const kEmptyPDFTestFile = 41 "printing/cloud_print_emptytest.pdf"; 42static const char* const kMockJobTitle = "Mock Job Title"; 43 44FilePath 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 51FilePath 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 58char* 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 67MATCHER_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 78namespace internal_cloud_print_helpers { 79 80class 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 100class 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 122using internal_cloud_print_helpers::CloudPrintDataSenderHelper; 123using internal_cloud_print_helpers::CloudPrintDataSender; 124 125class MockExternalHtmlDialogUI : public ExternalHtmlDialogUI { 126 public: 127 MOCK_METHOD1(RenderViewCreated, 128 void(RenderViewHost* render_view_host)); 129}; 130 131class 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 145class 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 157TEST_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. 210class 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. 236TEST_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 251TEST_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 267TEST_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 286using internal_cloud_print_helpers::MockCloudPrintFlowHandler; 287using internal_cloud_print_helpers::CloudPrintHtmlDialogDelegate; 288 289class 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 320TEST_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 331TEST_F(CloudPrintHtmlDialogDelegateTest, OwnedFlowDestroyed) { 332 delegate_.reset(); 333 EXPECT_THAT(mock_flow_handler_.get(), IsNull()); 334} 335 336TEST_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