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. 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/bind.h" 12#include "base/callback.h" 13#include "base/files/file_path.h" 14#include "base/files/file_util.h" 15#include "base/memory/weak_ptr.h" 16#include "base/message_loop/message_loop.h" 17#include "base/path_service.h" 18#include "base/strings/utf_string_conversions.h" 19#include "base/values.h" 20#include "chrome/common/chrome_paths.h" 21#include "chrome/common/url_constants.h" 22#include "components/cloud_devices/common/cloud_devices_urls.h" 23#include "content/public/browser/notification_details.h" 24#include "content/public/browser/notification_source.h" 25#include "content/public/browser/notification_types.h" 26#include "content/public/test/test_browser_thread.h" 27#include "testing/gmock/include/gmock/gmock.h" 28#include "testing/gtest/include/gtest/gtest.h" 29 30using content::BrowserThread; 31using content::WebContents; 32using content::WebUIMessageHandler; 33using testing::A; 34using testing::AtLeast; 35using testing::Eq; 36using testing::HasSubstr; 37using testing::IsNull; 38using testing::NotNull; 39using testing::Return; 40using testing::StrEq; 41using testing::_; 42using ui::ExternalWebDialogUI; 43 44const char kPDFTestFile[] = "printing/cloud_print_unittest.pdf"; 45const char kMockJobTitle[] = "Mock Job Title"; 46const char kMockPrintTicket[] = "Resolution=300"; 47 48 49base::FilePath GetTestDataFileName() { 50 base::FilePath test_data_directory; 51 PathService::Get(chrome::DIR_TEST_DATA, &test_data_directory); 52 base::FilePath test_file = test_data_directory.AppendASCII(kPDFTestFile); 53 return test_file; 54} 55 56char* GetTestData() { 57 static std::string sTestFileData; 58 if (sTestFileData.empty()) { 59 base::FilePath test_file = GetTestDataFileName(); 60 base::ReadFileToString(test_file, &sTestFileData); 61 } 62 return &sTestFileData[0]; 63} 64 65MATCHER_P(StringValueEq, expected, "StringValue") { 66 if (expected->Equals(&arg)) 67 return true; 68 std::string expected_string, arg_string; 69 expected->GetAsString(&expected_string); 70 arg.GetAsString(&arg_string); 71 *result_listener << "'" << arg_string 72 << "' (expected '" << expected_string << "')"; 73 return false; 74} 75 76namespace internal_cloud_print_helpers { 77 78class MockCloudPrintFlowHandler 79 : public CloudPrintFlowHandler, 80 public base::SupportsWeakPtr<MockCloudPrintFlowHandler> { 81 public: 82 MockCloudPrintFlowHandler(const base::string16& title, 83 const base::string16& print_ticket, 84 const std::string& file_type) 85 : CloudPrintFlowHandler(NULL, title, print_ticket, file_type) {} 86 MOCK_METHOD0(DestructorCalled, void()); 87 MOCK_METHOD0(RegisterMessages, void()); 88 MOCK_METHOD3(Observe, 89 void(int type, 90 const content::NotificationSource& source, 91 const content::NotificationDetails& details)); 92 MOCK_METHOD1(SetDialogDelegate, 93 void(CloudPrintWebDialogDelegate* delegate)); 94 MOCK_METHOD0(CreateCloudPrintDataSender, 95 scoped_refptr<CloudPrintDataSender>()); 96}; 97 98class MockCloudPrintWebDialogDelegate : public CloudPrintWebDialogDelegate { 99 public: 100 MOCK_CONST_METHOD0(GetDialogModalType, 101 ui::ModalType()); 102 MOCK_CONST_METHOD0(GetDialogTitle, 103 base::string16()); 104 MOCK_CONST_METHOD0(GetDialogContentURL, 105 GURL()); 106 MOCK_CONST_METHOD1(GetWebUIMessageHandlers, 107 void(std::vector<WebUIMessageHandler*>* handlers)); 108 MOCK_CONST_METHOD1(GetDialogSize, 109 void(gfx::Size* size)); 110 MOCK_CONST_METHOD0(GetDialogArgs, 111 std::string()); 112 MOCK_METHOD1(OnDialogClosed, 113 void(const std::string& json_retval)); 114 MOCK_METHOD2(OnCloseContents, 115 void(WebContents* source, bool *out_close_dialog)); 116}; 117 118} // namespace internal_cloud_print_helpers 119 120using internal_cloud_print_helpers::CloudPrintDataSenderHelper; 121using internal_cloud_print_helpers::CloudPrintDataSender; 122 123class MockExternalWebDialogUI : public ExternalWebDialogUI { 124 public: 125 MOCK_METHOD1(RenderViewCreated, 126 void(content::RenderViewHost* render_view_host)); 127}; 128 129class MockCloudPrintDataSenderHelper : public CloudPrintDataSenderHelper { 130 public: 131 // TODO(scottbyer): At some point this probably wants to use a 132 // MockTabContents instead of NULL, and to pre-load it with a bunch 133 // of expects/results. 134 MockCloudPrintDataSenderHelper() : CloudPrintDataSenderHelper(NULL) {} 135 MOCK_METHOD3(CallJavascriptFunction, void(const std::string&, 136 const base::Value& arg1, 137 const base::Value& arg2)); 138}; 139 140// Testing for CloudPrintDataSender needs a mock WebUI. 141class CloudPrintDataSenderTest : public testing::Test { 142 public: 143 CloudPrintDataSenderTest() 144 : file_thread_(BrowserThread::FILE, &message_loop_), 145 io_thread_(BrowserThread::IO, &message_loop_) {} 146 147 protected: 148 virtual void SetUp() { 149 mock_helper_.reset(new MockCloudPrintDataSenderHelper); 150 } 151 152 scoped_refptr<CloudPrintDataSender> CreateSender( 153 const base::RefCountedString* data) { 154 return new CloudPrintDataSender(mock_helper_.get(), 155 base::ASCIIToUTF16(kMockJobTitle), 156 base::ASCIIToUTF16(kMockPrintTicket), 157 std::string("application/pdf"), 158 data); 159 } 160 161 scoped_refptr<CloudPrintDataSender> print_data_sender_; 162 scoped_ptr<MockCloudPrintDataSenderHelper> mock_helper_; 163 164 base::MessageLoop message_loop_; 165 content::TestBrowserThread file_thread_; 166 content::TestBrowserThread io_thread_; 167}; 168 169TEST_F(CloudPrintDataSenderTest, CanSend) { 170 base::StringValue mock_job_title(kMockJobTitle); 171 EXPECT_CALL(*mock_helper_, 172 CallJavascriptFunction(_, _, StringValueEq(&mock_job_title))). 173 WillOnce(Return()); 174 175 std::string data("test_data"); 176 scoped_refptr<CloudPrintDataSender> print_data_sender( 177 CreateSender(base::RefCountedString::TakeString(&data))); 178 base::FilePath test_data_file_name = GetTestDataFileName(); 179 BrowserThread::PostTask( 180 BrowserThread::IO, FROM_HERE, 181 base::Bind(&CloudPrintDataSender::SendPrintData, print_data_sender)); 182 base::MessageLoop::current()->RunUntilIdle(); 183} 184 185TEST_F(CloudPrintDataSenderTest, NoData) { 186 EXPECT_CALL(*mock_helper_, CallJavascriptFunction(_, _, _)).Times(0); 187 188 scoped_refptr<CloudPrintDataSender> print_data_sender(CreateSender(NULL)); 189 base::FilePath test_data_file_name = GetTestDataFileName(); 190 BrowserThread::PostTask( 191 BrowserThread::IO, FROM_HERE, 192 base::Bind(&CloudPrintDataSender::SendPrintData, print_data_sender)); 193 base::MessageLoop::current()->RunUntilIdle(); 194} 195 196TEST_F(CloudPrintDataSenderTest, EmptyData) { 197 EXPECT_CALL(*mock_helper_, CallJavascriptFunction(_, _, _)).Times(0); 198 199 std::string data; 200 scoped_refptr<CloudPrintDataSender> print_data_sender( 201 CreateSender(base::RefCountedString::TakeString(&data))); 202 base::FilePath test_data_file_name = GetTestDataFileName(); 203 BrowserThread::PostTask( 204 BrowserThread::IO, FROM_HERE, 205 base::Bind(&CloudPrintDataSender::SendPrintData, print_data_sender)); 206 base::MessageLoop::current()->RunUntilIdle(); 207} 208 209// Testing for CloudPrintFlowHandler needs a mock 210// CloudPrintWebDialogDelegate, mock CloudPrintDataSender, and a mock 211// WebUI. 212 213// Testing for CloudPrintWebDialogDelegate needs a mock 214// CloudPrintFlowHandler. 215 216using internal_cloud_print_helpers::MockCloudPrintFlowHandler; 217using internal_cloud_print_helpers::CloudPrintWebDialogDelegate; 218 219class CloudPrintWebDialogDelegateTest : public testing::Test { 220 public: 221 CloudPrintWebDialogDelegateTest() 222 : ui_thread_(BrowserThread::UI, &message_loop_) {} 223 224 protected: 225 virtual void SetUp() { 226 base::string16 mock_title; 227 base::string16 mock_print_ticket; 228 std::string mock_file_type; 229 MockCloudPrintFlowHandler* handler = 230 new MockCloudPrintFlowHandler(mock_print_ticket, mock_title, 231 mock_file_type); 232 mock_flow_handler_ = handler->AsWeakPtr(); 233 EXPECT_CALL(*mock_flow_handler_.get(), SetDialogDelegate(_)); 234 EXPECT_CALL(*mock_flow_handler_.get(), SetDialogDelegate(NULL)); 235 delegate_.reset(new CloudPrintWebDialogDelegate(mock_flow_handler_.get(), 236 std::string())); 237 } 238 239 virtual void TearDown() { 240 delegate_.reset(); 241 if (mock_flow_handler_.get()) 242 delete mock_flow_handler_.get(); 243 } 244 245 base::MessageLoopForUI message_loop_; 246 content::TestBrowserThread ui_thread_; 247 base::WeakPtr<MockCloudPrintFlowHandler> mock_flow_handler_; 248 scoped_ptr<CloudPrintWebDialogDelegate> delegate_; 249}; 250 251TEST_F(CloudPrintWebDialogDelegateTest, BasicChecks) { 252 EXPECT_THAT(delegate_->GetDialogContentURL().spec(), 253 StrEq(chrome::kChromeUICloudPrintResourcesURL)); 254 EXPECT_TRUE(delegate_->GetDialogTitle().empty()); 255 256 bool close_dialog = false; 257 delegate_->OnCloseContents(NULL, &close_dialog); 258 EXPECT_TRUE(close_dialog); 259} 260 261TEST_F(CloudPrintWebDialogDelegateTest, OwnedFlowDestroyed) { 262 delegate_.reset(); 263 EXPECT_THAT(mock_flow_handler_.get(), IsNull()); 264} 265 266TEST_F(CloudPrintWebDialogDelegateTest, UnownedFlowLetGo) { 267 std::vector<WebUIMessageHandler*> handlers; 268 delegate_->GetWebUIMessageHandlers(&handlers); 269 delegate_.reset(); 270 EXPECT_THAT(mock_flow_handler_.get(), NotNull()); 271} 272 273// Testing for ExternalWebDialogUI needs a mock WebContents and mock 274// CloudPrintWebDialogDelegate (attached to the mock web_contents). 275 276// Testing for PrintDialogCloud needs a mock Browser. 277