Commit 5289cdfe authored by Hidehiko Abe's avatar Hidehiko Abe Committed by Commit Bot

Migrate LorgnetteManagerClient into DBusMethod.

BUG=739622
TEST=Ran trybots. Ran documentscan_AppTestWithFakeLorgnette on DUT.

Change-Id: I53358981be8b33e934ea5846391cad5fbc2af62b
Reviewed-on: https://chromium-review.googlesource.com/796491Reviewed-by: default avatarDan Erat <derat@chromium.org>
Reviewed-by: default avatarToni Barzic <tbarzic@chromium.org>
Commit-Queue: Hidehiko Abe <hidehiko@chromium.org>
Cr-Commit-Position: refs/heads/master@{#520856}
parent 34720eee
...@@ -21,33 +21,35 @@ FakeLorgnetteManagerClient::~FakeLorgnetteManagerClient() = default; ...@@ -21,33 +21,35 @@ FakeLorgnetteManagerClient::~FakeLorgnetteManagerClient() = default;
void FakeLorgnetteManagerClient::Init(dbus::Bus* bus) {} void FakeLorgnetteManagerClient::Init(dbus::Bus* bus) {}
void FakeLorgnetteManagerClient::ListScanners( void FakeLorgnetteManagerClient::ListScanners(
const ListScannersCallback& callback) { DBusMethodCallback<ScannerTable> callback) {
base::ThreadTaskRunnerHandle::Get()->PostTask( base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, FROM_HERE, base::BindOnce(std::move(callback),
base::BindOnce(callback, !scanner_table_.empty(), scanner_table_)); scanner_table_.empty()
? base::nullopt
: base::make_optional(scanner_table_)));
} }
void FakeLorgnetteManagerClient::ScanImageToString( void FakeLorgnetteManagerClient::ScanImageToString(
std::string device_name, std::string device_name,
const ScanProperties& properties, const ScanProperties& properties,
const ScanImageToStringCallback& callback) { DBusMethodCallback<std::string> callback) {
auto it = scan_data_.find( auto it = scan_data_.find(
std::make_tuple(device_name, properties.mode, properties.resolution_dpi)); std::make_tuple(device_name, properties.mode, properties.resolution_dpi));
auto task = it != scan_data_.end() auto data =
? base::BindOnce(callback, true, it->second) it == scan_data_.end() ? base::nullopt : base::make_optional(it->second);
: base::BindOnce(callback, false, std::string()); base::ThreadTaskRunnerHandle::Get()->PostTask(
base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, std::move(task)); FROM_HERE, base::BindOnce(std::move(callback), std::move(data)));
} }
void FakeLorgnetteManagerClient::AddScannerTableEntry( void FakeLorgnetteManagerClient::AddScannerTableEntry(
const std::string device_name, const std::string& device_name,
const ScannerTableEntry& entry) { const ScannerTableEntry& entry) {
scanner_table_[device_name] = entry; scanner_table_[device_name] = entry;
} }
void FakeLorgnetteManagerClient::AddScanData(const std::string& device_name, void FakeLorgnetteManagerClient::AddScanData(const std::string& device_name,
const ScanProperties& properties, const ScanProperties& properties,
const std::string data) { const std::string& data) {
scan_data_[std::make_tuple(device_name, properties.mode, scan_data_[std::make_tuple(device_name, properties.mode,
properties.resolution_dpi)] = data; properties.resolution_dpi)] = data;
} }
......
...@@ -24,21 +24,20 @@ class CHROMEOS_EXPORT FakeLorgnetteManagerClient ...@@ -24,21 +24,20 @@ class CHROMEOS_EXPORT FakeLorgnetteManagerClient
void Init(dbus::Bus* bus) override; void Init(dbus::Bus* bus) override;
void ListScanners(const ListScannersCallback& callback) override; void ListScanners(DBusMethodCallback<ScannerTable> callback) override;
void ScanImageToString( void ScanImageToString(std::string device_name,
std::string device_name, const ScanProperties& properties,
const ScanProperties& properties, DBusMethodCallback<std::string> callback) override;
const ScanImageToStringCallback& callback) override;
// Adds a fake scanner table entry, which will be returned by ListScanners(). // Adds a fake scanner table entry, which will be returned by ListScanners().
void AddScannerTableEntry(const std::string device_name, void AddScannerTableEntry(const std::string& device_name,
const ScannerTableEntry& entry); const ScannerTableEntry& entry);
// Adds a fake scan data, which will be returned by ScanImageToString(), // Adds a fake scan data, which will be returned by ScanImageToString(),
// if |device_name| and |properties| are matched. // if |device_name| and |properties| are matched.
void AddScanData(const std::string& device_name, void AddScanData(const std::string& device_name,
const ScanProperties& properties, const ScanProperties& properties,
const std::string data); const std::string& data);
private: private:
ScannerTable scanner_table_; ScannerTable scanner_table_;
......
...@@ -28,25 +28,22 @@ namespace chromeos { ...@@ -28,25 +28,22 @@ namespace chromeos {
// The LorgnetteManagerClient implementation used in production. // The LorgnetteManagerClient implementation used in production.
class LorgnetteManagerClientImpl : public LorgnetteManagerClient { class LorgnetteManagerClientImpl : public LorgnetteManagerClient {
public: public:
LorgnetteManagerClientImpl() : LorgnetteManagerClientImpl() = default;
lorgnette_daemon_proxy_(NULL), weak_ptr_factory_(this) {}
~LorgnetteManagerClientImpl() override = default; ~LorgnetteManagerClientImpl() override = default;
void ListScanners(const ListScannersCallback& callback) override { void ListScanners(DBusMethodCallback<ScannerTable> callback) override {
dbus::MethodCall method_call(lorgnette::kManagerServiceInterface, dbus::MethodCall method_call(lorgnette::kManagerServiceInterface,
lorgnette::kListScannersMethod); lorgnette::kListScannersMethod);
lorgnette_daemon_proxy_->CallMethod( lorgnette_daemon_proxy_->CallMethod(
&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
base::BindOnce(&LorgnetteManagerClientImpl::OnListScanners, base::BindOnce(&LorgnetteManagerClientImpl::OnListScanners,
weak_ptr_factory_.GetWeakPtr(), callback)); weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
} }
// LorgnetteManagerClient override. // LorgnetteManagerClient override.
void ScanImageToString( void ScanImageToString(std::string device_name,
std::string device_name, const ScanProperties& properties,
const ScanProperties& properties, DBusMethodCallback<std::string> callback) override {
const ScanImageToStringCallback& callback) override {
auto scan_data_reader = std::make_unique<ScanDataReader>(); auto scan_data_reader = std::make_unique<ScanDataReader>();
base::ScopedFD fd = scan_data_reader->Start(); base::ScopedFD fd = scan_data_reader->Start();
...@@ -57,8 +54,8 @@ class LorgnetteManagerClientImpl : public LorgnetteManagerClient { ...@@ -57,8 +54,8 @@ class LorgnetteManagerClientImpl : public LorgnetteManagerClient {
writer.AppendString(device_name); writer.AppendString(device_name);
writer.AppendFileDescriptor(fd.get()); writer.AppendFileDescriptor(fd.get());
dbus::MessageWriter option_writer(NULL); dbus::MessageWriter option_writer(nullptr);
dbus::MessageWriter element_writer(NULL); dbus::MessageWriter element_writer(nullptr);
writer.OpenArray("{sv}", &option_writer); writer.OpenArray("{sv}", &option_writer);
if (!properties.mode.empty()) { if (!properties.mode.empty()) {
option_writer.OpenDictEntry(&element_writer); option_writer.OpenDictEntry(&element_writer);
...@@ -77,7 +74,7 @@ class LorgnetteManagerClientImpl : public LorgnetteManagerClient { ...@@ -77,7 +74,7 @@ class LorgnetteManagerClientImpl : public LorgnetteManagerClient {
lorgnette_daemon_proxy_->CallMethod( lorgnette_daemon_proxy_->CallMethod(
&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
base::BindOnce(&LorgnetteManagerClientImpl::OnScanImageComplete, base::BindOnce(&LorgnetteManagerClientImpl::OnScanImageComplete,
weak_ptr_factory_.GetWeakPtr(), callback, weak_ptr_factory_.GetWeakPtr(), std::move(callback),
std::move(scan_data_reader))); std::move(scan_data_reader)));
} }
...@@ -97,7 +94,7 @@ class LorgnetteManagerClientImpl : public LorgnetteManagerClient { ...@@ -97,7 +94,7 @@ class LorgnetteManagerClientImpl : public LorgnetteManagerClient {
using CompletionCallback = using CompletionCallback =
base::OnceCallback<void(base::Optional<std::string> data)>; base::OnceCallback<void(base::Optional<std::string> data)>;
ScanDataReader() : weak_ptr_factory_(this) {} ScanDataReader() = default;
// Creates a pipe to read the scan data from the D-Bus service. // Creates a pipe to read the scan data from the D-Bus service.
// Returns a write-side FD. // Returns a write-side FD.
...@@ -150,86 +147,81 @@ class LorgnetteManagerClientImpl : public LorgnetteManagerClient { ...@@ -150,86 +147,81 @@ class LorgnetteManagerClientImpl : public LorgnetteManagerClient {
CompletionCallback callback_; CompletionCallback callback_;
base::WeakPtrFactory<ScanDataReader> weak_ptr_factory_; base::WeakPtrFactory<ScanDataReader> weak_ptr_factory_{this};
DISALLOW_COPY_AND_ASSIGN(ScanDataReader); DISALLOW_COPY_AND_ASSIGN(ScanDataReader);
}; };
// Called when ListScanners completes. // Called when ListScanners completes.
void OnListScanners(const ListScannersCallback& callback, void OnListScanners(DBusMethodCallback<ScannerTable> callback,
dbus::Response* response) { dbus::Response* response) {
ScannerTable scanners; dbus::MessageReader table_reader(nullptr);
dbus::MessageReader table_reader(NULL);
if (!response || !dbus::MessageReader(response).PopArray(&table_reader)) { if (!response || !dbus::MessageReader(response).PopArray(&table_reader)) {
callback.Run(false, scanners); std::move(callback).Run(base::nullopt);
return; return;
} }
bool decode_failure = false; ScannerTable scanners;
while (table_reader.HasMoreData()) { while (table_reader.HasMoreData()) {
std::string device_name; std::string device_name;
dbus::MessageReader device_entry_reader(NULL); dbus::MessageReader device_entry_reader(nullptr);
dbus::MessageReader device_element_reader(NULL); dbus::MessageReader device_element_reader(nullptr);
if (!table_reader.PopDictEntry(&device_entry_reader) || if (!table_reader.PopDictEntry(&device_entry_reader) ||
!device_entry_reader.PopString(&device_name) || !device_entry_reader.PopString(&device_name) ||
!device_entry_reader.PopArray(&device_element_reader)) { !device_entry_reader.PopArray(&device_element_reader)) {
decode_failure = true; LOG(ERROR) << "Failed to decode response from ListScanners";
break; std::move(callback).Run(base::nullopt);
return;
} }
ScannerTableEntry scanner_entry; ScannerTableEntry scanner_entry;
while (device_element_reader.HasMoreData()) { while (device_element_reader.HasMoreData()) {
dbus::MessageReader device_attribute_reader(NULL);
std::string attribute; std::string attribute;
std::string value; std::string value;
dbus::MessageReader device_attribute_reader(nullptr);
if (!device_element_reader.PopDictEntry(&device_attribute_reader) || if (!device_element_reader.PopDictEntry(&device_attribute_reader) ||
!device_attribute_reader.PopString(&attribute) || !device_attribute_reader.PopString(&attribute) ||
!device_attribute_reader.PopString(&value)) { !device_attribute_reader.PopString(&value)) {
decode_failure = true; LOG(ERROR) << "Failed to decode response from ListScanners";
break; std::move(callback).Run(base::nullopt);
return;
} }
scanner_entry[attribute] = value; scanner_entry.emplace(std::move(attribute), std::move(value));
} }
if (decode_failure) scanners.emplace(std::move(device_name), std::move(scanner_entry));
break;
scanners[device_name] = scanner_entry;
} }
if (decode_failure) { std::move(callback).Run(std::move(scanners));
LOG(ERROR) << "Failed to decode response from ListScanners";
callback.Run(false, scanners);
} else {
callback.Run(true, scanners);
}
} }
// Called when a response for ScanImage() is received. // Called when a response for ScanImage() is received.
void OnScanImageComplete(const ScanImageToStringCallback& callback, void OnScanImageComplete(DBusMethodCallback<std::string> callback,
std::unique_ptr<ScanDataReader> scan_data_reader, std::unique_ptr<ScanDataReader> scan_data_reader,
dbus::Response* response) { dbus::Response* response) {
if (!response) { if (!response) {
LOG(ERROR) << "Failed to scan image"; LOG(ERROR) << "Failed to scan image";
// Do not touch |scan_data_reader|, so that RAII deletes it and // Do not touch |scan_data_reader|, so that RAII deletes it and
// cancels the inflight operation. // cancels the inflight operation.
callback.Run(false, std::string()); std::move(callback).Run(base::nullopt);
return; return;
} }
auto* reader = scan_data_reader.get(); auto* reader = scan_data_reader.get();
reader->Wait(base::BindOnce( reader->Wait(
&LorgnetteManagerClientImpl::OnScanDataCompleted, base::BindOnce(&LorgnetteManagerClientImpl::OnScanDataCompleted,
weak_ptr_factory_.GetWeakPtr(), callback, std::move(scan_data_reader))); weak_ptr_factory_.GetWeakPtr(), std::move(callback),
std::move(scan_data_reader)));
} }
// Called when scan data read is completed. // Called when scan data read is completed.
void OnScanDataCompleted(const ScanImageToStringCallback& callback, // This is to maintain the lifetime of ScanDataReader instance.
void OnScanDataCompleted(DBusMethodCallback<std::string> callback,
std::unique_ptr<ScanDataReader> scan_data_reader, std::unique_ptr<ScanDataReader> scan_data_reader,
base::Optional<std::string> data) { base::Optional<std::string> data) {
callback.Run(data.has_value(), data.value_or(std::string())); std::move(callback).Run(std::move(data));
} }
dbus::ObjectProxy* lorgnette_daemon_proxy_; dbus::ObjectProxy* lorgnette_daemon_proxy_ = nullptr;
base::WeakPtrFactory<LorgnetteManagerClientImpl> weak_ptr_factory_; base::WeakPtrFactory<LorgnetteManagerClientImpl> weak_ptr_factory_{this};
DISALLOW_COPY_AND_ASSIGN(LorgnetteManagerClientImpl); DISALLOW_COPY_AND_ASSIGN(LorgnetteManagerClientImpl);
}; };
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "base/macros.h" #include "base/macros.h"
#include "chromeos/chromeos_export.h" #include "chromeos/chromeos_export.h"
#include "chromeos/dbus/dbus_client.h" #include "chromeos/dbus/dbus_client.h"
#include "chromeos/dbus/dbus_method_call_status.h"
namespace chromeos { namespace chromeos {
...@@ -20,20 +21,8 @@ namespace chromeos { ...@@ -20,20 +21,8 @@ namespace chromeos {
class CHROMEOS_EXPORT LorgnetteManagerClient : public DBusClient { class CHROMEOS_EXPORT LorgnetteManagerClient : public DBusClient {
public: public:
// The property information for each scanner retured by ListScanners. // The property information for each scanner retured by ListScanners.
typedef std::map<std::string, std::string> ScannerTableEntry; using ScannerTableEntry = std::map<std::string, std::string>;
typedef std::map<std::string, ScannerTableEntry> ScannerTable; using ScannerTable = std::map<std::string, ScannerTableEntry>;
// Callback type for ListScanners(). Returns a map which contains
// a ScannerTableEntry for each available scanner.
typedef base::Callback<void(
bool succeeded, const ScannerTable&)> ListScannersCallback;
// Called once ScanImageToString() is complete. Takes two parameters:
// - succeeded: was the scan completed successfully.
// - image_data: the contents of the image.
typedef base::Callback<void(
bool succeeded,
const std::string& image_data)> ScanImageToStringCallback;
// Attributes provided to a scan request. // Attributes provided to a scan request.
struct ScanProperties { struct ScanProperties {
...@@ -44,14 +33,14 @@ class CHROMEOS_EXPORT LorgnetteManagerClient : public DBusClient { ...@@ -44,14 +33,14 @@ class CHROMEOS_EXPORT LorgnetteManagerClient : public DBusClient {
~LorgnetteManagerClient() override; ~LorgnetteManagerClient() override;
// Gets a list of scanners from the lorgnette manager. // Gets a list of scanners from the lorgnette manager.
virtual void ListScanners(const ListScannersCallback& callback) = 0; virtual void ListScanners(DBusMethodCallback<ScannerTable> callback) = 0;
// Request a scanned image and calls |callback| when completed with a string // Request a scanned image and calls |callback| when completed with a string
// pointing at the scanned image data. Image data will be stored in the .png // pointing at the scanned image data. Image data will be stored in the .png
// format. // format.
virtual void ScanImageToString(std::string device_name, virtual void ScanImageToString(std::string device_name,
const ScanProperties& properties, const ScanProperties& properties,
const ScanImageToStringCallback& callback) = 0; DBusMethodCallback<std::string> callback) = 0;
// Factory function, creates a new instance and returns ownership. // Factory function, creates a new instance and returns ownership.
// For normal usage, access the singleton via DBusThreadManager::Get(). // For normal usage, access the singleton via DBusThreadManager::Get().
......
...@@ -14,9 +14,9 @@ ...@@ -14,9 +14,9 @@
namespace { namespace {
const char kImageScanFailedError[] = "Image scan failed"; constexpr char kImageScanFailedError[] = "Image scan failed";
const char kScannerImageMimeTypePng[] = "image/png"; constexpr char kScannerImageMimeTypePng[] = "image/png";
const char kPngImageDataUrlPrefix[] = "data:image/png;base64,"; constexpr char kPngImageDataUrlPrefix[] = "data:image/png;base64,";
chromeos::LorgnetteManagerClient* GetLorgnetteManagerClient() { chromeos::LorgnetteManagerClient* GetLorgnetteManagerClient() {
DCHECK(chromeos::DBusThreadManager::IsInitialized()); DCHECK(chromeos::DBusThreadManager::IsInitialized());
...@@ -36,33 +36,34 @@ DocumentScanInterfaceChromeos::~DocumentScanInterfaceChromeos() = default; ...@@ -36,33 +36,34 @@ DocumentScanInterfaceChromeos::~DocumentScanInterfaceChromeos() = default;
void DocumentScanInterfaceChromeos::ListScanners( void DocumentScanInterfaceChromeos::ListScanners(
const ListScannersResultsCallback& callback) { const ListScannersResultsCallback& callback) {
GetLorgnetteManagerClient()->ListScanners( GetLorgnetteManagerClient()->ListScanners(
base::Bind(&DocumentScanInterfaceChromeos::OnScannerListReceived, base::BindOnce(&DocumentScanInterfaceChromeos::OnScannerListReceived,
base::Unretained(this), callback)); base::Unretained(this), callback));
} }
void DocumentScanInterfaceChromeos::OnScannerListReceived( void DocumentScanInterfaceChromeos::OnScannerListReceived(
const ListScannersResultsCallback& callback, const ListScannersResultsCallback& callback,
bool succeeded, base::Optional<chromeos::LorgnetteManagerClient::ScannerTable> scanners) {
const chromeos::LorgnetteManagerClient::ScannerTable& scanners) {
std::vector<ScannerDescription> scanner_descriptions; std::vector<ScannerDescription> scanner_descriptions;
for (const auto& scanner : scanners) { if (scanners.has_value()) {
ScannerDescription description; for (const auto& scanner : scanners.value()) {
description.name = scanner.first; ScannerDescription description;
const auto& entry = scanner.second; description.name = scanner.first;
auto info_it = entry.find(lorgnette::kScannerPropertyManufacturer); const auto& entry = scanner.second;
if (info_it != entry.end()) { auto info_it = entry.find(lorgnette::kScannerPropertyManufacturer);
description.manufacturer = info_it->second; if (info_it != entry.end()) {
description.manufacturer = info_it->second;
}
info_it = entry.find(lorgnette::kScannerPropertyModel);
if (info_it != entry.end()) {
description.model = info_it->second;
}
info_it = entry.find(lorgnette::kScannerPropertyType);
if (info_it != entry.end()) {
description.scanner_type = info_it->second;
}
description.image_mime_type = kScannerImageMimeTypePng;
scanner_descriptions.push_back(description);
} }
info_it = entry.find(lorgnette::kScannerPropertyModel);
if (info_it != entry.end()) {
description.model = info_it->second;
}
info_it = entry.find(lorgnette::kScannerPropertyType);
if (info_it != entry.end()) {
description.scanner_type = info_it->second;
}
description.image_mime_type = kScannerImageMimeTypePng;
scanner_descriptions.push_back(description);
} }
const std::string kNoError; const std::string kNoError;
callback.Run(scanner_descriptions, kNoError); callback.Run(scanner_descriptions, kNoError);
...@@ -94,25 +95,22 @@ void DocumentScanInterfaceChromeos::Scan(const std::string& scanner_name, ...@@ -94,25 +95,22 @@ void DocumentScanInterfaceChromeos::Scan(const std::string& scanner_name,
GetLorgnetteManagerClient()->ScanImageToString( GetLorgnetteManagerClient()->ScanImageToString(
scanner_name, properties, scanner_name, properties,
base::Bind(&DocumentScanInterfaceChromeos::OnScanCompleted, base::BindOnce(&DocumentScanInterfaceChromeos::OnScanCompleted,
base::Unretained(this), callback)); base::Unretained(this), callback));
} }
void DocumentScanInterfaceChromeos::OnScanCompleted( void DocumentScanInterfaceChromeos::OnScanCompleted(
const ScanResultsCallback& callback, const ScanResultsCallback& callback,
bool succeeded, base::Optional<std::string> image_data) {
const std::string& image_data) { VLOG(1) << "ScanImage returns " << image_data.has_value();
VLOG(1) << "ScanImage returns " << succeeded; if (!image_data.has_value()) {
std::string error_string; callback.Run(std::string(), std::string(), kImageScanFailedError);
if (!succeeded) { return;
error_string = kImageScanFailedError;
} }
std::string image_base64; std::string image_base64;
base::Base64Encode(image_data, &image_base64); base::Base64Encode(image_data.value(), &image_base64);
std::string image_url(std::string(kPngImageDataUrlPrefix) + image_base64); callback.Run(kPngImageDataUrlPrefix + image_base64, kScannerImageMimeTypePng,
std::string() /* error */);
callback.Run(image_url, kScannerImageMimeTypePng, error_string);
} }
// static // static
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <string> #include <string>
#include "base/macros.h" #include "base/macros.h"
#include "base/optional.h"
#include "chromeos/dbus/lorgnette_manager_client.h" #include "chromeos/dbus/lorgnette_manager_client.h"
#include "extensions/browser/api/document_scan/document_scan_interface.h" #include "extensions/browser/api/document_scan/document_scan_interface.h"
...@@ -29,11 +30,9 @@ class DocumentScanInterfaceChromeos : public DocumentScanInterface { ...@@ -29,11 +30,9 @@ class DocumentScanInterfaceChromeos : public DocumentScanInterface {
private: private:
void OnScannerListReceived( void OnScannerListReceived(
const ListScannersResultsCallback& callback, const ListScannersResultsCallback& callback,
bool succeeded, base::Optional<chromeos::LorgnetteManagerClient::ScannerTable> scanners);
const chromeos::LorgnetteManagerClient::ScannerTable& scanners);
void OnScanCompleted(const ScanResultsCallback& callback, void OnScanCompleted(const ScanResultsCallback& callback,
bool succeeded, base::Optional<std::string> image_data);
const std::string& image_data);
DISALLOW_COPY_AND_ASSIGN(DocumentScanInterfaceChromeos); DISALLOW_COPY_AND_ASSIGN(DocumentScanInterfaceChromeos);
}; };
......
...@@ -83,8 +83,8 @@ TEST_F(DocumentScanInterfaceChromeosTest, ScanFailure) { ...@@ -83,8 +83,8 @@ TEST_F(DocumentScanInterfaceChromeosTest, ScanFailure) {
[](base::RunLoop* run_loop, const std::string& scanned_image, [](base::RunLoop* run_loop, const std::string& scanned_image,
const std::string& mime_type, const std::string& error) { const std::string& mime_type, const std::string& error) {
run_loop->Quit(); run_loop->Quit();
EXPECT_EQ("data:image/png;base64,", scanned_image); EXPECT_EQ("", scanned_image);
EXPECT_EQ("image/png", mime_type); EXPECT_EQ("", mime_type);
EXPECT_EQ("Image scan failed", error); EXPECT_EQ("Image scan failed", error);
}, },
&run_loop)); &run_loop));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment