blob: f7d93d602bf9b36025c0cc848df33214268d27ad [file] [log] [blame]
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ash/printing/usb_printer_util.h"
#include "services/device/public/mojom/usb_device.mojom.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace ash {
namespace {
using device::mojom::UsbAlternateInterfaceInfo;
using device::mojom::UsbConfigurationInfo;
using device::mojom::UsbDeviceInfo;
using device::mojom::UsbInterfaceInfo;
using testing::ElementsAre;
using testing::Eq;
using testing::HasSubstr;
using testing::Optional;
TEST(UsbPrinterUtilTest, UsbDeviceToPrinterWithValidSerialNumber) {
UsbDeviceInfo device_info;
device_info.vendor_id = 1;
device_info.product_id = 2;
device_info.serial_number = u"12345";
PrinterDetector::DetectedPrinter entry;
EXPECT_TRUE(UsbDeviceToPrinter(device_info, &entry));
EXPECT_THAT(entry.printer.uri().GetNormalized(), HasSubstr("?serial=12345"));
}
TEST(UsbPrinterUtilTest, UsbDeviceToPrinterWithNoSerialNumber) {
UsbDeviceInfo device_info;
device_info.vendor_id = 1;
device_info.product_id = 2;
PrinterDetector::DetectedPrinter entry;
EXPECT_TRUE(UsbDeviceToPrinter(device_info, &entry));
// If the device_info does not specify a serial number, the URI should get
// created with the character '?'.
EXPECT_THAT(entry.printer.uri().GetNormalized(), HasSubstr("?serial=?"));
}
TEST(UsbPrinterUtilTest, UsbDeviceToPrinterWithEmptySerialNumber) {
UsbDeviceInfo device_info;
device_info.vendor_id = 1;
device_info.product_id = 2;
device_info.serial_number = u"";
PrinterDetector::DetectedPrinter entry;
EXPECT_TRUE(UsbDeviceToPrinter(device_info, &entry));
// If the device_info specifies an empty serial number, the URI should get
// created with the character '?'.
EXPECT_THAT(entry.printer.uri().GetNormalized(), HasSubstr("?serial=?"));
}
TEST(UsbPrinterUtilTest, GuessEffectiveMakeAndModelDuplicatedManufacturer) {
UsbDeviceInfo device_info;
device_info.manufacturer_name = u"bixolon";
device_info.product_name = u"bixolon abc-123";
EXPECT_EQ(GuessEffectiveMakeAndModel(device_info), "bixolon abc-123");
}
TEST(UsbPrinterUtilTest, GuessEffectiveMakeAndModel) {
UsbDeviceInfo device_info;
device_info.manufacturer_name = u"bixolon";
device_info.product_name = u"abc-123";
EXPECT_EQ(GuessEffectiveMakeAndModel(device_info), "bixolon abc-123");
}
TEST(UsbPrinterUtilTest, MakeDisplayNameBothMissing) {
std::string make_and_model = MakeDisplayName("", "");
EXPECT_FALSE(make_and_model.empty());
}
TEST(UsbPrinterUtilTest, MakeDisplayNameBothPresent) {
std::string make_and_model = MakeDisplayName("TheMake", "TheModel");
EXPECT_NE(make_and_model.find("TheMake"), std::string::npos);
EXPECT_NE(make_and_model.find("TheModel"), std::string::npos);
}
TEST(UsbPrinterUtilTest, MakeDisplayNameMakeOnly) {
std::string make_and_model = MakeDisplayName("TheMake", "");
EXPECT_NE(make_and_model.find("TheMake"), std::string::npos);
}
TEST(UsbPrinterUtilTest, MakeDisplayNameModelOnly) {
std::string make_and_model = MakeDisplayName("", "TheModel");
EXPECT_NE(make_and_model.find("TheModel"), std::string::npos);
}
TEST(UsbPrinterUtilTest, SearchDataNotUpdatedWithoutMake) {
UsbDeviceInfo device_info;
device_info.vendor_id = 1;
device_info.product_id = 2;
device_info.serial_number = u"";
device_info.manufacturer_name = u"make";
device_info.product_name = u"model";
PrinterDetector::DetectedPrinter entry;
EXPECT_TRUE(UsbDeviceToPrinter(device_info, &entry));
entry.ppd_search_data.make_and_model.push_back("make model");
chromeos::UsbPrinterId device_id;
device_id.set_model("new-model");
UpdateSearchDataFromDeviceId(device_id, &entry);
EXPECT_EQ("make model", entry.printer.make_and_model());
EXPECT_THAT(entry.ppd_search_data.make_and_model, ElementsAre("make model"));
}
TEST(UsbPrinterUtilTest, SearchDataNotUpdatedWithoutModel) {
UsbDeviceInfo device_info;
device_info.vendor_id = 1;
device_info.product_id = 2;
device_info.serial_number = u"";
device_info.manufacturer_name = u"make";
device_info.product_name = u"model";
PrinterDetector::DetectedPrinter entry;
EXPECT_TRUE(UsbDeviceToPrinter(device_info, &entry));
entry.ppd_search_data.make_and_model.push_back("make model");
chromeos::UsbPrinterId device_id;
device_id.set_make("new-make");
UpdateSearchDataFromDeviceId(device_id, &entry);
EXPECT_EQ("make model", entry.printer.make_and_model());
EXPECT_THAT(entry.ppd_search_data.make_and_model, ElementsAre("make model"));
}
TEST(UsbPrinterUtilTest, SearchDataNotUpdatedIfNamesMatch) {
UsbDeviceInfo device_info;
device_info.vendor_id = 1;
device_info.product_id = 2;
device_info.serial_number = u"";
device_info.manufacturer_name = u"make";
device_info.product_name = u"model";
PrinterDetector::DetectedPrinter entry;
EXPECT_TRUE(UsbDeviceToPrinter(device_info, &entry));
entry.ppd_search_data.make_and_model.push_back("make model");
chromeos::UsbPrinterId device_id;
device_id.set_make("MAKE");
device_id.set_model("MODEL");
UpdateSearchDataFromDeviceId(device_id, &entry);
EXPECT_EQ("make model", entry.printer.make_and_model());
EXPECT_THAT(entry.ppd_search_data.make_and_model, ElementsAre("make model"));
}
TEST(UsbPrinterUtilTest, SearchDataReplacedForGenericDescriptors) {
UsbDeviceInfo device_info;
device_info.vendor_id = 1;
device_info.product_id = 2;
device_info.serial_number = u"";
device_info.manufacturer_name = u"epson";
device_info.product_name = u"usb2.0 mfp(hi-speed)";
PrinterDetector::DetectedPrinter entry;
EXPECT_TRUE(UsbDeviceToPrinter(device_info, &entry));
entry.ppd_search_data.make_and_model.push_back("epson usb2.0 mfp(hi-speed)");
chromeos::UsbPrinterId device_id;
device_id.set_make("MAKE");
device_id.set_model("MODEL");
UpdateSearchDataFromDeviceId(device_id, &entry);
EXPECT_EQ("MAKE MODEL", entry.printer.make_and_model());
EXPECT_THAT(entry.ppd_search_data.make_and_model, ElementsAre("make model"));
}
TEST(UsbPrinterUtilTest, SearchDataReplacedForEmptyMakeModel) {
UsbDeviceInfo device_info;
device_info.vendor_id = 1;
device_info.product_id = 2;
device_info.serial_number = u"";
device_info.manufacturer_name = u"";
device_info.product_name = u"";
PrinterDetector::DetectedPrinter entry;
EXPECT_TRUE(UsbDeviceToPrinter(device_info, &entry));
entry.ppd_search_data.make_and_model.push_back("");
chromeos::UsbPrinterId device_id;
device_id.set_make("MAKE");
device_id.set_model("MODEL");
UpdateSearchDataFromDeviceId(device_id, &entry);
EXPECT_EQ("MAKE MODEL", entry.printer.make_and_model());
EXPECT_THAT(entry.ppd_search_data.make_and_model, ElementsAre("make model"));
}
TEST(UsbPrinterUtilTest, SearchDataAugmentedForNonGenericDescriptors) {
UsbDeviceInfo device_info;
device_info.vendor_id = 1;
device_info.product_id = 2;
device_info.serial_number = u"";
device_info.manufacturer_name = u"make";
device_info.product_name = u"model";
PrinterDetector::DetectedPrinter entry;
EXPECT_TRUE(UsbDeviceToPrinter(device_info, &entry));
entry.ppd_search_data.make_and_model.push_back("make model");
chromeos::UsbPrinterId device_id;
device_id.set_make("REAL-MAKE");
device_id.set_model("REAL-MODEL");
UpdateSearchDataFromDeviceId(device_id, &entry);
EXPECT_EQ("make model", entry.printer.make_and_model());
EXPECT_THAT(entry.ppd_search_data.make_and_model,
ElementsAre("make model", "real-make real-model"));
}
TEST(UsbPrinterUtilTest, FindPrinterInterfaceTargetMissingConfig) {
UsbDeviceInfo di;
EXPECT_FALSE(internal::FindPrinterInterfaceTarget(di).has_value());
}
TEST(UsbPrinterUtilTest, FindPrinterInterfaceTargetMissingInterface) {
UsbDeviceInfo di;
di.configurations.emplace_back(UsbConfigurationInfo::New());
EXPECT_FALSE(internal::FindPrinterInterfaceTarget(di).has_value());
}
TEST(UsbPrinterUtilTest, FindPrinterInterfaceTargetMissingAlternate) {
UsbDeviceInfo di;
auto& config = di.configurations.emplace_back(UsbConfigurationInfo::New());
config->interfaces.emplace_back(UsbInterfaceInfo::New());
EXPECT_FALSE(internal::FindPrinterInterfaceTarget(di).has_value());
}
TEST(UsbPrinterUtilTest, FindPrinterInterfaceTargetNonPrinterAlternate) {
UsbDeviceInfo di;
auto& config = di.configurations.emplace_back(UsbConfigurationInfo::New());
auto& iface = config->interfaces.emplace_back(UsbInterfaceInfo::New());
auto& alt = iface->alternates.emplace_back(
device::mojom::UsbAlternateInterfaceInfo::New());
alt->class_code = 0;
EXPECT_FALSE(internal::FindPrinterInterfaceTarget(di).has_value());
}
TEST(UsbPrinterUtilTest, FindPrinterInterfaceTargetOnePrinterAlternate) {
UsbDeviceInfo di;
di.vendor_id = 0x1234;
di.product_id = 0x5678;
auto& config = di.configurations.emplace_back(UsbConfigurationInfo::New());
auto& iface = config->interfaces.emplace_back(UsbInterfaceInfo::New());
auto& alt = iface->alternates.emplace_back(
device::mojom::UsbAlternateInterfaceInfo::New());
alt->class_code = 7;
alt->subclass_code = 1;
// The first interface is a printer, so it should be returned.
internal::PrinterInterfaceTarget expected = {.vidpid = "1234:5678",
.config = 0,
.interface = 0,
.alternate = 0,
.set_alternate = false};
EXPECT_THAT(internal::FindPrinterInterfaceTarget(di), Optional(Eq(expected)));
}
TEST(UsbPrinterUtilTest, FindPrinterInterfaceTargetPrinterInterfaceSecond) {
UsbDeviceInfo di;
di.vendor_id = 0x1234;
di.product_id = 0x5678;
auto& config = di.configurations.emplace_back(UsbConfigurationInfo::New());
auto& iface1 = config->interfaces.emplace_back(UsbInterfaceInfo::New());
auto& alt1 = iface1->alternates.emplace_back(
device::mojom::UsbAlternateInterfaceInfo::New());
alt1->class_code = 255;
alt1->subclass_code = 255;
auto& iface2 = config->interfaces.emplace_back(UsbInterfaceInfo::New());
auto& alt2 = iface2->alternates.emplace_back(
device::mojom::UsbAlternateInterfaceInfo::New());
alt2->class_code = 7;
alt2->subclass_code = 1;
// Skip the first non-printer interface and return the printer interface.
internal::PrinterInterfaceTarget expected = {.vidpid = "1234:5678",
.config = 0,
.interface = 1,
.alternate = 0,
.set_alternate = false};
EXPECT_THAT(internal::FindPrinterInterfaceTarget(di), Optional(Eq(expected)));
}
TEST(UsbPrinterUtilTest, FindPrinterInterfaceTargetPrinterSkipMultiAlternates) {
UsbDeviceInfo di;
di.vendor_id = 0x1234;
di.product_id = 0x5678;
auto& config = di.configurations.emplace_back(UsbConfigurationInfo::New());
auto& iface1 = config->interfaces.emplace_back(UsbInterfaceInfo::New());
auto& alt11 = iface1->alternates.emplace_back(
device::mojom::UsbAlternateInterfaceInfo::New());
alt11->class_code = 255;
alt11->subclass_code = 255;
auto& alt12 = iface1->alternates.emplace_back(
device::mojom::UsbAlternateInterfaceInfo::New());
alt12->class_code = 7;
alt12->subclass_code = 1;
auto& iface2 = config->interfaces.emplace_back(UsbInterfaceInfo::New());
auto& alt2 = iface2->alternates.emplace_back(
device::mojom::UsbAlternateInterfaceInfo::New());
alt2->class_code = 7;
alt2->subclass_code = 1;
// Skip the first interface because its printer class isn't the first
// alternate.
internal::PrinterInterfaceTarget expected = {.vidpid = "1234:5678",
.config = 0,
.interface = 1,
.alternate = 0,
.set_alternate = false};
EXPECT_THAT(internal::FindPrinterInterfaceTarget(di), Optional(Eq(expected)));
}
TEST(UsbPrinterUtilTest,
FindPrinterInterfaceTargetPrinterForcedMultiAlternates) {
UsbDeviceInfo di;
di.vendor_id = 0x1234;
di.product_id = 0x5678;
auto& config = di.configurations.emplace_back(UsbConfigurationInfo::New());
auto& iface1 = config->interfaces.emplace_back(UsbInterfaceInfo::New());
auto& alt11 = iface1->alternates.emplace_back(
device::mojom::UsbAlternateInterfaceInfo::New());
alt11->class_code = 255;
alt11->subclass_code = 255;
auto& alt12 = iface1->alternates.emplace_back(
device::mojom::UsbAlternateInterfaceInfo::New());
alt12->class_code = 7;
alt12->subclass_code = 1;
auto& iface2 = config->interfaces.emplace_back(UsbInterfaceInfo::New());
auto& alt2 = iface2->alternates.emplace_back(
device::mojom::UsbAlternateInterfaceInfo::New());
alt2->class_code = 255;
alt2->subclass_code = 255;
// Choose the first interface even though it has multiple alternates because
// none of the other interfaces are printer class.
internal::PrinterInterfaceTarget expected = {.vidpid = "1234:5678",
.config = 0,
.interface = 0,
.alternate = 1,
.set_alternate = true};
EXPECT_THAT(internal::FindPrinterInterfaceTarget(di), Optional(Eq(expected)));
}
} // namespace
} // namespace ash