summaryrefslogtreecommitdiffstats
path: root/device/hid/hid_report_descriptor_unittest.cc
diff options
context:
space:
mode:
authorrockot@chromium.org <rockot@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-04-25 00:16:40 +0000
committerrockot@chromium.org <rockot@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-04-25 00:16:40 +0000
commitfe7b300e384f4f7d593d0e39ed4c132577c52e63 (patch)
tree5ff70cf4d1cbc4fd8449208955fc63b1453d6838 /device/hid/hid_report_descriptor_unittest.cc
parent25c9e66e7408cf3025a1e208b05b75496bd5237b (diff)
downloadchromium_src-fe7b300e384f4f7d593d0e39ed4c132577c52e63.zip
chromium_src-fe7b300e384f4f7d593d0e39ed4c132577c52e63.tar.gz
chromium_src-fe7b300e384f4f7d593d0e39ed4c132577c52e63.tar.bz2
HID: Support top-level collection usages in device info.
This CL exists as an effort to actually land https://codereview.chromium.org/225513005/. This applies a small fix to the hid_service_win.cc module. BUG=359560 TBR=rpaquay TBR=jracle@logitech.com Review URL: https://codereview.chromium.org/256673002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@266066 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'device/hid/hid_report_descriptor_unittest.cc')
-rw-r--r--device/hid/hid_report_descriptor_unittest.cc613
1 files changed, 613 insertions, 0 deletions
diff --git a/device/hid/hid_report_descriptor_unittest.cc b/device/hid/hid_report_descriptor_unittest.cc
new file mode 100644
index 0000000..0d25889
--- /dev/null
+++ b/device/hid/hid_report_descriptor_unittest.cc
@@ -0,0 +1,613 @@
+// Copyright (c) 2014 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 <sstream>
+
+#include "device/hid/hid_report_descriptor.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using namespace testing;
+
+namespace device {
+
+namespace {
+
+std::ostream& operator<<(std::ostream& os,
+ const HidUsageAndPage::Page& usage_page) {
+ switch (usage_page) {
+ case HidUsageAndPage::kPageUndefined:
+ os << "Undefined";
+ break;
+ case HidUsageAndPage::kPageGenericDesktop:
+ os << "Generic Desktop";
+ break;
+ case HidUsageAndPage::kPageSimulation:
+ os << "Simulation";
+ break;
+ case HidUsageAndPage::kPageVirtualReality:
+ os << "Virtual Reality";
+ break;
+ case HidUsageAndPage::kPageSport:
+ os << "Sport";
+ break;
+ case HidUsageAndPage::kPageGame:
+ os << "Game";
+ break;
+ case HidUsageAndPage::kPageKeyboard:
+ os << "Keyboard";
+ break;
+ case HidUsageAndPage::kPageLed:
+ os << "Led";
+ break;
+ case HidUsageAndPage::kPageButton:
+ os << "Button";
+ break;
+ case HidUsageAndPage::kPageOrdinal:
+ os << "Ordinal";
+ break;
+ case HidUsageAndPage::kPageTelephony:
+ os << "Telephony";
+ break;
+ case HidUsageAndPage::kPageConsumer:
+ os << "Consumer";
+ break;
+ case HidUsageAndPage::kPageDigitizer:
+ os << "Digitizer";
+ break;
+ case HidUsageAndPage::kPagePidPage:
+ os << "Pid Page";
+ break;
+ case HidUsageAndPage::kPageUnicode:
+ os << "Unicode";
+ break;
+ case HidUsageAndPage::kPageAlphanumericDisplay:
+ os << "Alphanumeric Display";
+ break;
+ case HidUsageAndPage::kPageMedicalInstruments:
+ os << "Medical Instruments";
+ break;
+ case HidUsageAndPage::kPageMonitor0:
+ os << "Monitor 0";
+ break;
+ case HidUsageAndPage::kPageMonitor1:
+ os << "Monitor 1";
+ break;
+ case HidUsageAndPage::kPageMonitor2:
+ os << "Monitor 2";
+ break;
+ case HidUsageAndPage::kPageMonitor3:
+ os << "Monitor 3";
+ break;
+ case HidUsageAndPage::kPagePower0:
+ os << "Power 0";
+ break;
+ case HidUsageAndPage::kPagePower1:
+ os << "Power 1";
+ break;
+ case HidUsageAndPage::kPagePower2:
+ os << "Power 2";
+ break;
+ case HidUsageAndPage::kPagePower3:
+ os << "Power 3";
+ break;
+ case HidUsageAndPage::kPageBarCodeScanner:
+ os << "Bar Code Scanner";
+ break;
+ case HidUsageAndPage::kPageScale:
+ os << "Scale";
+ break;
+ case HidUsageAndPage::kPageMagneticStripeReader:
+ os << "Magnetic Stripe Reader";
+ break;
+ case HidUsageAndPage::kPageReservedPointOfSale:
+ os << "Reserved Point Of Sale";
+ break;
+ case HidUsageAndPage::kPageCameraControl:
+ os << "Camera Control";
+ break;
+ case HidUsageAndPage::kPageArcade:
+ os << "Arcade";
+ break;
+ case HidUsageAndPage::kPageVendor:
+ os << "Vendor";
+ break;
+ case HidUsageAndPage::kPageMediaCenter:
+ os << "Media Center";
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+ return os;
+}
+
+std::ostream& operator<<(std::ostream& os,
+ const HidUsageAndPage& usage_and_page) {
+ os << "Usage Page: " << usage_and_page.usage_page << ", Usage: "
+ << "0x" << std::hex << std::uppercase << usage_and_page.usage;
+ return os;
+}
+
+std::ostream& operator<<(std::ostream& os,
+ const HidReportDescriptorItem::Tag& tag) {
+ switch (tag) {
+ case HidReportDescriptorItem::kTagDefault:
+ os << "Default";
+ break;
+ case HidReportDescriptorItem::kTagInput:
+ os << "Input";
+ break;
+ case HidReportDescriptorItem::kTagOutput:
+ os << "Output";
+ break;
+ case HidReportDescriptorItem::kTagFeature:
+ os << "Feature";
+ break;
+ case HidReportDescriptorItem::kTagCollection:
+ os << "Collection";
+ break;
+ case HidReportDescriptorItem::kTagEndCollection:
+ os << "End Collection";
+ break;
+ case HidReportDescriptorItem::kTagUsagePage:
+ os << "Usage Page";
+ break;
+ case HidReportDescriptorItem::kTagLogicalMinimum:
+ os << "Logical Minimum";
+ break;
+ case HidReportDescriptorItem::kTagLogicalMaximum:
+ os << "Logical Maximum";
+ break;
+ case HidReportDescriptorItem::kTagPhysicalMinimum:
+ os << "Physical Minimum";
+ break;
+ case HidReportDescriptorItem::kTagPhysicalMaximum:
+ os << "Physical Maximum";
+ break;
+ case HidReportDescriptorItem::kTagUnitExponent:
+ os << "Unit Exponent";
+ break;
+ case HidReportDescriptorItem::kTagUnit:
+ os << "Unit";
+ break;
+ case HidReportDescriptorItem::kTagReportSize:
+ os << "Report Size";
+ break;
+ case HidReportDescriptorItem::kTagReportId:
+ os << "Report ID";
+ break;
+ case HidReportDescriptorItem::kTagReportCount:
+ os << "Report Count";
+ break;
+ case HidReportDescriptorItem::kTagPush:
+ os << "Push";
+ break;
+ case HidReportDescriptorItem::kTagPop:
+ os << "Pop";
+ break;
+ case HidReportDescriptorItem::kTagUsage:
+ os << "Usage";
+ break;
+ case HidReportDescriptorItem::kTagUsageMinimum:
+ os << "Usage Minimum";
+ break;
+ case HidReportDescriptorItem::kTagUsageMaximum:
+ os << "Usage Maximum";
+ break;
+ case HidReportDescriptorItem::kTagDesignatorIndex:
+ os << "Designator Index";
+ break;
+ case HidReportDescriptorItem::kTagDesignatorMinimum:
+ os << "Designator Minimum";
+ break;
+ case HidReportDescriptorItem::kTagDesignatorMaximum:
+ os << "Designator Maximum";
+ break;
+ case HidReportDescriptorItem::kTagStringIndex:
+ os << "String Index";
+ break;
+ case HidReportDescriptorItem::kTagStringMinimum:
+ os << "String Minimum";
+ break;
+ case HidReportDescriptorItem::kTagStringMaximum:
+ os << "String Maximum";
+ break;
+ case HidReportDescriptorItem::kTagDelimiter:
+ os << "Delimeter";
+ break;
+ case HidReportDescriptorItem::kTagLong:
+ os << "Long";
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+
+ return os;
+}
+
+std::ostream& operator<<(std::ostream& os,
+ const HidReportDescriptorItem::ReportInfo& data) {
+ if (data.data_or_constant)
+ os << "Con";
+ else
+ os << "Dat";
+ if (data.array_or_variable)
+ os << "|Arr";
+ else
+ os << "|Var";
+ if (data.absolute_or_relative)
+ os << "|Abs";
+ else
+ os << "|Rel";
+ if (data.wrap)
+ os << "|Wrp";
+ else
+ os << "|NoWrp";
+ if (data.linear)
+ os << "|NoLin";
+ else
+ os << "|Lin";
+ if (data.preferred)
+ os << "|NoPrf";
+ else
+ os << "|Prf";
+ if (data.null)
+ os << "|Null";
+ else
+ os << "|NoNull";
+ if (data.bit_field_or_buffer)
+ os << "|Buff";
+ else
+ os << "|BitF";
+ return os;
+}
+
+std::ostream& operator<<(std::ostream& os,
+ const HidReportDescriptorItem::CollectionType& type) {
+ switch (type) {
+ case HidReportDescriptorItem::kCollectionTypePhysical:
+ os << "Physical";
+ break;
+ case HidReportDescriptorItem::kCollectionTypeApplication:
+ os << "Application";
+ break;
+ case HidReportDescriptorItem::kCollectionTypeLogical:
+ os << "Logical";
+ break;
+ case HidReportDescriptorItem::kCollectionTypeReport:
+ os << "Report";
+ break;
+ case HidReportDescriptorItem::kCollectionTypeNamedArray:
+ os << "Named Array";
+ break;
+ case HidReportDescriptorItem::kCollectionTypeUsageSwitch:
+ os << "Usage Switch";
+ break;
+ case HidReportDescriptorItem::kCollectionTypeUsageModifier:
+ os << "Usage Modifier";
+ break;
+ case HidReportDescriptorItem::kCollectionTypeReserved:
+ os << "Reserved";
+ break;
+ case HidReportDescriptorItem::kCollectionTypeVendor:
+ os << "Vendor";
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+ return os;
+}
+
+std::ostream& operator<<(std::ostream& os,
+ const HidReportDescriptorItem& item) {
+ HidReportDescriptorItem::Tag item_tag = item.tag();
+ uint32_t data = item.GetShortData();
+
+ std::ostringstream sstr;
+ sstr << item_tag;
+ sstr << " (";
+
+ long pos = sstr.tellp();
+ switch (item_tag) {
+ case HidReportDescriptorItem::kTagDefault:
+ case HidReportDescriptorItem::kTagEndCollection:
+ case HidReportDescriptorItem::kTagPush:
+ case HidReportDescriptorItem::kTagPop:
+ case HidReportDescriptorItem::kTagLong:
+ break;
+
+ case HidReportDescriptorItem::kTagCollection:
+ sstr << HidReportDescriptorItem::GetCollectionTypeFromValue(data);
+ break;
+
+ case HidReportDescriptorItem::kTagInput:
+ case HidReportDescriptorItem::kTagOutput:
+ case HidReportDescriptorItem::kTagFeature:
+ sstr << (HidReportDescriptorItem::ReportInfo&)data;
+ break;
+
+ case HidReportDescriptorItem::kTagUsagePage:
+ sstr << (HidUsageAndPage::Page)data;
+ break;
+
+ case HidReportDescriptorItem::kTagUsage:
+ case HidReportDescriptorItem::kTagReportId:
+ sstr << "0x" << std::hex << std::uppercase << data;
+ break;
+
+ default:
+ sstr << data;
+ break;
+ }
+ if (pos == sstr.tellp()) {
+ std::string str = sstr.str();
+ str.erase(str.end() - 2, str.end());
+ os << str;
+ } else {
+ os << sstr.str() << ")";
+ }
+
+ return os;
+}
+
+const char kIndentStep[] = " ";
+
+std::ostream& operator<<(std::ostream& os,
+ const HidReportDescriptor& descriptor) {
+ for (std::vector<linked_ptr<HidReportDescriptorItem> >::const_iterator
+ items_iter = descriptor.items().begin();
+ items_iter != descriptor.items().end();
+ ++items_iter) {
+ linked_ptr<HidReportDescriptorItem> item = *items_iter;
+ size_t indentLevel = item->GetDepth();
+ for (size_t i = 0; i < indentLevel; i++)
+ os << kIndentStep;
+ os << *item.get() << std::endl;
+ }
+ return os;
+}
+
+// See 'E.6 Report Descriptor (Keyboard)'
+// in HID specifications (v1.11)
+const uint8_t kKeyboard[] = {
+ 0x05, 0x01, 0x09, 0x06, 0xA1, 0x01, 0x05, 0x07, 0x19, 0xE0, 0x29,
+ 0xE7, 0x15, 0x00, 0x25, 0x01, 0x75, 0x01, 0x95, 0x08, 0x81, 0x02,
+ 0x95, 0x01, 0x75, 0x08, 0x81, 0x01, 0x95, 0x05, 0x75, 0x01, 0x05,
+ 0x08, 0x19, 0x01, 0x29, 0x05, 0x91, 0x02, 0x95, 0x01, 0x75, 0x03,
+ 0x91, 0x01, 0x95, 0x06, 0x75, 0x08, 0x15, 0x00, 0x25, 0x65, 0x05,
+ 0x07, 0x19, 0x00, 0x29, 0x65, 0x81, 0x00, 0xC0};
+
+// See 'E.10 Report Descriptor (Mouse)'
+// in HID specifications (v1.11)
+const uint8_t kMouse[] = {0x05, 0x01, 0x09, 0x02, 0xA1, 0x01, 0x09, 0x01, 0xA1,
+ 0x00, 0x05, 0x09, 0x19, 0x01, 0x29, 0x03, 0x15, 0x00,
+ 0x25, 0x01, 0x95, 0x03, 0x75, 0x01, 0x81, 0x02, 0x95,
+ 0x01, 0x75, 0x05, 0x81, 0x01, 0x05, 0x01, 0x09, 0x30,
+ 0x09, 0x31, 0x15, 0x81, 0x25, 0x7F, 0x75, 0x08, 0x95,
+ 0x02, 0x81, 0x06, 0xC0, 0xC0};
+
+const uint8_t kLogitechUnifyingReceiver[] = {
+ 0x06, 0x00, 0xFF, 0x09, 0x01, 0xA1, 0x01, 0x85, 0x10, 0x75, 0x08,
+ 0x95, 0x06, 0x15, 0x00, 0x26, 0xFF, 0x00, 0x09, 0x01, 0x81, 0x00,
+ 0x09, 0x01, 0x91, 0x00, 0xC0, 0x06, 0x00, 0xFF, 0x09, 0x02, 0xA1,
+ 0x01, 0x85, 0x11, 0x75, 0x08, 0x95, 0x13, 0x15, 0x00, 0x26, 0xFF,
+ 0x00, 0x09, 0x02, 0x81, 0x00, 0x09, 0x02, 0x91, 0x00, 0xC0, 0x06,
+ 0x00, 0xFF, 0x09, 0x04, 0xA1, 0x01, 0x85, 0x20, 0x75, 0x08, 0x95,
+ 0x0E, 0x15, 0x00, 0x26, 0xFF, 0x00, 0x09, 0x41, 0x81, 0x00, 0x09,
+ 0x41, 0x91, 0x00, 0x85, 0x21, 0x95, 0x1F, 0x15, 0x00, 0x26, 0xFF,
+ 0x00, 0x09, 0x42, 0x81, 0x00, 0x09, 0x42, 0x91, 0x00, 0xC0};
+
+} // namespace
+
+class HidReportDescriptorTest : public testing::Test {
+
+ protected:
+ virtual void SetUp() OVERRIDE { descriptor_ = NULL; }
+
+ virtual void TearDown() OVERRIDE {
+ if (descriptor_) {
+ delete descriptor_;
+ }
+ }
+
+ public:
+ void ParseDescriptor(const std::string& expected,
+ const uint8_t* bytes,
+ size_t size) {
+ descriptor_ = new HidReportDescriptor(bytes, size);
+
+ std::stringstream actual;
+ actual << *descriptor_;
+
+ std::cout << "HID report descriptor:" << std::endl;
+ std::cout << actual.str();
+
+ // TODO(jracle@logitech.com): refactor string comparison in favor of
+ // testing individual fields.
+ ASSERT_EQ(expected, actual.str());
+ }
+
+ void GetTopLevelCollections(const std::vector<HidUsageAndPage>& expected,
+ const uint8_t* bytes,
+ size_t size) {
+ descriptor_ = new HidReportDescriptor(bytes, size);
+
+ std::vector<HidUsageAndPage> actual;
+ descriptor_->GetTopLevelCollections(&actual);
+
+ std::cout << "HID top-level collections:" << std::endl;
+ for (std::vector<HidUsageAndPage>::const_iterator iter = actual.begin();
+ iter != actual.end();
+ ++iter) {
+ std::cout << *iter << std::endl;
+ }
+
+ ASSERT_THAT(actual, ContainerEq(expected));
+ }
+
+ private:
+ HidReportDescriptor* descriptor_;
+};
+
+TEST_F(HidReportDescriptorTest, ParseDescriptor_Keyboard) {
+ const char expected[] = {
+ "Usage Page (Generic Desktop)\n"
+ "Usage (0x6)\n"
+ "Collection (Physical)\n"
+ " Usage Page (Keyboard)\n"
+ " Usage Minimum (224)\n"
+ " Usage Maximum (231)\n"
+ " Logical Minimum (0)\n"
+ " Logical Maximum (1)\n"
+ " Report Size (1)\n"
+ " Report Count (8)\n"
+ " Input (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)\n"
+ " Report Count (1)\n"
+ " Report Size (8)\n"
+ " Input (Con|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)\n"
+ " Report Count (5)\n"
+ " Report Size (1)\n"
+ " Usage Page (Led)\n"
+ " Usage Minimum (1)\n"
+ " Usage Maximum (5)\n"
+ " Output (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)\n"
+ " Report Count (1)\n"
+ " Report Size (3)\n"
+ " Output (Con|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)\n"
+ " Report Count (6)\n"
+ " Report Size (8)\n"
+ " Logical Minimum (0)\n"
+ " Logical Maximum (101)\n"
+ " Usage Page (Keyboard)\n"
+ " Usage Minimum (0)\n"
+ " Usage Maximum (101)\n"
+ " Input (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)\n"
+ "End Collection\n"};
+
+ ParseDescriptor(std::string(expected), kKeyboard, sizeof(kKeyboard));
+}
+
+TEST_F(HidReportDescriptorTest, TopLevelCollections_Keyboard) {
+ HidUsageAndPage expected[] = {
+ HidUsageAndPage(0x06, HidUsageAndPage::kPageGenericDesktop)};
+
+ GetTopLevelCollections(std::vector<HidUsageAndPage>(
+ expected, expected + ARRAYSIZE_UNSAFE(expected)),
+ kKeyboard,
+ sizeof(kKeyboard));
+}
+
+TEST_F(HidReportDescriptorTest, ParseDescriptor_Mouse) {
+ const char expected[] = {
+ "Usage Page (Generic Desktop)\n"
+ "Usage (0x2)\n"
+ "Collection (Physical)\n"
+ " Usage (0x1)\n"
+ " Collection (Physical)\n"
+ " Usage Page (Button)\n"
+ " Usage Minimum (1)\n"
+ " Usage Maximum (3)\n"
+ " Logical Minimum (0)\n"
+ " Logical Maximum (1)\n"
+ " Report Count (3)\n"
+ " Report Size (1)\n"
+ " Input (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)\n"
+ " Report Count (1)\n"
+ " Report Size (5)\n"
+ " Input (Con|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)\n"
+ " Usage Page (Generic Desktop)\n"
+ " Usage (0x30)\n"
+ " Usage (0x31)\n"
+ " Logical Minimum (129)\n"
+ " Logical Maximum (127)\n"
+ " Report Size (8)\n"
+ " Report Count (2)\n"
+ " Input (Dat|Arr|Abs|NoWrp|Lin|Prf|NoNull|BitF)\n"
+ " End Collection\n"
+ "End Collection\n"};
+
+ ParseDescriptor(std::string(expected), kMouse, sizeof(kMouse));
+}
+
+TEST_F(HidReportDescriptorTest, TopLevelCollections_Mouse) {
+ HidUsageAndPage expected[] = {
+ HidUsageAndPage(0x02, HidUsageAndPage::kPageGenericDesktop)};
+
+ GetTopLevelCollections(std::vector<HidUsageAndPage>(
+ expected, expected + ARRAYSIZE_UNSAFE(expected)),
+ kMouse,
+ sizeof(kMouse));
+}
+
+TEST_F(HidReportDescriptorTest, ParseDescriptor_LogitechUnifyingReceiver) {
+ const char expected[] = {
+ "Usage Page (Vendor)\n"
+ "Usage (0x1)\n"
+ "Collection (Physical)\n"
+ " Report ID (0x10)\n"
+ " Report Size (8)\n"
+ " Report Count (6)\n"
+ " Logical Minimum (0)\n"
+ " Logical Maximum (255)\n"
+ " Usage (0x1)\n"
+ " Input (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)\n"
+ " Usage (0x1)\n"
+ " Output (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)\n"
+ "End Collection\n"
+ "Usage Page (Vendor)\n"
+ "Usage (0x2)\n"
+ "Collection (Physical)\n"
+ " Report ID (0x11)\n"
+ " Report Size (8)\n"
+ " Report Count (19)\n"
+ " Logical Minimum (0)\n"
+ " Logical Maximum (255)\n"
+ " Usage (0x2)\n"
+ " Input (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)\n"
+ " Usage (0x2)\n"
+ " Output (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)\n"
+ "End Collection\n"
+ "Usage Page (Vendor)\n"
+ "Usage (0x4)\n"
+ "Collection (Physical)\n"
+ " Report ID (0x20)\n"
+ " Report Size (8)\n"
+ " Report Count (14)\n"
+ " Logical Minimum (0)\n"
+ " Logical Maximum (255)\n"
+ " Usage (0x41)\n"
+ " Input (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)\n"
+ " Usage (0x41)\n"
+ " Output (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)\n"
+ " Report ID (0x21)\n"
+ " Report Count (31)\n"
+ " Logical Minimum (0)\n"
+ " Logical Maximum (255)\n"
+ " Usage (0x42)\n"
+ " Input (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)\n"
+ " Usage (0x42)\n"
+ " Output (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)\n"
+ "End Collection\n"};
+
+ ParseDescriptor(std::string(expected),
+ kLogitechUnifyingReceiver,
+ sizeof(kLogitechUnifyingReceiver));
+}
+
+TEST_F(HidReportDescriptorTest, TopLevelCollections_LogitechUnifyingReceiver) {
+ HidUsageAndPage expected[] = {
+ HidUsageAndPage(0x01, HidUsageAndPage::kPageVendor),
+ HidUsageAndPage(0x02, HidUsageAndPage::kPageVendor),
+ HidUsageAndPage(0x04, HidUsageAndPage::kPageVendor), };
+
+ GetTopLevelCollections(std::vector<HidUsageAndPage>(
+ expected, expected + ARRAYSIZE_UNSAFE(expected)),
+ kLogitechUnifyingReceiver,
+ sizeof(kLogitechUnifyingReceiver));
+}
+
+} // namespace device