Home | History | Annotate | Download | only in printing
      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