| // Copyright 2015 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/ui/webui/print_preview/extension_printer_handler.h" |
| |
| #include <stddef.h> |
| #include <stdint.h> |
| |
| #include <memory> |
| #include <queue> |
| #include <string> |
| |
| #include "base/bind.h" |
| #include "base/files/file_util.h" |
| #include "base/files/scoped_temp_dir.h" |
| #include "base/json/json_string_value_serializer.h" |
| #include "base/macros.h" |
| #include "base/memory/ptr_util.h" |
| #include "base/run_loop.h" |
| #include "base/strings/string16.h" |
| #include "base/strings/stringprintf.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/test/values_test_util.h" |
| #include "base/threading/thread_task_runner_handle.h" |
| #include "base/values.h" |
| #include "chrome/browser/extensions/test_extension_environment.h" |
| #include "chrome/browser/printing/pwg_raster_converter.h" |
| #include "chrome/test/base/testing_profile.h" |
| #include "components/version_info/version_info.h" |
| #include "device/base/mock_device_client.h" |
| #include "device/usb/mock_usb_device.h" |
| #include "device/usb/mock_usb_service.h" |
| #include "extensions/browser/api/device_permissions_manager.h" |
| #include "extensions/browser/api/printer_provider/printer_provider_api.h" |
| #include "extensions/browser/api/printer_provider/printer_provider_api_factory.h" |
| #include "extensions/browser/api/printer_provider/printer_provider_print_job.h" |
| #include "extensions/common/extension.h" |
| #include "extensions/common/value_builder.h" |
| #include "printing/pdf_render_settings.h" |
| #include "printing/pwg_raster_settings.h" |
| #include "printing/units.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "ui/gfx/geometry/size.h" |
| |
| using device::MockUsbDevice; |
| using device::MockUsbService; |
| using extensions::DictionaryBuilder; |
| using extensions::Extension; |
| using extensions::PrinterProviderAPI; |
| using extensions::PrinterProviderPrintJob; |
| using extensions::TestExtensionEnvironment; |
| using printing::PWGRasterConverter; |
| |
| namespace { |
| |
| // Printer id used for requests in tests. |
| const char kPrinterId[] = "printer_id"; |
| |
| // Printer list used a result for getPrinters. |
| const char kPrinterDescriptionList[] = |
| "[{" |
| " \"id\": \"printer1\"," |
| " \"name\": \"Printer 1\"" |
| "}, {" |
| " \"id\": \"printer2\"," |
| " \"name\": \"Printer 2\"," |
| " \"description\": \"Test printer 2\"" |
| "}]"; |
| |
| // Printer capability for printer that supports all content types. |
| const char kAllContentTypesSupportedPrinter[] = |
| "{" |
| " \"version\": \"1.0\"," |
| " \"printer\": {" |
| " \"supported_content_type\": [" |
| " {\"content_type\": \"*/*\"}" |
| " ]" |
| " }" |
| "}"; |
| |
| // Printer capability for a printer that supports PDF. |
| const char kPdfSupportedPrinter[] = |
| "{" |
| " \"version\": \"1.0\"," |
| " \"printer\": {" |
| " \"supported_content_type\": [" |
| " {\"content_type\": \"application/pdf\"}," |
| " {\"content_type\": \"image/pwg-raster\"}" |
| " ]" |
| " }" |
| "}"; |
| |
| // Printer capability for a printer that supportd only PWG raster. |
| const char kPWGRasterOnlyPrinterSimpleDescription[] = |
| "{" |
| " \"version\": \"1.0\"," |
| " \"printer\": {" |
| " \"supported_content_type\": [" |
| " {\"content_type\": \"image/pwg-raster\"}" |
| " ]" |
| " }" |
| "}"; |
| |
| // Printer capability for a printer that supportd only PWG raster that has |
| // options other that supported_content_type set. |
| const char kPWGRasterOnlyPrinter[] = |
| "{" |
| " \"version\": \"1.0\"," |
| " \"printer\": {" |
| " \"supported_content_type\": [" |
| " {\"content_type\": \"image/pwg-raster\"}" |
| " ]," |
| " \"pwg_raster_config\": {" |
| " \"document_sheet_back\": \"FLIPPED\"," |
| " \"reverse_order_streaming\": true," |
| " \"rotate_all_pages\": true" |
| " }," |
| " \"dpi\": {" |
| " \"option\": [{" |
| " \"horizontal_dpi\": 100," |
| " \"vertical_dpi\": 200," |
| " \"is_default\": true" |
| " }]" |
| " }" |
| " }" |
| "}"; |
| |
| // Print ticket with no parameters set. |
| const char kEmptyPrintTicket[] = "{\"version\": \"1.0\"}"; |
| |
| // Print ticket that has duplex parameter set. |
| const char kPrintTicketWithDuplex[] = |
| "{" |
| " \"version\": \"1.0\"," |
| " \"print\": {" |
| " \"duplex\": {\"type\": \"LONG_EDGE\"}" |
| " }" |
| "}"; |
| |
| // An extension with permission for 1 printer it supports. |
| const char kExtension1[] = |
| "{" |
| " \"name\": \"Provider 1\"," |
| " \"app\": {" |
| " \"background\": {" |
| " \"scripts\": [\"background.js\"]" |
| " }" |
| " }," |
| " \"permissions\": [" |
| " \"printerProvider\"," |
| " \"usb\"," |
| " {" |
| " \"usbDevices\": [" |
| " { \"vendorId\": 0, \"productId\": 1 }" |
| " ]" |
| " }," |
| " ]," |
| " \"usb_printers\": {" |
| " \"filters\": [" |
| " { \"vendorId\": 0, \"productId\": 0 }," |
| " { \"vendorId\": 0, \"productId\": 1 }" |
| " ]" |
| " }" |
| "}"; |
| |
| // An extension with permission for none of the printers it supports. |
| const char kExtension2[] = |
| "{" |
| " \"name\": \"Provider 2\"," |
| " \"app\": {" |
| " \"background\": {" |
| " \"scripts\": [\"background.js\"]" |
| " }" |
| " }," |
| " \"permissions\": [ \"printerProvider\", \"usb\" ]," |
| " \"usb_printers\": {" |
| " \"filters\": [" |
| " { \"vendorId\": 0, \"productId\": 0 }," |
| " { \"vendorId\": 0, \"productId\": 1 }" |
| " ]" |
| " }" |
| "}"; |
| |
| const char kContentTypePDF[] = "application/pdf"; |
| const char kContentTypePWG[] = "image/pwg-raster"; |
| |
| // Print request status considered to be successful by fake PrinterProviderAPI. |
| const char kPrintRequestSuccess[] = "OK"; |
| |
| // Used as a callback to StartGetPrinters in tests. |
| // Increases |*call_count| and records values returned by StartGetPrinters. |
| void RecordPrinterList(size_t* call_count, |
| std::unique_ptr<base::ListValue>* printers_out, |
| bool* is_done_out, |
| const base::ListValue& printers, |
| bool is_done) { |
| ++(*call_count); |
| printers_out->reset(printers.DeepCopy()); |
| *is_done_out = is_done; |
| } |
| |
| // Used as a callback to StartGetCapability in tests. |
| // Increases |*call_count| and records values returned by StartGetCapability. |
| void RecordCapability(size_t* call_count, |
| std::string* destination_id_out, |
| std::unique_ptr<base::DictionaryValue>* capability_out, |
| const std::string& destination_id, |
| const base::DictionaryValue& capability) { |
| ++(*call_count); |
| *destination_id_out = destination_id; |
| capability_out->reset(capability.DeepCopy()); |
| } |
| |
| // Used as a callback to StartPrint in tests. |
| // Increases |*call_count| and records values returned by StartPrint. |
| void RecordPrintResult(size_t* call_count, |
| bool* success_out, |
| std::string* status_out, |
| bool success, |
| const std::string& status) { |
| ++(*call_count); |
| *success_out = success; |
| *status_out = status; |
| } |
| |
| // Used as a callback to StartGrantPrinterAccess in tests. |
| // Increases |*call_count| and records the value returned. |
| void RecordPrinterInfo(size_t* call_count, |
| std::unique_ptr<base::DictionaryValue>* printer_info_out, |
| const base::DictionaryValue& printer_info) { |
| ++(*call_count); |
| printer_info_out->reset(printer_info.DeepCopy()); |
| } |
| |
| // Converts JSON string to base::ListValue object. |
| // On failure, returns NULL and fills |*error| string. |
| std::unique_ptr<base::ListValue> GetJSONAsListValue(const std::string& json, |
| std::string* error) { |
| std::unique_ptr<base::Value> deserialized( |
| JSONStringValueDeserializer(json).Deserialize(NULL, error)); |
| if (!deserialized) |
| return std::unique_ptr<base::ListValue>(); |
| base::ListValue* list = nullptr; |
| if (!deserialized->GetAsList(&list)) { |
| *error = "Value is not a list."; |
| return std::unique_ptr<base::ListValue>(); |
| } |
| return std::unique_ptr<base::ListValue>(list->DeepCopy()); |
| } |
| |
| // Converts JSON string to base::DictionaryValue object. |
| // On failure, returns NULL and fills |*error| string. |
| std::unique_ptr<base::DictionaryValue> GetJSONAsDictionaryValue( |
| const std::string& json, |
| std::string* error) { |
| std::unique_ptr<base::Value> deserialized( |
| JSONStringValueDeserializer(json).Deserialize(NULL, error)); |
| if (!deserialized) |
| return std::unique_ptr<base::DictionaryValue>(); |
| base::DictionaryValue* dictionary; |
| if (!deserialized->GetAsDictionary(&dictionary)) { |
| *error = "Value is not a dictionary."; |
| return std::unique_ptr<base::DictionaryValue>(); |
| } |
| return std::unique_ptr<base::DictionaryValue>(dictionary->DeepCopy()); |
| } |
| |
| std::string RefCountedMemoryToString( |
| const scoped_refptr<base::RefCountedMemory>& memory) { |
| return std::string(memory->front_as<char>(), memory->size()); |
| } |
| |
| // Fake PWGRasterConverter used in the tests. |
| class FakePWGRasterConverter : public PWGRasterConverter { |
| public: |
| FakePWGRasterConverter() : fail_conversion_(false), initialized_(false) {} |
| ~FakePWGRasterConverter() override = default; |
| |
| // PWGRasterConverter implementation. It writes |data| to a temp file. |
| // Also, remembers conversion and bitmap settings passed into the method. |
| void Start(base::RefCountedMemory* data, |
| const printing::PdfRenderSettings& conversion_settings, |
| const printing::PwgRasterSettings& bitmap_settings, |
| const ResultCallback& callback) override { |
| if (fail_conversion_) { |
| callback.Run(false, base::FilePath()); |
| return; |
| } |
| |
| if (!initialized_ && !temp_dir_.CreateUniqueTempDir()) { |
| ADD_FAILURE() << "Unable to create target dir for cenverter"; |
| callback.Run(false, base::FilePath()); |
| return; |
| } |
| |
| initialized_ = true; |
| |
| path_ = temp_dir_.GetPath().AppendASCII("output.pwg"); |
| std::string data_str(data->front_as<char>(), data->size()); |
| int written = WriteFile(path_, data_str.c_str(), data_str.size()); |
| if (written != static_cast<int>(data_str.size())) { |
| ADD_FAILURE() << "Failed to write pwg raster file."; |
| callback.Run(false, base::FilePath()); |
| return; |
| } |
| |
| conversion_settings_ = conversion_settings; |
| bitmap_settings_ = bitmap_settings; |
| |
| callback.Run(true, path_); |
| } |
| |
| // Makes |Start| method always return an error. |
| void FailConversion() { fail_conversion_ = true; } |
| |
| const base::FilePath& path() { return path_; } |
| const printing::PdfRenderSettings& conversion_settings() const { |
| return conversion_settings_; |
| } |
| |
| const printing::PwgRasterSettings& bitmap_settings() const { |
| return bitmap_settings_; |
| } |
| |
| private: |
| base::ScopedTempDir temp_dir_; |
| |
| base::FilePath path_; |
| printing::PdfRenderSettings conversion_settings_; |
| printing::PwgRasterSettings bitmap_settings_; |
| bool fail_conversion_; |
| bool initialized_; |
| |
| DISALLOW_COPY_AND_ASSIGN(FakePWGRasterConverter); |
| }; |
| |
| // Information about received print requests. |
| struct PrintRequestInfo { |
| PrinterProviderAPI::PrintCallback callback; |
| PrinterProviderPrintJob job; |
| }; |
| |
| // Fake PrinterProviderAPI used in tests. |
| // It caches requests issued to API and exposes methods to trigger their |
| // callbacks. |
| class FakePrinterProviderAPI : public PrinterProviderAPI { |
| public: |
| FakePrinterProviderAPI() = default; |
| ~FakePrinterProviderAPI() override = default; |
| |
| void DispatchGetPrintersRequested( |
| const PrinterProviderAPI::GetPrintersCallback& callback) override { |
| pending_printers_callbacks_.push(callback); |
| } |
| |
| void DispatchGetCapabilityRequested( |
| const std::string& destination_id, |
| const PrinterProviderAPI::GetCapabilityCallback& callback) override { |
| pending_capability_callbacks_.push(callback); |
| } |
| |
| void DispatchPrintRequested( |
| const PrinterProviderPrintJob& job, |
| const PrinterProviderAPI::PrintCallback& callback) override { |
| PrintRequestInfo request_info; |
| request_info.callback = callback; |
| request_info.job = job; |
| |
| pending_print_requests_.push(request_info); |
| } |
| |
| void DispatchGetUsbPrinterInfoRequested( |
| const std::string& extension_id, |
| scoped_refptr<device::UsbDevice> device, |
| const PrinterProviderAPI::GetPrinterInfoCallback& callback) override { |
| EXPECT_EQ("fake extension id", extension_id); |
| EXPECT_TRUE(device); |
| pending_usb_info_callbacks_.push(callback); |
| } |
| |
| size_t pending_get_printers_count() const { |
| return pending_printers_callbacks_.size(); |
| } |
| |
| const PrinterProviderPrintJob* GetPrintJob( |
| const extensions::Extension* extension, |
| int request_id) const override { |
| ADD_FAILURE() << "Not reached"; |
| return nullptr; |
| } |
| |
| void TriggerNextGetPrintersCallback(const base::ListValue& printers, |
| bool done) { |
| ASSERT_GT(pending_get_printers_count(), 0u); |
| pending_printers_callbacks_.front().Run(printers, done); |
| pending_printers_callbacks_.pop(); |
| } |
| |
| size_t pending_get_capability_count() const { |
| return pending_capability_callbacks_.size(); |
| } |
| |
| void TriggerNextGetCapabilityCallback( |
| const base::DictionaryValue& description) { |
| ASSERT_GT(pending_get_capability_count(), 0u); |
| pending_capability_callbacks_.front().Run(description); |
| pending_capability_callbacks_.pop(); |
| } |
| |
| size_t pending_print_count() const { return pending_print_requests_.size(); } |
| |
| const PrinterProviderPrintJob* GetNextPendingPrintJob() const { |
| EXPECT_GT(pending_print_count(), 0u); |
| if (pending_print_count() == 0) |
| return NULL; |
| return &pending_print_requests_.front().job; |
| } |
| |
| void TriggerNextPrintCallback(const std::string& result) { |
| ASSERT_GT(pending_print_count(), 0u); |
| pending_print_requests_.front().callback.Run(result == kPrintRequestSuccess, |
| result); |
| pending_print_requests_.pop(); |
| } |
| |
| size_t pending_usb_info_count() const { |
| return pending_usb_info_callbacks_.size(); |
| } |
| |
| void TriggerNextUsbPrinterInfoCallback( |
| const base::DictionaryValue& printer_info) { |
| ASSERT_GT(pending_usb_info_count(), 0u); |
| pending_usb_info_callbacks_.front().Run(printer_info); |
| pending_usb_info_callbacks_.pop(); |
| } |
| |
| private: |
| std::queue<PrinterProviderAPI::GetPrintersCallback> |
| pending_printers_callbacks_; |
| std::queue<PrinterProviderAPI::GetCapabilityCallback> |
| pending_capability_callbacks_; |
| std::queue<PrintRequestInfo> pending_print_requests_; |
| std::queue<PrinterProviderAPI::GetPrinterInfoCallback> |
| pending_usb_info_callbacks_; |
| |
| DISALLOW_COPY_AND_ASSIGN(FakePrinterProviderAPI); |
| }; |
| |
| std::unique_ptr<KeyedService> BuildTestingPrinterProviderAPI( |
| content::BrowserContext* context) { |
| return base::MakeUnique<FakePrinterProviderAPI>(); |
| } |
| |
| } // namespace |
| |
| class ExtensionPrinterHandlerTest : public testing::Test { |
| public: |
| ExtensionPrinterHandlerTest() : pwg_raster_converter_(NULL) {} |
| ~ExtensionPrinterHandlerTest() override = default; |
| |
| void SetUp() override { |
| extensions::PrinterProviderAPIFactory::GetInstance()->SetTestingFactory( |
| env_.profile(), &BuildTestingPrinterProviderAPI); |
| extension_printer_handler_.reset(new ExtensionPrinterHandler( |
| env_.profile(), base::ThreadTaskRunnerHandle::Get())); |
| |
| pwg_raster_converter_ = new FakePWGRasterConverter(); |
| extension_printer_handler_->SetPWGRasterConverterForTesting( |
| std::unique_ptr<PWGRasterConverter>(pwg_raster_converter_)); |
| } |
| |
| protected: |
| FakePrinterProviderAPI* GetPrinterProviderAPI() { |
| return static_cast<FakePrinterProviderAPI*>( |
| extensions::PrinterProviderAPIFactory::GetInstance() |
| ->GetForBrowserContext(env_.profile())); |
| } |
| |
| device::MockUsbService& usb_service() { |
| return *device_client_.usb_service(); |
| } |
| |
| device::MockDeviceClient device_client_; |
| TestExtensionEnvironment env_; |
| std::unique_ptr<ExtensionPrinterHandler> extension_printer_handler_; |
| |
| FakePWGRasterConverter* pwg_raster_converter_; |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(ExtensionPrinterHandlerTest); |
| }; |
| |
| TEST_F(ExtensionPrinterHandlerTest, GetPrinters) { |
| size_t call_count = 0; |
| std::unique_ptr<base::ListValue> printers; |
| bool is_done = false; |
| |
| extension_printer_handler_->StartGetPrinters( |
| base::Bind(&RecordPrinterList, &call_count, &printers, &is_done)); |
| |
| EXPECT_FALSE(printers.get()); |
| FakePrinterProviderAPI* fake_api = GetPrinterProviderAPI(); |
| ASSERT_TRUE(fake_api); |
| ASSERT_EQ(1u, fake_api->pending_get_printers_count()); |
| |
| std::string error; |
| std::unique_ptr<base::ListValue> original_printers( |
| GetJSONAsListValue(kPrinterDescriptionList, &error)); |
| ASSERT_TRUE(original_printers) << "Failed to deserialize printers: " << error; |
| |
| fake_api->TriggerNextGetPrintersCallback(*original_printers, true); |
| |
| EXPECT_EQ(1u, call_count); |
| EXPECT_TRUE(is_done); |
| ASSERT_TRUE(printers.get()); |
| EXPECT_TRUE(printers->Equals(original_printers.get())) |
| << *printers << ", expected: " << *original_printers; |
| } |
| |
| TEST_F(ExtensionPrinterHandlerTest, GetPrinters_Reset) { |
| size_t call_count = 0; |
| std::unique_ptr<base::ListValue> printers; |
| bool is_done = false; |
| |
| extension_printer_handler_->StartGetPrinters( |
| base::Bind(&RecordPrinterList, &call_count, &printers, &is_done)); |
| |
| EXPECT_FALSE(printers.get()); |
| FakePrinterProviderAPI* fake_api = GetPrinterProviderAPI(); |
| ASSERT_TRUE(fake_api); |
| ASSERT_EQ(1u, fake_api->pending_get_printers_count()); |
| |
| extension_printer_handler_->Reset(); |
| |
| std::string error; |
| std::unique_ptr<base::ListValue> original_printers( |
| GetJSONAsListValue(kPrinterDescriptionList, &error)); |
| ASSERT_TRUE(original_printers) << "Error deserializing printers: " << error; |
| |
| fake_api->TriggerNextGetPrintersCallback(*original_printers, true); |
| |
| EXPECT_EQ(0u, call_count); |
| } |
| |
| TEST_F(ExtensionPrinterHandlerTest, GetUsbPrinters) { |
| scoped_refptr<MockUsbDevice> device0 = |
| new MockUsbDevice(0, 0, "Google", "USB Printer", ""); |
| usb_service().AddDevice(device0); |
| scoped_refptr<MockUsbDevice> device1 = |
| new MockUsbDevice(0, 1, "Google", "USB Printer", ""); |
| usb_service().AddDevice(device1); |
| |
| const Extension* extension_1 = env_.MakeExtension( |
| *base::test::ParseJson(kExtension1), "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); |
| const Extension* extension_2 = env_.MakeExtension( |
| *base::test::ParseJson(kExtension2), "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"); |
| |
| extensions::DevicePermissionsManager* permissions_manager = |
| extensions::DevicePermissionsManager::Get(env_.profile()); |
| permissions_manager->AllowUsbDevice(extension_2->id(), device0); |
| |
| size_t call_count = 0; |
| std::unique_ptr<base::ListValue> printers; |
| bool is_done = false; |
| extension_printer_handler_->StartGetPrinters( |
| base::Bind(&RecordPrinterList, &call_count, &printers, &is_done)); |
| |
| base::RunLoop().RunUntilIdle(); |
| |
| FakePrinterProviderAPI* fake_api = GetPrinterProviderAPI(); |
| ASSERT_TRUE(fake_api); |
| ASSERT_EQ(1u, fake_api->pending_get_printers_count()); |
| |
| EXPECT_EQ(1u, call_count); |
| EXPECT_FALSE(is_done); |
| EXPECT_TRUE(printers.get()); |
| EXPECT_EQ(2u, printers->GetSize()); |
| std::unique_ptr<base::DictionaryValue> extension_1_entry( |
| DictionaryBuilder() |
| .Set("id", base::StringPrintf("provisional-usb:%s:%s", |
| extension_1->id().c_str(), |
| device0->guid().c_str())) |
| .Set("name", "USB Printer") |
| .Set("extensionName", "Provider 1") |
| .Set("extensionId", extension_1->id()) |
| .Set("provisional", true) |
| .Build()); |
| std::unique_ptr<base::DictionaryValue> extension_2_entry( |
| DictionaryBuilder() |
| .Set("id", base::StringPrintf("provisional-usb:%s:%s", |
| extension_2->id().c_str(), |
| device1->guid().c_str())) |
| .Set("name", "USB Printer") |
| .Set("extensionName", "Provider 2") |
| .Set("extensionId", extension_2->id()) |
| .Set("provisional", true) |
| .Build()); |
| EXPECT_TRUE(printers->Find(*extension_1_entry) != printers->end()); |
| EXPECT_TRUE(printers->Find(*extension_2_entry) != printers->end()); |
| |
| fake_api->TriggerNextGetPrintersCallback(base::ListValue(), true); |
| |
| EXPECT_EQ(2u, call_count); |
| EXPECT_TRUE(is_done); |
| EXPECT_TRUE(printers.get()); |
| EXPECT_EQ(0u, printers->GetSize()); // RecordPrinterList resets |printers|. |
| } |
| |
| TEST_F(ExtensionPrinterHandlerTest, GetCapability) { |
| size_t call_count = 0; |
| std::string destination_id; |
| std::unique_ptr<base::DictionaryValue> capability; |
| |
| extension_printer_handler_->StartGetCapability( |
| kPrinterId, |
| base::Bind(&RecordCapability, &call_count, &destination_id, &capability)); |
| |
| EXPECT_EQ(0u, call_count); |
| |
| FakePrinterProviderAPI* fake_api = GetPrinterProviderAPI(); |
| ASSERT_TRUE(fake_api); |
| ASSERT_EQ(1u, fake_api->pending_get_capability_count()); |
| |
| std::string error; |
| std::unique_ptr<base::DictionaryValue> original_capability( |
| GetJSONAsDictionaryValue(kPWGRasterOnlyPrinterSimpleDescription, &error)); |
| ASSERT_TRUE(original_capability) |
| << "Error deserializing capability: " << error; |
| |
| fake_api->TriggerNextGetCapabilityCallback(*original_capability); |
| |
| EXPECT_EQ(1u, call_count); |
| EXPECT_EQ(kPrinterId, destination_id); |
| ASSERT_TRUE(capability.get()); |
| EXPECT_TRUE(capability->Equals(original_capability.get())) |
| << *capability << ", expected: " << *original_capability; |
| } |
| |
| TEST_F(ExtensionPrinterHandlerTest, GetCapability_Reset) { |
| size_t call_count = 0; |
| std::string destination_id; |
| std::unique_ptr<base::DictionaryValue> capability; |
| |
| extension_printer_handler_->StartGetCapability( |
| kPrinterId, |
| base::Bind(&RecordCapability, &call_count, &destination_id, &capability)); |
| |
| EXPECT_EQ(0u, call_count); |
| |
| FakePrinterProviderAPI* fake_api = GetPrinterProviderAPI(); |
| ASSERT_TRUE(fake_api); |
| ASSERT_EQ(1u, fake_api->pending_get_capability_count()); |
| |
| extension_printer_handler_->Reset(); |
| |
| std::string error; |
| std::unique_ptr<base::DictionaryValue> original_capability( |
| GetJSONAsDictionaryValue(kPWGRasterOnlyPrinterSimpleDescription, &error)); |
| ASSERT_TRUE(original_capability) |
| << "Error deserializing capability: " << error; |
| |
| fake_api->TriggerNextGetCapabilityCallback(*original_capability); |
| |
| EXPECT_EQ(0u, call_count); |
| } |
| |
| TEST_F(ExtensionPrinterHandlerTest, Print_Pdf) { |
| size_t call_count = 0; |
| bool success = false; |
| std::string status; |
| |
| scoped_refptr<base::RefCountedString> print_data( |
| new base::RefCountedString()); |
| print_data->data() = "print data, PDF"; |
| base::string16 title = base::ASCIIToUTF16("Title"); |
| |
| extension_printer_handler_->StartPrint( |
| kPrinterId, kPdfSupportedPrinter, title, kEmptyPrintTicket, |
| gfx::Size(100, 100), print_data, |
| base::Bind(&RecordPrintResult, &call_count, &success, &status)); |
| |
| EXPECT_EQ(0u, call_count); |
| FakePrinterProviderAPI* fake_api = GetPrinterProviderAPI(); |
| ASSERT_TRUE(fake_api); |
| ASSERT_EQ(1u, fake_api->pending_print_count()); |
| |
| const PrinterProviderPrintJob* print_job = fake_api->GetNextPendingPrintJob(); |
| ASSERT_TRUE(print_job); |
| |
| EXPECT_EQ(kPrinterId, print_job->printer_id); |
| EXPECT_EQ(title, print_job->job_title); |
| EXPECT_EQ(kEmptyPrintTicket, print_job->ticket_json); |
| EXPECT_EQ(kContentTypePDF, print_job->content_type); |
| EXPECT_TRUE(print_job->document_path.empty()); |
| ASSERT_TRUE(print_job->document_bytes); |
| EXPECT_EQ(print_data->data(), |
| RefCountedMemoryToString(print_job->document_bytes)); |
| |
| fake_api->TriggerNextPrintCallback(kPrintRequestSuccess); |
| |
| EXPECT_EQ(1u, call_count); |
| EXPECT_TRUE(success); |
| EXPECT_EQ(kPrintRequestSuccess, status); |
| } |
| |
| TEST_F(ExtensionPrinterHandlerTest, Print_Pdf_Reset) { |
| size_t call_count = 0; |
| bool success = false; |
| std::string status; |
| |
| scoped_refptr<base::RefCountedString> print_data( |
| new base::RefCountedString()); |
| print_data->data() = "print data, PDF"; |
| base::string16 title = base::ASCIIToUTF16("Title"); |
| |
| extension_printer_handler_->StartPrint( |
| kPrinterId, kPdfSupportedPrinter, title, kEmptyPrintTicket, |
| gfx::Size(100, 100), print_data, |
| base::Bind(&RecordPrintResult, &call_count, &success, &status)); |
| |
| EXPECT_EQ(0u, call_count); |
| FakePrinterProviderAPI* fake_api = GetPrinterProviderAPI(); |
| ASSERT_TRUE(fake_api); |
| ASSERT_EQ(1u, fake_api->pending_print_count()); |
| |
| extension_printer_handler_->Reset(); |
| |
| fake_api->TriggerNextPrintCallback(kPrintRequestSuccess); |
| |
| EXPECT_EQ(0u, call_count); |
| } |
| |
| TEST_F(ExtensionPrinterHandlerTest, Print_All) { |
| size_t call_count = 0; |
| bool success = false; |
| std::string status; |
| |
| scoped_refptr<base::RefCountedString> print_data( |
| new base::RefCountedString()); |
| print_data->data() = "print data, PDF"; |
| base::string16 title = base::ASCIIToUTF16("Title"); |
| |
| extension_printer_handler_->StartPrint( |
| kPrinterId, kAllContentTypesSupportedPrinter, title, kEmptyPrintTicket, |
| gfx::Size(100, 100), print_data, |
| base::Bind(&RecordPrintResult, &call_count, &success, &status)); |
| |
| EXPECT_EQ(0u, call_count); |
| |
| FakePrinterProviderAPI* fake_api = GetPrinterProviderAPI(); |
| ASSERT_TRUE(fake_api); |
| ASSERT_EQ(1u, fake_api->pending_print_count()); |
| |
| const PrinterProviderPrintJob* print_job = fake_api->GetNextPendingPrintJob(); |
| ASSERT_TRUE(print_job); |
| |
| EXPECT_EQ(kPrinterId, print_job->printer_id); |
| EXPECT_EQ(title, print_job->job_title); |
| EXPECT_EQ(kEmptyPrintTicket, print_job->ticket_json); |
| EXPECT_EQ(kContentTypePDF, print_job->content_type); |
| EXPECT_TRUE(print_job->document_path.empty()); |
| ASSERT_TRUE(print_job->document_bytes); |
| EXPECT_EQ(print_data->data(), |
| RefCountedMemoryToString(print_job->document_bytes)); |
| |
| fake_api->TriggerNextPrintCallback(kPrintRequestSuccess); |
| |
| EXPECT_EQ(1u, call_count); |
| EXPECT_TRUE(success); |
| EXPECT_EQ(kPrintRequestSuccess, status); |
| } |
| |
| TEST_F(ExtensionPrinterHandlerTest, Print_Pwg) { |
| size_t call_count = 0; |
| bool success = false; |
| std::string status; |
| |
| scoped_refptr<base::RefCountedString> print_data( |
| new base::RefCountedString()); |
| print_data->data() = "print data, PDF"; |
| base::string16 title = base::ASCIIToUTF16("Title"); |
| |
| extension_printer_handler_->StartPrint( |
| kPrinterId, kPWGRasterOnlyPrinterSimpleDescription, title, |
| kEmptyPrintTicket, gfx::Size(100, 50), print_data, |
| base::Bind(&RecordPrintResult, &call_count, &success, &status)); |
| |
| EXPECT_EQ(0u, call_count); |
| |
| base::RunLoop().RunUntilIdle(); |
| |
| FakePrinterProviderAPI* fake_api = GetPrinterProviderAPI(); |
| ASSERT_TRUE(fake_api); |
| ASSERT_EQ(1u, fake_api->pending_print_count()); |
| |
| EXPECT_EQ(printing::TRANSFORM_NORMAL, |
| pwg_raster_converter_->bitmap_settings().odd_page_transform); |
| EXPECT_FALSE(pwg_raster_converter_->bitmap_settings().rotate_all_pages); |
| EXPECT_FALSE(pwg_raster_converter_->bitmap_settings().reverse_page_order); |
| |
| EXPECT_EQ(printing::kDefaultPdfDpi, |
| pwg_raster_converter_->conversion_settings().dpi); |
| EXPECT_TRUE(pwg_raster_converter_->conversion_settings().autorotate); |
| EXPECT_EQ("0,0 208x416", // vertically_oriented_size * dpi / points_per_inch |
| pwg_raster_converter_->conversion_settings().area.ToString()); |
| |
| const PrinterProviderPrintJob* print_job = fake_api->GetNextPendingPrintJob(); |
| ASSERT_TRUE(print_job); |
| |
| EXPECT_EQ(kPrinterId, print_job->printer_id); |
| EXPECT_EQ(title, print_job->job_title); |
| EXPECT_EQ(kEmptyPrintTicket, print_job->ticket_json); |
| EXPECT_EQ(kContentTypePWG, print_job->content_type); |
| EXPECT_FALSE(print_job->document_bytes); |
| EXPECT_FALSE(print_job->document_path.empty()); |
| EXPECT_EQ(pwg_raster_converter_->path(), print_job->document_path); |
| EXPECT_EQ(static_cast<int64_t>(print_data->size()), |
| print_job->file_info.size); |
| |
| fake_api->TriggerNextPrintCallback(kPrintRequestSuccess); |
| |
| EXPECT_EQ(1u, call_count); |
| EXPECT_TRUE(success); |
| EXPECT_EQ(kPrintRequestSuccess, status); |
| } |
| |
| TEST_F(ExtensionPrinterHandlerTest, Print_Pwg_NonDefaultSettings) { |
| size_t call_count = 0; |
| bool success = false; |
| std::string status; |
| |
| scoped_refptr<base::RefCountedString> print_data( |
| new base::RefCountedString()); |
| print_data->data() = "print data, PDF"; |
| base::string16 title = base::ASCIIToUTF16("Title"); |
| |
| extension_printer_handler_->StartPrint( |
| kPrinterId, kPWGRasterOnlyPrinter, title, kPrintTicketWithDuplex, |
| gfx::Size(100, 50), print_data, |
| base::Bind(&RecordPrintResult, &call_count, &success, &status)); |
| |
| EXPECT_EQ(0u, call_count); |
| |
| base::RunLoop().RunUntilIdle(); |
| |
| FakePrinterProviderAPI* fake_api = GetPrinterProviderAPI(); |
| ASSERT_TRUE(fake_api); |
| ASSERT_EQ(1u, fake_api->pending_print_count()); |
| |
| EXPECT_EQ(printing::TRANSFORM_FLIP_VERTICAL, |
| pwg_raster_converter_->bitmap_settings().odd_page_transform); |
| EXPECT_TRUE(pwg_raster_converter_->bitmap_settings().rotate_all_pages); |
| EXPECT_TRUE(pwg_raster_converter_->bitmap_settings().reverse_page_order); |
| |
| EXPECT_EQ(200, // max(vertical_dpi, horizontal_dpi) |
| pwg_raster_converter_->conversion_settings().dpi); |
| EXPECT_TRUE(pwg_raster_converter_->conversion_settings().autorotate); |
| EXPECT_EQ("0,0 138x277", // vertically_oriented_size * dpi / points_per_inch |
| pwg_raster_converter_->conversion_settings().area.ToString()); |
| |
| const PrinterProviderPrintJob* print_job = fake_api->GetNextPendingPrintJob(); |
| ASSERT_TRUE(print_job); |
| |
| EXPECT_EQ(kPrinterId, print_job->printer_id); |
| EXPECT_EQ(title, print_job->job_title); |
| EXPECT_EQ(kPrintTicketWithDuplex, print_job->ticket_json); |
| EXPECT_EQ(kContentTypePWG, print_job->content_type); |
| EXPECT_FALSE(print_job->document_bytes); |
| EXPECT_FALSE(print_job->document_path.empty()); |
| EXPECT_EQ(pwg_raster_converter_->path(), print_job->document_path); |
| EXPECT_EQ(static_cast<int64_t>(print_data->size()), |
| print_job->file_info.size); |
| |
| fake_api->TriggerNextPrintCallback(kPrintRequestSuccess); |
| |
| EXPECT_EQ(1u, call_count); |
| EXPECT_TRUE(success); |
| EXPECT_EQ(kPrintRequestSuccess, status); |
| } |
| |
| TEST_F(ExtensionPrinterHandlerTest, Print_Pwg_Reset) { |
| size_t call_count = 0; |
| bool success = false; |
| std::string status; |
| |
| scoped_refptr<base::RefCountedString> print_data( |
| new base::RefCountedString()); |
| print_data->data() = "print data, PDF"; |
| base::string16 title = base::ASCIIToUTF16("Title"); |
| |
| extension_printer_handler_->StartPrint( |
| kPrinterId, kPWGRasterOnlyPrinterSimpleDescription, title, |
| kEmptyPrintTicket, gfx::Size(100, 50), print_data, |
| base::Bind(&RecordPrintResult, &call_count, &success, &status)); |
| |
| EXPECT_EQ(0u, call_count); |
| |
| base::RunLoop().RunUntilIdle(); |
| |
| FakePrinterProviderAPI* fake_api = GetPrinterProviderAPI(); |
| ASSERT_TRUE(fake_api); |
| ASSERT_EQ(1u, fake_api->pending_print_count()); |
| |
| extension_printer_handler_->Reset(); |
| |
| fake_api->TriggerNextPrintCallback(kPrintRequestSuccess); |
| |
| EXPECT_EQ(0u, call_count); |
| } |
| |
| TEST_F(ExtensionPrinterHandlerTest, Print_Pwg_InvalidTicket) { |
| size_t call_count = 0; |
| bool success = false; |
| std::string status; |
| |
| scoped_refptr<base::RefCountedString> print_data( |
| new base::RefCountedString()); |
| print_data->data() = "print data, PDF"; |
| base::string16 title = base::ASCIIToUTF16("Title"); |
| |
| extension_printer_handler_->StartPrint( |
| kPrinterId, kPWGRasterOnlyPrinterSimpleDescription, title, |
| "{}" /* ticket */, gfx::Size(100, 100), print_data, |
| base::Bind(&RecordPrintResult, &call_count, &success, &status)); |
| |
| EXPECT_EQ(1u, call_count); |
| |
| EXPECT_FALSE(success); |
| EXPECT_EQ("INVALID_TICKET", status); |
| } |
| |
| TEST_F(ExtensionPrinterHandlerTest, Print_Pwg_FailedConversion) { |
| size_t call_count = 0; |
| bool success = false; |
| std::string status; |
| |
| pwg_raster_converter_->FailConversion(); |
| |
| scoped_refptr<base::RefCountedString> print_data( |
| new base::RefCountedString()); |
| print_data->data() = "print data, PDF"; |
| base::string16 title = base::ASCIIToUTF16("Title"); |
| |
| extension_printer_handler_->StartPrint( |
| kPrinterId, kPWGRasterOnlyPrinterSimpleDescription, title, |
| kEmptyPrintTicket, gfx::Size(100, 100), print_data, |
| base::Bind(&RecordPrintResult, &call_count, &success, &status)); |
| |
| EXPECT_EQ(1u, call_count); |
| |
| EXPECT_FALSE(success); |
| EXPECT_EQ("INVALID_DATA", status); |
| } |
| |
| TEST_F(ExtensionPrinterHandlerTest, GrantUsbPrinterAccess) { |
| scoped_refptr<MockUsbDevice> device = |
| new MockUsbDevice(0, 0, "Google", "USB Printer", ""); |
| usb_service().AddDevice(device); |
| |
| size_t call_count = 0; |
| std::unique_ptr<base::DictionaryValue> printer_info; |
| |
| std::string printer_id = base::StringPrintf( |
| "provisional-usb:fake extension id:%s", device->guid().c_str()); |
| extension_printer_handler_->StartGrantPrinterAccess( |
| printer_id, base::Bind(&RecordPrinterInfo, &call_count, &printer_info)); |
| |
| EXPECT_FALSE(printer_info.get()); |
| FakePrinterProviderAPI* fake_api = GetPrinterProviderAPI(); |
| ASSERT_TRUE(fake_api); |
| ASSERT_EQ(1u, fake_api->pending_usb_info_count()); |
| |
| std::unique_ptr<base::DictionaryValue> original_printer_info( |
| DictionaryBuilder() |
| .Set("id", "printer1") |
| .Set("name", "Printer 1") |
| .Build()); |
| |
| fake_api->TriggerNextUsbPrinterInfoCallback(*original_printer_info); |
| |
| EXPECT_EQ(1u, call_count); |
| ASSERT_TRUE(printer_info.get()); |
| EXPECT_TRUE(printer_info->Equals(original_printer_info.get())) |
| << *printer_info << ", expected: " << *original_printer_info; |
| } |
| |
| TEST_F(ExtensionPrinterHandlerTest, GrantUsbPrinterAccess_Reset) { |
| scoped_refptr<MockUsbDevice> device = |
| new MockUsbDevice(0, 0, "Google", "USB Printer", ""); |
| usb_service().AddDevice(device); |
| |
| size_t call_count = 0; |
| std::unique_ptr<base::DictionaryValue> printer_info; |
| |
| extension_printer_handler_->StartGrantPrinterAccess( |
| base::StringPrintf("provisional-usb:fake extension id:%s", |
| device->guid().c_str()), |
| base::Bind(&RecordPrinterInfo, &call_count, &printer_info)); |
| |
| EXPECT_FALSE(printer_info.get()); |
| FakePrinterProviderAPI* fake_api = GetPrinterProviderAPI(); |
| ASSERT_TRUE(fake_api); |
| ASSERT_EQ(1u, fake_api->pending_usb_info_count()); |
| |
| extension_printer_handler_->Reset(); |
| |
| std::unique_ptr<base::DictionaryValue> original_printer_info( |
| DictionaryBuilder() |
| .Set("id", "printer1") |
| .Set("name", "Printer 1") |
| .Build()); |
| |
| fake_api->TriggerNextUsbPrinterInfoCallback(*original_printer_info); |
| |
| EXPECT_EQ(0u, call_count); |
| EXPECT_FALSE(printer_info.get()); |
| } |