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