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/file_util.h"
14 #include "base/files/file_path.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
30 using content::BrowserThread;
31 using content::WebContents;
32 using content::WebUIMessageHandler;
33 using testing::A;
34 using testing::AtLeast;
35 using testing::Eq;
36 using testing::HasSubstr;
37 using testing::IsNull;
38 using testing::NotNull;
39 using testing::Return;
40 using testing::StrEq;
41 using testing::_;
42 using ui::ExternalWebDialogUI;
43
44 const char kPDFTestFile[] = "printing/cloud_print_unittest.pdf";
45 const char kMockJobTitle[] = "Mock Job Title";
46 const char kMockPrintTicket[] = "Resolution=300";
47
48
GetTestDataFileName()49 base::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
GetTestData()56 char* 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
65 MATCHER_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
76 namespace internal_cloud_print_helpers {
77
78 class MockCloudPrintFlowHandler
79 : public CloudPrintFlowHandler,
80 public base::SupportsWeakPtr<MockCloudPrintFlowHandler> {
81 public:
MockCloudPrintFlowHandler(const base::string16 & title,const base::string16 & print_ticket,const std::string & file_type)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
98 class 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
120 using internal_cloud_print_helpers::CloudPrintDataSenderHelper;
121 using internal_cloud_print_helpers::CloudPrintDataSender;
122
123 class MockExternalWebDialogUI : public ExternalWebDialogUI {
124 public:
125 MOCK_METHOD1(RenderViewCreated,
126 void(content::RenderViewHost* render_view_host));
127 };
128
129 class 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.
MockCloudPrintDataSenderHelper()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.
141 class CloudPrintDataSenderTest : public testing::Test {
142 public:
CloudPrintDataSenderTest()143 CloudPrintDataSenderTest()
144 : file_thread_(BrowserThread::FILE, &message_loop_),
145 io_thread_(BrowserThread::IO, &message_loop_) {}
146
147 protected:
SetUp()148 virtual void SetUp() {
149 mock_helper_.reset(new MockCloudPrintDataSenderHelper);
150 }
151
CreateSender(const base::RefCountedString * data)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
TEST_F(CloudPrintDataSenderTest,CanSend)169 TEST_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
TEST_F(CloudPrintDataSenderTest,NoData)185 TEST_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
TEST_F(CloudPrintDataSenderTest,EmptyData)196 TEST_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
216 using internal_cloud_print_helpers::MockCloudPrintFlowHandler;
217 using internal_cloud_print_helpers::CloudPrintWebDialogDelegate;
218
219 class CloudPrintWebDialogDelegateTest : public testing::Test {
220 public:
CloudPrintWebDialogDelegateTest()221 CloudPrintWebDialogDelegateTest()
222 : ui_thread_(BrowserThread::UI, &message_loop_) {}
223
224 protected:
SetUp()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
TearDown()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
TEST_F(CloudPrintWebDialogDelegateTest,BasicChecks)251 TEST_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
TEST_F(CloudPrintWebDialogDelegateTest,OwnedFlowDestroyed)261 TEST_F(CloudPrintWebDialogDelegateTest, OwnedFlowDestroyed) {
262 delegate_.reset();
263 EXPECT_THAT(mock_flow_handler_.get(), IsNull());
264 }
265
TEST_F(CloudPrintWebDialogDelegateTest,UnownedFlowLetGo)266 TEST_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