1 // Copyright (c) 2014 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 <stddef.h>
6 #include <stdint.h>
7 
8 #include <limits>
9 #include <sstream>
10 #include <unordered_map>
11 #include <utility>
12 
13 #include "base/macros.h"
14 #include "services/device/hid/test_report_descriptors.h"
15 #include "services/device/public/cpp/hid/hid_report_descriptor.h"
16 #include "services/device/public/cpp/hid/hid_usage_and_page.h"
17 #include "services/device/public/mojom/hid.mojom.h"
18 #include "testing/gmock/include/gmock/gmock.h"
19 #include "testing/gtest/include/gtest/gtest.h"
20 
21 namespace device {
22 
23 namespace {
24 using HidReport = std::vector<std::unique_ptr<HidReportItem>>;
25 using HidReportMap = std::unordered_map<uint8_t, HidReport>;
26 using HidCollectionVector = std::vector<std::unique_ptr<HidCollection>>;
27 
28 // HID unit values.
29 const uint32_t kUnitCandela = 0x010000e1;
30 const uint32_t kUnitDegrees = 0x14;
31 const uint32_t kUnitInch = 0x13;
32 const uint32_t kUnitNewton = 0xe111;
33 const uint32_t kUnitSecond = 0x1001;
34 
35 // Report info bitfield values. The bits are:
36 //   bit 0: Data (0) | Constant (1)
37 //   bit 1: Array (0) | Variable (1)
38 //   bit 2: Absolute (0) | Relative (1)
39 //   bit 3: No Wrap (0) | Wrap (1)
40 //   bit 4: Linear (0) | Non-Linear (1)
41 //   bit 5: Preferred State (0) | No Preferred State (1)
42 //   bit 6: No Null Value (0) | Has Null Value (1)
43 //   bit 7: Non-Volatile (0) | Volatile (1)
44 //   bit 8: Bit Field (0) | Buffered Bytes (1)
45 const uint16_t kNonNullableArray = 0x0000;
46 const uint16_t kConstantArray = 0x0001;
47 const uint16_t kAbsoluteVariable = 0x0002;
48 const uint16_t kConstant = 0x0003;
49 const uint16_t kRelativeVariable = 0x0006;
50 const uint16_t kNonLinearVariable = 0x0012;
51 const uint16_t kNullableArray = 0x0040;
52 const uint16_t kNullableAbsoluteVariable = 0x0042;
53 const uint16_t kVolatileConstant = 0x0083;
54 const uint16_t kBufferedBytes = 0x0102;
55 
56 // Vendor usage pages.
57 const uint16_t kPageVendor02 = mojom::kPageVendor + 0x02;
58 const uint16_t kPageVendor05 = mojom::kPageVendor + 0x05;
59 const uint16_t kPageVendor80 = mojom::kPageVendor + 0x80;
60 
61 // Bit-width and mask for the usage ID field in a 32-bit usage value.
62 const size_t kUsageIdSizeBits = sizeof(uint16_t) * 8;
63 const uint32_t kUsageIdMask = std::numeric_limits<uint16_t>::max();
64 
65 // Combined usage page and usage ID values. The usage page occupies the high 16
66 // bits, the usage ID occupies the low 16 bits.
67 const uint32_t kUsageButton = (mojom::kPageButton << kUsageIdSizeBits);
68 const uint32_t kUsageConsumer = (mojom::kPageConsumer << kUsageIdSizeBits);
69 const uint32_t kUsageConsumerACBack = kUsageConsumer | 0x0224;
70 const uint32_t kUsageConsumerACHome = kUsageConsumer | 0x0223;
71 const uint32_t kUsageConsumerControl = kUsageConsumer | 0x01;
72 const uint32_t kUsageConsumerModeStep = kUsageConsumer | 0x82;
73 const uint32_t kUsageDigitizer = (mojom::kPageDigitizer << kUsageIdSizeBits);
74 const uint32_t kUsageDigitizerDigitizer = kUsageDigitizer | 0x01;
75 const uint32_t kUsageDigitizerBarrelSwitch = kUsageDigitizer | 0x44;
76 const uint32_t kUsageDigitizerInRange = kUsageDigitizer | 0x32;
77 const uint32_t kUsageDigitizerPuck = kUsageDigitizer | 0x21;
78 const uint32_t kUsageDigitizerStylus = kUsageDigitizer | 0x20;
79 const uint32_t kUsageDigitizerTipPressure = kUsageDigitizer | 0x30;
80 const uint32_t kUsageDigitizerTipSwitch = kUsageDigitizer | 0x42;
81 const uint32_t kUsageGenericDesktop =
82     (mojom::kPageGenericDesktop << kUsageIdSizeBits);
83 const uint32_t kUsageGenericDesktopDial =
84     kUsageGenericDesktop | mojom::kGenericDesktopDial;
85 const uint32_t kUsageGenericDesktopGamePad =
86     kUsageGenericDesktop | mojom::kGenericDesktopGamePad;
87 const uint32_t kUsageGenericDesktopHatSwitch =
88     kUsageGenericDesktop | mojom::kGenericDesktopHatSwitch;
89 const uint32_t kUsageGenericDesktopJoystick =
90     kUsageGenericDesktop | mojom::kGenericDesktopJoystick;
91 const uint32_t kUsageGenericDesktopKeyboard =
92     kUsageGenericDesktop | mojom::kGenericDesktopKeyboard;
93 const uint32_t kUsageGenericDesktopMouse =
94     kUsageGenericDesktop | mojom::kGenericDesktopMouse;
95 const uint32_t kUsageGenericDesktopPointer =
96     kUsageGenericDesktop | mojom::kGenericDesktopPointer;
97 const uint32_t kUsageGenericDesktopRx =
98     kUsageGenericDesktop | mojom::kGenericDesktopRx;
99 const uint32_t kUsageGenericDesktopRy =
100     kUsageGenericDesktop | mojom::kGenericDesktopRy;
101 const uint32_t kUsageGenericDesktopRz =
102     kUsageGenericDesktop | mojom::kGenericDesktopRz;
103 const uint32_t kUsageGenericDesktopSystemControl =
104     kUsageGenericDesktop | mojom::kGenericDesktopSystemControl;
105 const uint32_t kUsageGenericDesktopSystemMainMenu =
106     kUsageGenericDesktop | mojom::kGenericDesktopSystemMainMenu;
107 const uint32_t kUsageGenericDesktopVbrx =
108     kUsageGenericDesktop | mojom::kGenericDesktopVbrx;
109 const uint32_t kUsageGenericDesktopVbry =
110     kUsageGenericDesktop | mojom::kGenericDesktopVbry;
111 const uint32_t kUsageGenericDesktopVbrz =
112     kUsageGenericDesktop | mojom::kGenericDesktopVbrz;
113 const uint32_t kUsageGenericDesktopVx =
114     kUsageGenericDesktop | mojom::kGenericDesktopVx;
115 const uint32_t kUsageGenericDesktopVy =
116     kUsageGenericDesktop | mojom::kGenericDesktopVy;
117 const uint32_t kUsageGenericDesktopVz =
118     kUsageGenericDesktop | mojom::kGenericDesktopVz;
119 const uint32_t kUsageGenericDesktopWheel =
120     kUsageGenericDesktop | mojom::kGenericDesktopWheel;
121 const uint32_t kUsageGenericDesktopX =
122     kUsageGenericDesktop | mojom::kGenericDesktopX;
123 const uint32_t kUsageGenericDesktopY =
124     kUsageGenericDesktop | mojom::kGenericDesktopY;
125 const uint32_t kUsageGenericDesktopZ =
126     kUsageGenericDesktop | mojom::kGenericDesktopZ;
127 const uint32_t kUsageGenericDeviceBatteryStrength =
128     (mojom::kPageGenericDevice << kUsageIdSizeBits) | 0x20;
129 const uint32_t kUsageKeyboard = (mojom::kPageKeyboard << kUsageIdSizeBits);
130 const uint32_t kUsageKeyboardApplication = kUsageKeyboard | 0x65;
131 const uint32_t kUsageKeyboardLeftControl = kUsageKeyboard | 0xe0;
132 const uint32_t kUsageKeyboardRightGui = kUsageKeyboard | 0xe7;
133 const uint32_t kUsageLedNumLock = (mojom::kPageLed << kUsageIdSizeBits) | 0x01;
134 const uint32_t kUsageLedCapsLock = (mojom::kPageLed << kUsageIdSizeBits) | 0x02;
135 const uint32_t kUsageLedScrollLock =
136     (mojom::kPageLed << kUsageIdSizeBits) | 0x03;
137 const uint32_t kUsageLedCompose = (mojom::kPageLed << kUsageIdSizeBits) | 0x04;
138 const uint32_t kUsageLedKana = (mojom::kPageLed << kUsageIdSizeBits) | 0x05;
139 const uint32_t kUsageMonitorControl =
140     (mojom::kPageMonitor0 << kUsageIdSizeBits) | 0x01;
141 const uint32_t kUsageMonitorEdidInfo =
142     (mojom::kPageMonitor0 << kUsageIdSizeBits) | 0x02;
143 const uint32_t kUsageMonitorVdifInfo =
144     (mojom::kPageMonitor0 << kUsageIdSizeBits) | 0x03;
145 const uint32_t kUsageMonitorBrightness =
146     (mojom::kPageMonitor2 << kUsageIdSizeBits) | 0x10;
147 const uint32_t kUsageMonitorContrast =
148     (mojom::kPageMonitor2 << kUsageIdSizeBits) | 0x12;
149 const uint32_t kUsageMonitorRedVideoGain =
150     (mojom::kPageMonitor2 << kUsageIdSizeBits) | 0x16;
151 const uint32_t kUsageMonitorGreenVideoGain =
152     (mojom::kPageMonitor2 << kUsageIdSizeBits) | 0x18;
153 const uint32_t kUsageMonitorBlueVideoGain =
154     (mojom::kPageMonitor2 << kUsageIdSizeBits) | 0x1a;
155 const uint32_t kUsageMonitorHorizontalPosition =
156     (mojom::kPageMonitor2 << kUsageIdSizeBits) | 0x20;
157 const uint32_t kUsageMonitorHorizontalSize =
158     (mojom::kPageMonitor2 << kUsageIdSizeBits) | 0x22;
159 const uint32_t kUsageMonitorVerticalPosition =
160     (mojom::kPageMonitor2 << kUsageIdSizeBits) | 0x30;
161 const uint32_t kUsageMonitorVerticalSize =
162     (mojom::kPageMonitor2 << kUsageIdSizeBits) | 0x32;
163 const uint32_t kUsageMonitorTrapezoidalDistortion =
164     (mojom::kPageMonitor2 << kUsageIdSizeBits) | 0x42;
165 const uint32_t kUsageMonitorTilt =
166     (mojom::kPageMonitor2 << kUsageIdSizeBits) | 0x44;
167 const uint32_t kUsageMonitorRedVideoBlackLevel =
168     (mojom::kPageMonitor2 << kUsageIdSizeBits) | 0x6c;
169 const uint32_t kUsageMonitorGreenVideoBlackLevel =
170     (mojom::kPageMonitor2 << kUsageIdSizeBits) | 0x6e;
171 const uint32_t kUsageMonitorBlueVideoBlackLevel =
172     (mojom::kPageMonitor2 << kUsageIdSizeBits) | 0x70;
173 const uint32_t kUsagePidSetEffectReport =
174     (mojom::kPagePidPage << kUsageIdSizeBits) | 0x21;
175 const uint32_t kUsagePidDuration =
176     (mojom::kPagePidPage << kUsageIdSizeBits) | 0x50;
177 const uint32_t kUsagePidMagnitude =
178     (mojom::kPagePidPage << kUsageIdSizeBits) | 0x70;
179 const uint32_t kUsagePidLoopCount =
180     (mojom::kPagePidPage << kUsageIdSizeBits) | 0x7c;
181 const uint32_t kUsagePidDCEnableActuators =
182     (mojom::kPagePidPage << kUsageIdSizeBits) | 0x97;
183 const uint32_t kUsagePidStartDelay =
184     (mojom::kPagePidPage << kUsageIdSizeBits) | 0xa7;
185 const uint32_t kUsageSimulationAccelerator =
186     (mojom::kPageSimulation << kUsageIdSizeBits) | 0xc4;
187 const uint32_t kUsageSimulationBrake =
188     (mojom::kPageSimulation << kUsageIdSizeBits) | 0xc5;
189 const uint32_t kUsageVendor = mojom::kPageVendor << kUsageIdSizeBits;
190 const uint32_t kUsageVendor02 = kPageVendor02 << kUsageIdSizeBits;
191 const uint32_t kUsageVendor05 = kPageVendor05 << kUsageIdSizeBits;
192 const uint32_t kUsageVendor80 = kPageVendor80 << kUsageIdSizeBits;
193 
194 // Report item tags.
195 const HidReportDescriptorItem::Tag kInput = HidReportDescriptorItem::kTagInput;
196 const HidReportDescriptorItem::Tag kOutput =
197     HidReportDescriptorItem::kTagOutput;
198 const HidReportDescriptorItem::Tag kFeature =
199     HidReportDescriptorItem::kTagFeature;
200 const uint32_t kCollectionTypeApplication =
201     mojom::kHIDCollectionTypeApplication;
202 const uint32_t kCollectionTypeLogical = mojom::kHIDCollectionTypeLogical;
203 const uint32_t kCollectionTypePhysical = mojom::kHIDCollectionTypePhysical;
204 
205 }  // namespace
206 
207 class HidReportDescriptorTest : public testing::Test {
208  protected:
209   using HidUsageAndPage = mojom::HidUsageAndPage;
210   using HidCollectionInfo = mojom::HidCollectionInfo;
211   using HidCollectionInfoPtr = mojom::HidCollectionInfoPtr;
212 
TearDown()213   void TearDown() override {
214     descriptor_ = nullptr;
215     expected_collection_infos_.clear();
216     expected_collections_.clear();
217     report_id_ = 0;
218     globals_ = HidItemStateTable::HidGlobalItemState();
219   }
220 
221  public:
222   // Add a top-level collection to |expected_collection_infos_|.
AddTopCollectionInfo(HidCollectionInfoPtr collection_info)223   void AddTopCollectionInfo(HidCollectionInfoPtr collection_info) {
224     expected_collection_infos_.push_back(std::move(collection_info));
225   }
226 
227   // Create a new collection and append it to |expected_collections_|.
AddTopCollection(uint32_t usage,uint32_t collection_type)228   HidCollection* AddTopCollection(uint32_t usage, uint32_t collection_type) {
229     uint16_t usage_page = (usage >> kUsageIdSizeBits) & kUsageIdMask;
230     usage = usage & kUsageIdMask;
231     expected_collections_.push_back(std::make_unique<HidCollection>(
232         nullptr, usage_page, usage, static_cast<uint32_t>(collection_type)));
233     return expected_collections_.back().get();
234   }
235 
236   // Create a new collection as a child of |parent|.
AddChild(HidCollection * parent,uint32_t usage,uint32_t collection_type)237   HidCollection* AddChild(HidCollection* parent,
238                           uint32_t usage,
239                           uint32_t collection_type) {
240     uint16_t usage_page = (usage >> kUsageIdSizeBits) & kUsageIdMask;
241     usage = usage & kUsageIdMask;
242     parent->AddChildForTesting(std::make_unique<HidCollection>(
243         parent, usage_page, usage, static_cast<uint32_t>(collection_type)));
244     return parent->GetChildren().back().get();
245   }
246 
247   // Set the |report_id|. Subsequent report items will be appended to the report
248   // with this ID.
SetReportId(uint8_t report_id)249   void SetReportId(uint8_t report_id) { report_id_ = report_id; }
250 
251   // Set the |unit| and |unit_exponent|. Subsequent report items will inherit
252   // these values.
SetUnitAndUnitExponent(uint32_t unit,uint32_t unit_exponent)253   void SetUnitAndUnitExponent(uint32_t unit, uint32_t unit_exponent) {
254     globals_.unit = unit;
255     globals_.unit_exponent = unit_exponent;
256   }
257 
258   // Set the logical and physical minimums and maximums. Subsequent report items
259   // will inherit these values.
SetLogicalAndPhysicalBounds(uint32_t logical_minimum,uint32_t logical_maximum,uint32_t physical_minimum,uint32_t physical_maximum)260   void SetLogicalAndPhysicalBounds(uint32_t logical_minimum,
261                                    uint32_t logical_maximum,
262                                    uint32_t physical_minimum,
263                                    uint32_t physical_maximum) {
264     globals_.logical_minimum = int32_t{logical_minimum};
265     globals_.logical_maximum = int32_t{logical_maximum};
266     globals_.physical_minimum = int32_t{physical_minimum};
267     globals_.physical_maximum = int32_t{physical_maximum};
268   }
269 
270   // Set the |report_size| in bits, and the |report_count|. Subsequent report
271   // items will inherit these values.
SetReportSizeAndCount(uint32_t report_size,uint32_t report_count)272   void SetReportSizeAndCount(uint32_t report_size, uint32_t report_count) {
273     globals_.report_size = report_size;
274     globals_.report_count = report_count;
275   }
276 
277   // Add a report item with a size and count but no usage value.
AddReportConstant(HidCollection * collection,HidReportDescriptorItem::Tag tag,uint32_t report_info)278   void AddReportConstant(HidCollection* collection,
279                          HidReportDescriptorItem::Tag tag,
280                          uint32_t report_info) {
281     HidItemStateTable state;
282     state.global_stack.push_back(globals_);
283     state.report_id = report_id_;
284     for (const HidCollection* c = collection; c; c = c->GetParent())
285       const_cast<HidCollection*>(c)->AddReportItem(tag, report_info, state);
286   }
287 
288   // Add a report item for one or more usages with the same size. The size of
289   // |usage_ids| is not required to be the same as the report count.
AddReportItem(HidCollection * collection,HidReportDescriptorItem::Tag tag,uint32_t report_info,const std::vector<uint32_t> & usage_ids)290   void AddReportItem(HidCollection* collection,
291                      HidReportDescriptorItem::Tag tag,
292                      uint32_t report_info,
293                      const std::vector<uint32_t>& usage_ids) {
294     HidItemStateTable state;
295     state.global_stack.push_back(globals_);
296     state.report_id = report_id_;
297     state.local.usages = usage_ids;
298     for (const HidCollection* c = collection; c; c = c->GetParent())
299       const_cast<HidCollection*>(c)->AddReportItem(tag, report_info, state);
300   }
301 
302   // Add a report item for a range of usages. The item may be a variable or an
303   // array.
AddReportItemRange(HidCollection * collection,HidReportDescriptorItem::Tag tag,uint32_t report_info,uint32_t usage_minimum,uint32_t usage_maximum)304   void AddReportItemRange(HidCollection* collection,
305                           HidReportDescriptorItem::Tag tag,
306                           uint32_t report_info,
307                           uint32_t usage_minimum,
308                           uint32_t usage_maximum) {
309     HidItemStateTable state;
310     state.global_stack.push_back(globals_);
311     state.report_id = report_id_;
312     state.local.usage_minimum = usage_minimum;
313     state.local.usage_maximum = usage_maximum;
314     for (const HidCollection* c = collection; c; c = c->GetParent())
315       const_cast<HidCollection*>(c)->AddReportItem(tag, report_info, state);
316   }
317 
ValidateDetails(const bool expected_has_report_id,const size_t expected_max_input_report_size,const size_t expected_max_output_report_size,const size_t expected_max_feature_report_size,const uint8_t * bytes,size_t size)318   void ValidateDetails(
319       const bool expected_has_report_id,
320       const size_t expected_max_input_report_size,
321       const size_t expected_max_output_report_size,
322       const size_t expected_max_feature_report_size,
323       const uint8_t* bytes,
324       size_t size) {
325     descriptor_ = std::make_unique<HidReportDescriptor>(
326         std::vector<uint8_t>(bytes, bytes + size));
327     std::vector<HidCollectionInfoPtr> actual_collection_infos;
328     bool actual_has_report_id;
329     size_t actual_max_input_report_size;
330     size_t actual_max_output_report_size;
331     size_t actual_max_feature_report_size;
332     descriptor_->GetDetails(&actual_collection_infos, &actual_has_report_id,
333                             &actual_max_input_report_size,
334                             &actual_max_output_report_size,
335                             &actual_max_feature_report_size);
336 
337     ASSERT_EQ(expected_collection_infos_.size(),
338               actual_collection_infos.size());
339     auto actual_info_iter = actual_collection_infos.begin();
340     auto expected_info_iter = expected_collection_infos_.begin();
341     while (expected_info_iter != expected_collection_infos_.end() &&
342            actual_info_iter != actual_collection_infos.end()) {
343       const HidCollectionInfoPtr& expected_info = *expected_info_iter;
344       const HidCollectionInfoPtr& actual_info = *actual_info_iter;
345       ASSERT_EQ(expected_info->usage->usage_page,
346                 actual_info->usage->usage_page);
347       ASSERT_EQ(expected_info->usage->usage, actual_info->usage->usage);
348       ASSERT_THAT(actual_info->report_ids,
349                   testing::ContainerEq(expected_info->report_ids));
350       ++expected_info_iter;
351       ++actual_info_iter;
352     }
353     ASSERT_EQ(expected_has_report_id, actual_has_report_id);
354     ASSERT_EQ(expected_max_input_report_size, actual_max_input_report_size);
355     ASSERT_EQ(expected_max_output_report_size, actual_max_output_report_size);
356     ASSERT_EQ(expected_max_feature_report_size, actual_max_feature_report_size);
357   }
358 
ValidateReportItem(const HidReportItem & expected,const HidReportItem & actual)359   static void ValidateReportItem(const HidReportItem& expected,
360                                  const HidReportItem& actual) {
361     uint32_t expected_report_info =
362         *reinterpret_cast<const uint32_t*>(&expected.GetReportInfo());
363     uint32_t actual_report_info =
364         *reinterpret_cast<const uint32_t*>(&actual.GetReportInfo());
365     ASSERT_EQ(expected.GetTag(), actual.GetTag());
366     ASSERT_EQ(expected_report_info, actual_report_info);
367     ASSERT_EQ(expected.GetReportId(), actual.GetReportId());
368     ASSERT_THAT(actual.GetUsages(), testing::ContainerEq(expected.GetUsages()));
369     ASSERT_EQ(expected.GetUsageMinimum(), actual.GetUsageMinimum());
370     ASSERT_EQ(expected.GetUsageMaximum(), actual.GetUsageMaximum());
371     ASSERT_EQ(expected.GetDesignatorMinimum(), actual.GetDesignatorMinimum());
372     ASSERT_EQ(expected.GetDesignatorMaximum(), actual.GetDesignatorMaximum());
373     ASSERT_EQ(expected.GetStringMinimum(), actual.GetStringMinimum());
374     ASSERT_EQ(expected.GetStringMaximum(), actual.GetStringMaximum());
375     ASSERT_EQ(expected.GetLogicalMinimum(), actual.GetLogicalMinimum());
376     ASSERT_EQ(expected.GetLogicalMaximum(), actual.GetLogicalMaximum());
377     ASSERT_EQ(expected.GetPhysicalMinimum(), actual.GetPhysicalMinimum());
378     ASSERT_EQ(expected.GetPhysicalMaximum(), actual.GetPhysicalMaximum());
379     ASSERT_EQ(expected.GetUnitExponent(), actual.GetUnitExponent());
380     ASSERT_EQ(expected.GetUnit(), actual.GetUnit());
381     ASSERT_EQ(expected.GetReportSize(), actual.GetReportSize());
382     ASSERT_EQ(expected.GetReportCount(), actual.GetReportCount());
383   }
384 
ValidateReportMap(const HidReportMap & expected_reports,const HidReportMap & actual_reports)385   static void ValidateReportMap(const HidReportMap& expected_reports,
386                                 const HidReportMap& actual_reports) {
387     for (const auto& expected_entry : expected_reports) {
388       auto find_it = actual_reports.find(expected_entry.first);
389       ASSERT_NE(find_it, actual_reports.end());
390       const auto& expected_report = expected_entry.second;
391       const auto& actual_report = find_it->second;
392       ASSERT_EQ(expected_report.size(), actual_report.size());
393       auto expected_item_iter = expected_report.begin();
394       auto actual_item_iter = actual_report.begin();
395       while (expected_item_iter != expected_report.end() &&
396              actual_item_iter != actual_report.end()) {
397         ValidateReportItem(**expected_item_iter, **actual_item_iter);
398         ++expected_item_iter;
399         ++actual_item_iter;
400       }
401     }
402     ASSERT_EQ(expected_reports.size(), actual_reports.size());
403   }
404 
ValidateLinkCollection(const HidCollection * expected_collection,const HidCollection * actual_collection)405   static void ValidateLinkCollection(const HidCollection* expected_collection,
406                                      const HidCollection* actual_collection) {
407     ASSERT_EQ(expected_collection->GetUsagePage(),
408               actual_collection->GetUsagePage());
409     ASSERT_EQ(expected_collection->GetUsage(), actual_collection->GetUsage());
410     ASSERT_EQ(expected_collection->GetCollectionType(),
411               actual_collection->GetCollectionType());
412     ValidateReportMap(expected_collection->GetInputReports(),
413                       actual_collection->GetInputReports());
414     ValidateReportMap(expected_collection->GetOutputReports(),
415                       actual_collection->GetOutputReports());
416     ValidateReportMap(expected_collection->GetFeatureReports(),
417                       actual_collection->GetFeatureReports());
418     const auto& expected_children = expected_collection->GetChildren();
419     const auto& actual_children = actual_collection->GetChildren();
420     auto expected_child_iter = expected_children.begin();
421     auto actual_child_iter = actual_children.begin();
422     while (expected_child_iter != expected_children.end() &&
423            actual_child_iter != actual_children.end()) {
424       const HidCollection* expected_child = expected_child_iter->get();
425       const HidCollection* actual_child = actual_child_iter->get();
426       ASSERT_EQ(actual_child->GetParent(), actual_collection);
427       ValidateLinkCollection(expected_child, actual_child);
428       ++expected_child_iter;
429       ++actual_child_iter;
430     }
431     ASSERT_EQ(expected_children.size(), actual_children.size());
432   }
433 
ValidateCollections(const uint8_t * bytes,size_t size)434   void ValidateCollections(const uint8_t* bytes, size_t size) {
435     descriptor_ = std::make_unique<HidReportDescriptor>(
436         std::vector<uint8_t>(bytes, bytes + size));
437     const auto& actual_collections = descriptor_->collections();
438     auto actual_collection_iter = actual_collections.begin();
439     auto expected_collection_iter = expected_collections_.begin();
440     while (expected_collection_iter != expected_collections_.end() &&
441            actual_collection_iter != actual_collections.end()) {
442       ValidateLinkCollection(expected_collection_iter->get(),
443                              actual_collection_iter->get());
444       ++expected_collection_iter;
445       ++actual_collection_iter;
446     }
447     ASSERT_EQ(expected_collections_.size(), actual_collections.size());
448   }
449 
450  private:
451   std::unique_ptr<HidReportDescriptor> descriptor_;
452   std::vector<HidCollectionInfoPtr> expected_collection_infos_;
453   HidCollectionVector expected_collections_;
454   uint8_t report_id_ = 0;
455   HidItemStateTable::HidGlobalItemState globals_;
456 };
457 
TEST_F(HidReportDescriptorTest,ValidateDetails_Digitizer)458 TEST_F(HidReportDescriptorTest, ValidateDetails_Digitizer) {
459   auto digitizer = HidCollectionInfo::New();
460   digitizer->usage = HidUsageAndPage::New(0x01, mojom::kPageDigitizer);
461   ASSERT_EQ(IsProtected(*digitizer->usage), false);
462   digitizer->report_ids = {0x01, 0x02, 0x03};
463   AddTopCollectionInfo(std::move(digitizer));
464   ValidateDetails(true, 6, 0, 0, kDigitizer, kDigitizerSize);
465 }
466 
TEST_F(HidReportDescriptorTest,ValidateCollections_Digitizer)467 TEST_F(HidReportDescriptorTest, ValidateCollections_Digitizer) {
468   auto* top =
469       AddTopCollection(kUsageDigitizerDigitizer, kCollectionTypeApplication);
470   auto* puck = AddChild(top, kUsageDigitizerPuck, kCollectionTypePhysical);
471   SetReportId(0x01);
472   SetLogicalAndPhysicalBounds(0, 12000, 0, 12);
473   SetUnitAndUnitExponent(kUnitInch, 0);
474   SetReportSizeAndCount(16, 2);
475   AddReportItem(puck, kInput, kAbsoluteVariable,
476                 {kUsageGenericDesktopX, kUsageGenericDesktopY});
477   SetLogicalAndPhysicalBounds(0, 1, 0, 1);
478   SetUnitAndUnitExponent(0, 0);
479   SetReportSizeAndCount(1, 3);
480   AddReportItem(puck, kInput, kAbsoluteVariable,
481                 {kUsageDigitizerInRange, kUsageDigitizerBarrelSwitch,
482                  kUsageDigitizerTipSwitch});
483   SetReportSizeAndCount(5, 1);
484   AddReportConstant(puck, kInput, kConstant);
485   SetReportId(0x02);
486   auto* stylus_up =
487       AddChild(top, kUsageDigitizerStylus, kCollectionTypePhysical);
488   SetLogicalAndPhysicalBounds(0, 12000, 0, 12);
489   SetUnitAndUnitExponent(kUnitInch, 0);
490   SetReportSizeAndCount(16, 2);
491   AddReportItem(stylus_up, kInput, kAbsoluteVariable,
492                 {kUsageGenericDesktopX, kUsageGenericDesktopY});
493   SetLogicalAndPhysicalBounds(0, 1, 0, 1);
494   SetUnitAndUnitExponent(0, 0);
495   SetReportSizeAndCount(1, 2);
496   AddReportItem(stylus_up, kInput, kAbsoluteVariable, {kUsageDigitizerInRange});
497   SetLogicalAndPhysicalBounds(0, 16, 0, 1);
498   SetReportSizeAndCount(5, 2);
499   AddReportItemRange(stylus_up, kInput, kNullableArray, kUsageButton,
500                      kUsageButton + 16);
501   SetReportSizeAndCount(2, 2);
502   AddReportConstant(stylus_up, kInput, kConstantArray);
503   SetReportId(0x03);
504   auto* stylus_down =
505       AddChild(top, kUsageDigitizerStylus, kCollectionTypePhysical);
506   SetLogicalAndPhysicalBounds(0, 12000, 0, 12);
507   SetUnitAndUnitExponent(kUnitInch, 0);
508   SetReportSizeAndCount(16, 2);
509   AddReportItem(stylus_down, kInput, kAbsoluteVariable,
510                 {kUsageGenericDesktopX, kUsageGenericDesktopY});
511   SetLogicalAndPhysicalBounds(0, 1, 0, 1);
512   SetUnitAndUnitExponent(0, 0);
513   SetReportSizeAndCount(1, 2);
514   AddReportItem(stylus_down, kInput, kAbsoluteVariable,
515                 {kUsageDigitizerInRange, kUsageDigitizerBarrelSwitch});
516   SetReportSizeAndCount(1, 6);
517   AddReportConstant(stylus_down, kInput, kConstant);
518   SetLogicalAndPhysicalBounds(0, 127, 0, 45);
519   SetUnitAndUnitExponent(kUnitNewton, 4);
520   SetReportSizeAndCount(8, 1);
521   AddReportItem(stylus_down, kInput, kNonLinearVariable,
522                 {kUsageDigitizerTipPressure});
523   ValidateCollections(kDigitizer, kDigitizerSize);
524 }
525 
TEST_F(HidReportDescriptorTest,ValidateDetails_Keyboard)526 TEST_F(HidReportDescriptorTest, ValidateDetails_Keyboard) {
527   auto keyboard = HidCollectionInfo::New();
528   keyboard->usage = HidUsageAndPage::New(mojom::kGenericDesktopKeyboard,
529                                          mojom::kPageGenericDesktop);
530   ASSERT_EQ(IsProtected(*keyboard->usage), true);
531   AddTopCollectionInfo(std::move(keyboard));
532   ValidateDetails(false, 8, 1, 0, kKeyboard, kKeyboardSize);
533 }
534 
TEST_F(HidReportDescriptorTest,ValidateCollections_Keyboard)535 TEST_F(HidReportDescriptorTest, ValidateCollections_Keyboard) {
536   auto* top = AddTopCollection(kUsageGenericDesktopKeyboard,
537                                kCollectionTypeApplication);
538   SetLogicalAndPhysicalBounds(0, 1, 0, 0);
539   SetReportSizeAndCount(1, 8);
540   AddReportItemRange(top, kInput, kAbsoluteVariable, kUsageKeyboardLeftControl,
541                      kUsageKeyboardRightGui);
542   SetReportSizeAndCount(8, 1);
543   AddReportConstant(top, kInput, kConstant);
544   SetReportSizeAndCount(1, 5);
545   AddReportItemRange(top, kOutput, kAbsoluteVariable, kUsageLedNumLock,
546                      kUsageLedKana);
547   SetReportSizeAndCount(3, 1);
548   AddReportConstant(top, kOutput, kConstant);
549   SetLogicalAndPhysicalBounds(0, 101, 0, 0);
550   SetReportSizeAndCount(8, 6);
551   AddReportItemRange(top, kInput, kNonNullableArray, kUsageKeyboard,
552                      kUsageKeyboardApplication);
553   ValidateCollections(kKeyboard, kKeyboardSize);
554 }
555 
TEST_F(HidReportDescriptorTest,ValidateDetails_Monitor)556 TEST_F(HidReportDescriptorTest, ValidateDetails_Monitor) {
557   auto monitor = HidCollectionInfo::New();
558   monitor->usage = HidUsageAndPage::New(0x01, mojom::kPageMonitor0);
559   ASSERT_EQ(IsProtected(*monitor->usage), false);
560   monitor->report_ids = {0x01, 0x02, 0x03, 0x04, 0x05};
561   AddTopCollectionInfo(std::move(monitor));
562   ValidateDetails(true, 0, 0, 243, kMonitor, kMonitorSize);
563 }
564 
TEST_F(HidReportDescriptorTest,ValidateCollections_Monitor)565 TEST_F(HidReportDescriptorTest, ValidateCollections_Monitor) {
566   auto* top =
567       AddTopCollection(kUsageMonitorControl, kCollectionTypeApplication);
568   SetReportId(0x01);
569   SetLogicalAndPhysicalBounds(0, 255, 0, 0);
570   SetReportSizeAndCount(8, 128);
571   AddReportItem(top, kFeature, kBufferedBytes, {kUsageMonitorEdidInfo});
572   SetReportId(0x02);
573   SetReportSizeAndCount(8, 243);
574   AddReportItem(top, kFeature, kBufferedBytes, {kUsageMonitorVdifInfo});
575   SetReportId(0x03);
576   SetUnitAndUnitExponent(kUnitCandela, 0x0e);
577   SetReportSizeAndCount(16, 1);
578   SetLogicalAndPhysicalBounds(0, 200, 0, 0);
579   AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageMonitorBrightness});
580   SetReportId(0x04);
581   SetLogicalAndPhysicalBounds(0, 100, 0, 0);
582   AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageMonitorContrast});
583   SetReportSizeAndCount(16, 6);
584   SetLogicalAndPhysicalBounds(0, 255, 0, 0);
585   AddReportItem(
586       top, kFeature, kAbsoluteVariable,
587       {kUsageMonitorRedVideoGain, kUsageMonitorGreenVideoGain,
588        kUsageMonitorBlueVideoGain, kUsageMonitorRedVideoBlackLevel,
589        kUsageMonitorGreenVideoBlackLevel, kUsageMonitorBlueVideoBlackLevel});
590   SetReportId(0x05);
591   SetLogicalAndPhysicalBounds(0, 127, 0, 0);
592   AddReportItem(top, kFeature, kAbsoluteVariable,
593                 {kUsageMonitorHorizontalPosition, kUsageMonitorHorizontalSize,
594                  kUsageMonitorVerticalPosition, kUsageMonitorVerticalSize,
595                  kUsageMonitorTrapezoidalDistortion, kUsageMonitorTilt});
596   ValidateCollections(kMonitor, kMonitorSize);
597 }
598 
TEST_F(HidReportDescriptorTest,ValidateDetails_Mouse)599 TEST_F(HidReportDescriptorTest, ValidateDetails_Mouse) {
600   auto mouse = HidCollectionInfo::New();
601   mouse->usage = HidUsageAndPage::New(mojom::kGenericDesktopMouse,
602                                       mojom::kPageGenericDesktop);
603   ASSERT_EQ(IsProtected(*mouse->usage), true);
604   AddTopCollectionInfo(std::move(mouse));
605   ValidateDetails(false, 3, 0, 0, kMouse, kMouseSize);
606 }
607 
TEST_F(HidReportDescriptorTest,ValidateCollections_Mouse)608 TEST_F(HidReportDescriptorTest, ValidateCollections_Mouse) {
609   auto* top =
610       AddTopCollection(kUsageGenericDesktopMouse, kCollectionTypeApplication);
611   auto* physical =
612       AddChild(top, kUsageGenericDesktopPointer, kCollectionTypePhysical);
613   SetLogicalAndPhysicalBounds(0, 1, 0, 0);
614   SetReportSizeAndCount(1, 3);
615   AddReportItemRange(physical, kInput, kAbsoluteVariable, kUsageButton + 1,
616                      kUsageButton + 3);
617   SetReportSizeAndCount(5, 1);
618   AddReportConstant(physical, kInput, kConstant);
619   SetLogicalAndPhysicalBounds(0x81, 0x7f, 0, 0);
620   SetReportSizeAndCount(8, 2);
621   AddReportItem(physical, kInput, kRelativeVariable,
622                 {kUsageGenericDesktopX, kUsageGenericDesktopY});
623   ValidateCollections(kMouse, kMouseSize);
624 }
625 
TEST_F(HidReportDescriptorTest,ValidateDetails_LogitechUnifyingReceiver)626 TEST_F(HidReportDescriptorTest, ValidateDetails_LogitechUnifyingReceiver) {
627   auto hidpp_short = HidCollectionInfo::New();
628   hidpp_short->usage = HidUsageAndPage::New(0x01, mojom::kPageVendor);
629   ASSERT_EQ(IsProtected(*hidpp_short->usage), false);
630   hidpp_short->report_ids = {0x10};
631   auto hidpp_long = HidCollectionInfo::New();
632   hidpp_long->usage = HidUsageAndPage::New(0x02, mojom::kPageVendor);
633   ASSERT_EQ(IsProtected(*hidpp_long->usage), false);
634   hidpp_long->report_ids = {0x11};
635   auto hidpp_dj = HidCollectionInfo::New();
636   hidpp_dj->usage = HidUsageAndPage::New(0x04, mojom::kPageVendor);
637   ASSERT_EQ(IsProtected(*hidpp_dj->usage), false);
638   hidpp_dj->report_ids = {0x20, 0x21};
639   AddTopCollectionInfo(std::move(hidpp_short));
640   AddTopCollectionInfo(std::move(hidpp_long));
641   AddTopCollectionInfo(std::move(hidpp_dj));
642   ValidateDetails(true, 31, 31, 0, kLogitechUnifyingReceiver,
643                   kLogitechUnifyingReceiverSize);
644 }
645 
TEST_F(HidReportDescriptorTest,ValidateCollections_LogitechUnifyingReceiver)646 TEST_F(HidReportDescriptorTest, ValidateCollections_LogitechUnifyingReceiver) {
647   auto* short_collection =
648       AddTopCollection(kUsageVendor + 0x01, kCollectionTypeApplication);
649   SetReportId(0x10);
650   SetLogicalAndPhysicalBounds(0, 255, 0, 0);
651   SetReportSizeAndCount(8, 6);
652   AddReportItem(short_collection, kInput, kNonNullableArray,
653                 {kUsageVendor + 0x01});
654   AddReportItem(short_collection, kOutput, kNonNullableArray,
655                 {kUsageVendor + 0x01});
656   auto* long_collection =
657       AddTopCollection(kUsageVendor + 0x02, kCollectionTypeApplication);
658   SetReportId(0x11);
659   SetReportSizeAndCount(8, 19);
660   AddReportItem(long_collection, kInput, kNonNullableArray,
661                 {kUsageVendor + 0x02});
662   AddReportItem(long_collection, kOutput, kNonNullableArray,
663                 {kUsageVendor + 0x02});
664   auto* dj_collection =
665       AddTopCollection(kUsageVendor + 0x04, kCollectionTypeApplication);
666   SetReportId(0x20);
667   SetReportSizeAndCount(8, 14);
668   AddReportItem(dj_collection, kInput, kNonNullableArray,
669                 {kUsageVendor + 0x41});
670   AddReportItem(dj_collection, kOutput, kNonNullableArray,
671                 {kUsageVendor + 0x41});
672   SetReportId(0x21);
673   SetReportSizeAndCount(8, 31);
674   AddReportItem(dj_collection, kInput, kNonNullableArray,
675                 {kUsageVendor + 0x42});
676   AddReportItem(dj_collection, kOutput, kNonNullableArray,
677                 {kUsageVendor + 0x42});
678   ValidateCollections(kLogitechUnifyingReceiver, kLogitechUnifyingReceiverSize);
679 }
680 
TEST_F(HidReportDescriptorTest,ValidateDetails_SonyDualshock3)681 TEST_F(HidReportDescriptorTest, ValidateDetails_SonyDualshock3) {
682   auto top_info = HidCollectionInfo::New();
683   top_info->usage = HidUsageAndPage::New(mojom::kGenericDesktopJoystick,
684                                          mojom::kPageGenericDesktop);
685   ASSERT_EQ(IsProtected(*top_info->usage), false);
686   top_info->report_ids = {0x01, 0x02, 0xee, 0xef};
687   AddTopCollectionInfo(std::move(top_info));
688   ValidateDetails(true, 48, 48, 48, kSonyDualshock3, kSonyDualshock3Size);
689 }
690 
TEST_F(HidReportDescriptorTest,ValidateCollections_SonyDualshock3)691 TEST_F(HidReportDescriptorTest, ValidateCollections_SonyDualshock3) {
692   auto* top = AddTopCollection(kUsageGenericDesktopJoystick,
693                                kCollectionTypeApplication);
694   auto* joystick = AddChild(top, kUsageGenericDesktop, kCollectionTypeLogical);
695   SetReportId(0x01);
696   SetLogicalAndPhysicalBounds(0, 255, 0, 0);
697   SetReportSizeAndCount(8, 1);
698   AddReportConstant(joystick, kInput, kConstant);
699   SetLogicalAndPhysicalBounds(0, 1, 0, 1);
700   SetReportSizeAndCount(1, 19);
701   AddReportItemRange(joystick, kInput, kAbsoluteVariable, kUsageButton + 1,
702                      kUsageButton + 19);
703   SetReportSizeAndCount(1, 13);
704   AddReportConstant(joystick, kInput, kConstant);
705   auto* stick_axes =
706       AddChild(joystick, kUsageGenericDesktopPointer, kCollectionTypePhysical);
707   SetLogicalAndPhysicalBounds(0, 255, 0, 255);
708   SetReportSizeAndCount(8, 4);
709   AddReportItem(stick_axes, kInput, kAbsoluteVariable,
710                 {kUsageGenericDesktopX, kUsageGenericDesktopY,
711                  kUsageGenericDesktopZ, kUsageGenericDesktopRz});
712   SetReportSizeAndCount(8, 39);
713   AddReportItem(joystick, kInput, kAbsoluteVariable,
714                 {kUsageGenericDesktopPointer});
715   SetReportSizeAndCount(8, 48);
716   AddReportItem(joystick, kOutput, kAbsoluteVariable,
717                 {kUsageGenericDesktopPointer});
718   AddReportItem(joystick, kFeature, kAbsoluteVariable,
719                 {kUsageGenericDesktopPointer});
720   auto* report_02_collection =
721       AddChild(top, kUsageGenericDesktop, kCollectionTypeLogical);
722   SetReportId(0x02);
723   AddReportItem(report_02_collection, kFeature, kAbsoluteVariable,
724                 {kUsageGenericDesktopPointer});
725   auto* report_ee_collection =
726       AddChild(top, kUsageGenericDesktop, kCollectionTypeLogical);
727   SetReportId(0xee);
728   AddReportItem(report_ee_collection, kFeature, kAbsoluteVariable,
729                 {kUsageGenericDesktopPointer});
730   auto* report_ef_collection =
731       AddChild(top, kUsageGenericDesktop, kCollectionTypeLogical);
732   SetReportId(0xef);
733   AddReportItem(report_ef_collection, kFeature, kAbsoluteVariable,
734                 {kUsageGenericDesktopPointer});
735   ValidateCollections(kSonyDualshock3, kSonyDualshock3Size);
736 }
737 
TEST_F(HidReportDescriptorTest,ValidateDetails_SonyDualshock4)738 TEST_F(HidReportDescriptorTest, ValidateDetails_SonyDualshock4) {
739   auto top_info = HidCollectionInfo::New();
740   top_info->usage = HidUsageAndPage::New(mojom::kGenericDesktopGamePad,
741                                          mojom::kPageGenericDesktop);
742   ASSERT_EQ(IsProtected(*top_info->usage), false);
743   top_info->report_ids = {0x01, 0x05, 0x04, 0x02, 0x08, 0x10, 0x11, 0x12, 0x13,
744                           0x14, 0x15, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86,
745                           0x87, 0x88, 0x89, 0x90, 0x91, 0x92, 0x93, 0xa0, 0xa1,
746                           0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xf0, 0xf1, 0xf2, 0xa7,
747                           0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0};
748   AddTopCollectionInfo(std::move(top_info));
749   ValidateDetails(true, 63, 31, 63, kSonyDualshock4, kSonyDualshock4Size);
750 }
751 
TEST_F(HidReportDescriptorTest,ValidateCollections_SonyDualshock4)752 TEST_F(HidReportDescriptorTest, ValidateCollections_SonyDualshock4) {
753   auto* top =
754       AddTopCollection(kUsageGenericDesktopGamePad, kCollectionTypeApplication);
755   SetReportId(0x01);
756   SetLogicalAndPhysicalBounds(0, 255, 0, 0);
757   SetReportSizeAndCount(8, 4);
758   AddReportItem(top, kInput, kAbsoluteVariable,
759                 {kUsageGenericDesktopX, kUsageGenericDesktopY,
760                  kUsageGenericDesktopZ, kUsageGenericDesktopRz});
761   SetLogicalAndPhysicalBounds(0, 7, 0, 315);
762   SetUnitAndUnitExponent(kUnitDegrees, 0);
763   SetReportSizeAndCount(4, 1);
764   AddReportItem(top, kInput, kNullableAbsoluteVariable,
765                 {kUsageGenericDesktopHatSwitch});
766   SetLogicalAndPhysicalBounds(0, 1, 0, 315);
767   SetUnitAndUnitExponent(0, 0);
768   SetReportSizeAndCount(1, 14);
769   AddReportItemRange(top, kInput, kAbsoluteVariable, kUsageButton + 1,
770                      kUsageButton + 14);
771   SetLogicalAndPhysicalBounds(0, 127, 0, 315);
772   SetReportSizeAndCount(6, 1);
773   AddReportItem(top, kInput, kAbsoluteVariable, {kUsageVendor + 0x20});
774   SetLogicalAndPhysicalBounds(0, 255, 0, 315);
775   SetReportSizeAndCount(8, 2);
776   AddReportItem(top, kInput, kAbsoluteVariable,
777                 {kUsageGenericDesktopRx, kUsageGenericDesktopRy});
778   SetReportSizeAndCount(8, 54);
779   AddReportItem(top, kInput, kAbsoluteVariable, {kUsageVendor + 0x21});
780   SetReportId(0x05);
781   SetReportSizeAndCount(8, 31);
782   AddReportItem(top, kOutput, kAbsoluteVariable, {kUsageVendor + 0x22});
783   SetReportId(0x04);
784   SetReportSizeAndCount(8, 36);
785   AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor + 0x23});
786   SetReportId(0x02);
787   AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor + 0x24});
788   SetReportId(0x08);
789   SetReportSizeAndCount(8, 3);
790   AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor + 0x25});
791   SetReportId(0x10);
792   SetReportSizeAndCount(8, 4);
793   AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor + 0x26});
794   SetReportId(0x11);
795   SetReportSizeAndCount(8, 2);
796   AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor + 0x27});
797   SetReportId(0x12);
798   SetReportSizeAndCount(8, 15);
799   AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor02 + 0x21});
800   SetReportId(0x13);
801   SetReportSizeAndCount(8, 22);
802   AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor02 + 0x22});
803   SetReportId(0x14);
804   SetReportSizeAndCount(8, 16);
805   AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor05 + 0x20});
806   SetReportId(0x15);
807   SetReportSizeAndCount(8, 44);
808   AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor05 + 0x21});
809   SetReportId(0x80);
810   SetReportSizeAndCount(8, 6);
811   AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x20});
812   SetReportId(0x81);
813   AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x21});
814   SetReportId(0x82);
815   SetReportSizeAndCount(8, 5);
816   AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x22});
817   SetReportId(0x83);
818   SetReportSizeAndCount(8, 1);
819   AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x23});
820   SetReportId(0x84);
821   SetReportSizeAndCount(8, 4);
822   AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x24});
823   SetReportId(0x85);
824   SetReportSizeAndCount(8, 6);
825   AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x25});
826   SetReportId(0x86);
827   AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x26});
828   SetReportId(0x87);
829   SetReportSizeAndCount(8, 35);
830   AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x27});
831   SetReportId(0x88);
832   SetReportSizeAndCount(8, 34);
833   AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x28});
834   SetReportId(0x89);
835   SetReportSizeAndCount(8, 2);
836   AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x29});
837   SetReportId(0x90);
838   SetReportSizeAndCount(8, 5);
839   AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x30});
840   SetReportId(0x91);
841   SetReportSizeAndCount(8, 3);
842   AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x31});
843   SetReportId(0x92);
844   AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x32});
845   SetReportId(0x93);
846   SetReportSizeAndCount(8, 12);
847   AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x33});
848   SetReportId(0xa0);
849   SetReportSizeAndCount(8, 6);
850   AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x40});
851   SetReportId(0xa1);
852   SetReportSizeAndCount(8, 1);
853   AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x41});
854   SetReportId(0xa2);
855   AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x42});
856   SetReportId(0xa3);
857   SetReportSizeAndCount(8, 48);
858   AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x43});
859   SetReportId(0xa4);
860   SetReportSizeAndCount(8, 13);
861   AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x44});
862   SetReportId(0xa5);
863   SetReportSizeAndCount(8, 21);
864   AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x45});
865   SetReportId(0xa6);
866   AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x46});
867   SetReportId(0xf0);
868   SetReportSizeAndCount(8, 63);
869   AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x47});
870   SetReportId(0xf1);
871   AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x48});
872   SetReportId(0xf2);
873   SetReportSizeAndCount(8, 15);
874   AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x49});
875   SetReportId(0xa7);
876   SetReportSizeAndCount(8, 1);
877   AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x4a});
878   SetReportId(0xa8);
879   AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x4b});
880   SetReportId(0xa9);
881   SetReportSizeAndCount(8, 8);
882   AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x4c});
883   SetReportId(0xaa);
884   SetReportSizeAndCount(8, 1);
885   AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x4e});
886   SetReportId(0xab);
887   SetReportSizeAndCount(8, 57);
888   AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x4f});
889   SetReportId(0xac);
890   AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x50});
891   SetReportId(0xad);
892   SetReportSizeAndCount(8, 11);
893   AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x51});
894   SetReportId(0xae);
895   SetReportSizeAndCount(8, 1);
896   AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x52});
897   SetReportId(0xaf);
898   SetReportSizeAndCount(8, 2);
899   AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x53});
900   SetReportId(0xb0);
901   SetReportSizeAndCount(8, 63);
902   AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x54});
903   ValidateCollections(kSonyDualshock4, kSonyDualshock4Size);
904 }
905 
TEST_F(HidReportDescriptorTest,ValidateDetails_XboxWirelessController)906 TEST_F(HidReportDescriptorTest, ValidateDetails_XboxWirelessController) {
907   auto top_info = HidCollectionInfo::New();
908   top_info->usage = HidUsageAndPage::New(mojom::kGenericDesktopGamePad,
909                                          mojom::kPageGenericDesktop);
910   ASSERT_EQ(IsProtected(*top_info->usage), false);
911   top_info->report_ids = {0x01, 0x02, 0x03, 0x04};
912   AddTopCollectionInfo(std::move(top_info));
913   ValidateDetails(true, 15, 8, 0, kMicrosoftXboxWirelessController,
914                   kMicrosoftXboxWirelessControllerSize);
915 }
916 
TEST_F(HidReportDescriptorTest,ValidateCollections_XboxWirelessController)917 TEST_F(HidReportDescriptorTest, ValidateCollections_XboxWirelessController) {
918   auto* top =
919       AddTopCollection(kUsageGenericDesktopGamePad, kCollectionTypeApplication);
920   SetReportId(0x01);
921   auto* left_stick =
922       AddChild(top, kUsageGenericDesktopPointer, kCollectionTypePhysical);
923   SetLogicalAndPhysicalBounds(0, 0xffff, 0, 0);
924   SetReportSizeAndCount(16, 2);
925   AddReportItem(left_stick, kInput, kAbsoluteVariable,
926                 {kUsageGenericDesktopX, kUsageGenericDesktopY});
927   auto* right_stick =
928       AddChild(top, kUsageGenericDesktopPointer, kCollectionTypePhysical);
929   SetLogicalAndPhysicalBounds(0, 0xffff, 0, 0);
930   AddReportItem(right_stick, kInput, kAbsoluteVariable,
931                 {kUsageGenericDesktopRx, kUsageGenericDesktopRy});
932   SetLogicalAndPhysicalBounds(0, 1023, 0, 0);
933   SetReportSizeAndCount(10, 1);
934   AddReportItem(top, kInput, kAbsoluteVariable, {kUsageGenericDesktopZ});
935   SetLogicalAndPhysicalBounds(0, 0, 0, 0);
936   SetReportSizeAndCount(6, 1);
937   AddReportConstant(top, kInput, kConstant);
938   SetLogicalAndPhysicalBounds(0, 1023, 0, 0);
939   SetReportSizeAndCount(10, 1);
940   AddReportItem(top, kInput, kAbsoluteVariable, {kUsageGenericDesktopRz});
941   SetLogicalAndPhysicalBounds(0, 0, 0, 0);
942   SetReportSizeAndCount(6, 1);
943   AddReportConstant(top, kInput, kConstant);
944   SetLogicalAndPhysicalBounds(1, 8, 0, 315);
945   SetUnitAndUnitExponent(kUnitDegrees, 0);
946   SetReportSizeAndCount(4, 1);
947   AddReportItem(top, kInput, kNullableAbsoluteVariable,
948                 {kUsageGenericDesktopHatSwitch});
949   SetLogicalAndPhysicalBounds(0, 0, 0, 0);
950   SetUnitAndUnitExponent(0, 0);
951   AddReportConstant(top, kInput, kConstant);
952   SetLogicalAndPhysicalBounds(0, 1, 0, 0);
953   SetReportSizeAndCount(1, 10);
954   AddReportItemRange(top, kInput, kAbsoluteVariable, kUsageButton + 1,
955                      kUsageButton + 10);
956   SetLogicalAndPhysicalBounds(0, 0, 0, 0);
957   SetReportSizeAndCount(6, 1);
958   AddReportConstant(top, kInput, kConstant);
959   SetReportId(0x02);
960   auto* mode_collection =
961       AddChild(top, kUsageGenericDesktopSystemControl, kCollectionTypePhysical);
962   SetLogicalAndPhysicalBounds(0, 1, 0, 0);
963   SetReportSizeAndCount(1, 1);
964   AddReportItem(mode_collection, kInput, kAbsoluteVariable,
965                 {kUsageGenericDesktopSystemMainMenu});
966   SetLogicalAndPhysicalBounds(0, 0, 0, 0);
967   SetReportSizeAndCount(7, 1);
968   AddReportConstant(mode_collection, kInput, kConstant);
969   SetReportId(0x03);
970   auto* pid_collection =
971       AddChild(top, kUsagePidSetEffectReport, kCollectionTypeLogical);
972   SetLogicalAndPhysicalBounds(0, 1, 0, 0);
973   SetReportSizeAndCount(4, 1);
974   AddReportItem(pid_collection, kOutput, kAbsoluteVariable,
975                 {kUsagePidDCEnableActuators});
976   SetLogicalAndPhysicalBounds(0, 0, 0, 0);
977   AddReportConstant(pid_collection, kOutput, kConstant);
978   SetLogicalAndPhysicalBounds(0, 100, 0, 0);
979   SetReportSizeAndCount(8, 4);
980   AddReportItem(pid_collection, kOutput, kAbsoluteVariable,
981                 {kUsagePidMagnitude});
982   SetLogicalAndPhysicalBounds(0, 255, 0, 0);
983   SetUnitAndUnitExponent(kUnitSecond, 0x0e);
984   SetReportSizeAndCount(8, 1);
985   AddReportItem(pid_collection, kOutput, kAbsoluteVariable,
986                 {kUsagePidDuration});
987   AddReportItem(pid_collection, kOutput, kAbsoluteVariable,
988                 {kUsagePidStartDelay});
989   SetUnitAndUnitExponent(0, 0);
990   AddReportItem(pid_collection, kOutput, kAbsoluteVariable,
991                 {kUsagePidLoopCount});
992   SetReportId(0x04);
993   AddReportItem(top, kInput, kAbsoluteVariable,
994                 {kUsageGenericDeviceBatteryStrength});
995   ValidateCollections(kMicrosoftXboxWirelessController,
996                       kMicrosoftXboxWirelessControllerSize);
997 }
998 
TEST_F(HidReportDescriptorTest,ValidateDetails_NintendoSwitchProController)999 TEST_F(HidReportDescriptorTest, ValidateDetails_NintendoSwitchProController) {
1000   auto top_info = HidCollectionInfo::New();
1001   top_info->usage = HidUsageAndPage::New(mojom::kGenericDesktopJoystick,
1002                                          mojom::kPageGenericDesktop);
1003   ASSERT_EQ(IsProtected(*top_info->usage), false);
1004   top_info->report_ids = {0x30, 0x21, 0x81, 0x01, 0x10, 0x80, 0x82};
1005   AddTopCollectionInfo(std::move(top_info));
1006   ValidateDetails(true, 63, 63, 0, kNintendoSwitchProController,
1007                   kNintendoSwitchProControllerSize);
1008 }
1009 
TEST_F(HidReportDescriptorTest,ValidateCollections_NintendoSwitchProController)1010 TEST_F(HidReportDescriptorTest,
1011        ValidateCollections_NintendoSwitchProController) {
1012   auto* top = AddTopCollection(kUsageGenericDesktopJoystick,
1013                                kCollectionTypeApplication);
1014   SetReportId(0x30);
1015   SetLogicalAndPhysicalBounds(0, 1, 0, 0);
1016   SetUnitAndUnitExponent(0, 0);
1017   SetReportSizeAndCount(1, 10);
1018   AddReportItemRange(top, kInput, kAbsoluteVariable, kUsageButton + 1,
1019                      kUsageButton + 10);
1020   SetReportSizeAndCount(1, 4);
1021   AddReportItemRange(top, kInput, kAbsoluteVariable, kUsageButton + 11,
1022                      kUsageButton + 14);
1023   SetReportSizeAndCount(1, 2);
1024   AddReportConstant(top, kInput, kConstant);
1025   auto* stick_axes =
1026       AddChild(top, kUsageGenericDesktopPointer, kCollectionTypePhysical);
1027   SetLogicalAndPhysicalBounds(0, 0xffff, 0, 0);
1028   SetReportSizeAndCount(16, 4);
1029   AddReportItem(stick_axes, kInput, kAbsoluteVariable,
1030                 {kUsageGenericDesktopX, kUsageGenericDesktopY,
1031                  kUsageGenericDesktopZ, kUsageGenericDesktopRz});
1032   SetLogicalAndPhysicalBounds(0, 7, 0, 315);
1033   SetUnitAndUnitExponent(kUnitDegrees, 0);
1034   SetReportSizeAndCount(4, 1);
1035   AddReportItem(top, kInput, kAbsoluteVariable,
1036                 {kUsageGenericDesktopHatSwitch});
1037   SetLogicalAndPhysicalBounds(0, 1, 0, 315);
1038   SetReportSizeAndCount(1, 4);
1039   AddReportItemRange(top, kInput, kAbsoluteVariable, kUsageButton + 15,
1040                      kUsageButton + 18);
1041   SetReportSizeAndCount(8, 52);
1042   AddReportConstant(top, kInput, kConstant);
1043   SetReportId(0x21);
1044   SetReportSizeAndCount(8, 63);
1045   AddReportItem(top, kInput, kConstant, {kUsageVendor + 0x01});
1046   SetReportId(0x81);
1047   AddReportItem(top, kInput, kConstant, {kUsageVendor + 0x02});
1048   SetReportId(0x01);
1049   AddReportItem(top, kOutput, kVolatileConstant, {kUsageVendor + 0x03});
1050   SetReportId(0x10);
1051   AddReportItem(top, kOutput, kVolatileConstant, {kUsageVendor + 0x04});
1052   SetReportId(0x80);
1053   AddReportItem(top, kOutput, kVolatileConstant, {kUsageVendor + 0x05});
1054   SetReportId(0x82);
1055   AddReportItem(top, kOutput, kVolatileConstant, {kUsageVendor + 0x06});
1056   ValidateCollections(kNintendoSwitchProController,
1057                       kNintendoSwitchProControllerSize);
1058 }
1059 
TEST_F(HidReportDescriptorTest,ValidateDetails_XboxAdaptiveController)1060 TEST_F(HidReportDescriptorTest, ValidateDetails_XboxAdaptiveController) {
1061   auto gamepad_info = HidCollectionInfo::New();
1062   gamepad_info->usage = HidUsageAndPage::New(mojom::kGenericDesktopGamePad,
1063                                              mojom::kPageGenericDesktop);
1064   ASSERT_EQ(IsProtected(*gamepad_info->usage), false);
1065   gamepad_info->report_ids = {0x01, 0x02, 0x03, 0x04, 0x06,
1066                               0x07, 0x08, 0x09, 0x0a, 0x0b};
1067   auto keyboard_info = HidCollectionInfo::New();
1068   keyboard_info->usage = HidUsageAndPage::New(mojom::kGenericDesktopKeyboard,
1069                                               mojom::kPageGenericDesktop);
1070   ASSERT_EQ(IsProtected(*keyboard_info->usage), true);
1071   keyboard_info->report_ids = {0x05};
1072   AddTopCollectionInfo(std::move(gamepad_info));
1073   AddTopCollectionInfo(std::move(keyboard_info));
1074   ValidateDetails(true, 54, 8, 64, kMicrosoftXboxAdaptiveController,
1075                   kMicrosoftXboxAdaptiveControllerSize);
1076 }
1077 
TEST_F(HidReportDescriptorTest,ValidateCollections_XboxAdaptiveController)1078 TEST_F(HidReportDescriptorTest, ValidateCollections_XboxAdaptiveController) {
1079   auto* gamepad =
1080       AddTopCollection(kUsageGenericDesktopGamePad, kCollectionTypeApplication);
1081   SetReportId(0x01);
1082   auto* left_stick =
1083       AddChild(gamepad, kUsageGenericDesktopPointer, kCollectionTypePhysical);
1084   SetLogicalAndPhysicalBounds(0, 0xffff, 0, 0);
1085   SetReportSizeAndCount(16, 2);
1086   AddReportItem(left_stick, kInput, kAbsoluteVariable,
1087                 {kUsageGenericDesktopX, kUsageGenericDesktopY});
1088   auto* right_stick =
1089       AddChild(gamepad, kUsageGenericDesktopPointer, kCollectionTypePhysical);
1090   AddReportItem(right_stick, kInput, kAbsoluteVariable,
1091                 {kUsageGenericDesktopZ, kUsageGenericDesktopRz});
1092   SetLogicalAndPhysicalBounds(0, 1023, 0, 0);
1093   SetReportSizeAndCount(10, 1);
1094   AddReportItem(gamepad, kInput, kAbsoluteVariable, {kUsageSimulationBrake});
1095   SetLogicalAndPhysicalBounds(0, 0, 0, 0);
1096   SetReportSizeAndCount(6, 1);
1097   AddReportConstant(gamepad, kInput, kConstant);
1098   SetLogicalAndPhysicalBounds(0, 1023, 0, 0);
1099   SetReportSizeAndCount(10, 1);
1100   AddReportItem(gamepad, kInput, kAbsoluteVariable,
1101                 {kUsageSimulationAccelerator});
1102   SetLogicalAndPhysicalBounds(0, 0, 0, 0);
1103   SetReportSizeAndCount(6, 1);
1104   AddReportConstant(gamepad, kInput, kConstant);
1105   SetLogicalAndPhysicalBounds(1, 8, 0, 315);
1106   SetUnitAndUnitExponent(kUnitDegrees, 0);
1107   SetReportSizeAndCount(4, 1);
1108   AddReportItem(gamepad, kInput, kNullableAbsoluteVariable,
1109                 {kUsageGenericDesktopHatSwitch});
1110   SetLogicalAndPhysicalBounds(0, 0, 0, 0);
1111   SetUnitAndUnitExponent(0, 0);
1112   AddReportConstant(gamepad, kInput, kConstant);
1113   SetLogicalAndPhysicalBounds(0, 1, 0, 0);
1114   SetReportSizeAndCount(1, 15);
1115   AddReportItemRange(gamepad, kInput, kAbsoluteVariable, kUsageButton + 1,
1116                      kUsageButton + 15);
1117   SetLogicalAndPhysicalBounds(0, 0, 0, 0);
1118   SetReportSizeAndCount(1, 1);
1119   AddReportConstant(gamepad, kInput, kConstant);
1120   SetLogicalAndPhysicalBounds(0, 1, 0, 0);
1121   AddReportItem(gamepad, kInput, kAbsoluteVariable, {kUsageConsumerACBack});
1122   SetLogicalAndPhysicalBounds(0, 0, 0, 0);
1123   SetReportSizeAndCount(7, 1);
1124   AddReportConstant(gamepad, kInput, kConstant);
1125   auto* left_stick2 =
1126       AddChild(gamepad, kUsageGenericDesktopPointer, kCollectionTypePhysical);
1127   SetLogicalAndPhysicalBounds(0, 0xffff, 0, 0);
1128   SetReportSizeAndCount(16, 2);
1129   AddReportItem(left_stick2, kInput, kAbsoluteVariable,
1130                 {kUsageGenericDesktopVx, kUsageGenericDesktopVy});
1131   auto* right_stick2 =
1132       AddChild(gamepad, kUsageGenericDesktopPointer, kCollectionTypePhysical);
1133   SetLogicalAndPhysicalBounds(0, 0xffff, 0, 0);
1134   AddReportItem(right_stick2, kInput, kAbsoluteVariable,
1135                 {kUsageGenericDesktopVbrx, kUsageGenericDesktopVbry});
1136   SetLogicalAndPhysicalBounds(0, 1023, 0, 0);
1137   SetReportSizeAndCount(10, 1);
1138   AddReportItem(gamepad, kInput, kAbsoluteVariable, {kUsageGenericDesktopVz});
1139   SetLogicalAndPhysicalBounds(0, 0, 0, 0);
1140   SetReportSizeAndCount(6, 1);
1141   AddReportConstant(gamepad, kInput, kConstant);
1142   SetLogicalAndPhysicalBounds(0, 1023, 0, 0);
1143   SetReportSizeAndCount(10, 1);
1144   AddReportItem(gamepad, kInput, kAbsoluteVariable, {kUsageGenericDesktopVbrz});
1145   SetLogicalAndPhysicalBounds(0, 0, 0, 0);
1146   SetReportSizeAndCount(6, 1);
1147   AddReportConstant(gamepad, kInput, kConstant);
1148   SetLogicalAndPhysicalBounds(1, 8, 0, 315);
1149   SetUnitAndUnitExponent(kUnitDegrees, 0);
1150   SetReportSizeAndCount(4, 1);
1151   AddReportItem(gamepad, kInput, kNullableAbsoluteVariable,
1152                 {kUsageGenericDesktopDial});
1153   SetLogicalAndPhysicalBounds(0, 0, 0, 0);
1154   SetUnitAndUnitExponent(0, 0);
1155   AddReportConstant(gamepad, kInput, kConstant);
1156   SetLogicalAndPhysicalBounds(0, 1, 0, 0);
1157   SetReportSizeAndCount(1, 15);
1158   AddReportItemRange(gamepad, kInput, kAbsoluteVariable, kUsageButton + 16,
1159                      kUsageButton + 30);
1160   SetLogicalAndPhysicalBounds(0, 0, 0, 0);
1161   SetReportSizeAndCount(1, 1);
1162   AddReportConstant(gamepad, kInput, kConstant);
1163   SetLogicalAndPhysicalBounds(0, 1, 0, 0);
1164   AddReportItem(gamepad, kInput, kAbsoluteVariable, {kUsageConsumerModeStep});
1165   SetLogicalAndPhysicalBounds(0, 0, 0, 0);
1166   SetReportSizeAndCount(7, 1);
1167   AddReportConstant(gamepad, kInput, kConstant);
1168   auto* consumer_collection =
1169       AddChild(gamepad, kUsageConsumerControl, kCollectionTypeApplication);
1170   SetLogicalAndPhysicalBounds(0, 255, 0, 0);
1171   SetReportSizeAndCount(4, 1);
1172   AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
1173                 {kUsageConsumer + 0x81});
1174   SetLogicalAndPhysicalBounds(0, 0, 0, 0);
1175   AddReportConstant(consumer_collection, kInput, kConstant);
1176   SetLogicalAndPhysicalBounds(0, 255, 0, 0);
1177   AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
1178                 {kUsageConsumer + 0x84});
1179   SetLogicalAndPhysicalBounds(0, 0, 0, 0);
1180   AddReportConstant(consumer_collection, kInput, kConstant);
1181   SetLogicalAndPhysicalBounds(0, 255, 0, 0);
1182   SetReportSizeAndCount(8, 1);
1183   AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
1184                 {kUsageConsumer + 0x85});
1185   SetReportSizeAndCount(4, 1);
1186   AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
1187                 {kUsageConsumer + 0x99});
1188   SetLogicalAndPhysicalBounds(0, 0, 0, 0);
1189   AddReportConstant(consumer_collection, kInput, kConstant);
1190   SetLogicalAndPhysicalBounds(0, 255, 0, 0);
1191   SetReportSizeAndCount(8, 1);
1192   AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
1193                 {kUsageConsumer + 0x9e});
1194   AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
1195                 {kUsageConsumer + 0xa1});
1196   AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
1197                 {kUsageConsumer + 0xa2});
1198   AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
1199                 {kUsageConsumer + 0xa3});
1200   AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
1201                 {kUsageConsumer + 0xa4});
1202   AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
1203                 {kUsageConsumer + 0xb9});
1204   AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
1205                 {kUsageConsumer + 0xba});
1206   AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
1207                 {kUsageConsumer + 0xbb});
1208   AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
1209                 {kUsageConsumer + 0xbe});
1210   AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
1211                 {kUsageConsumer + 0xc0});
1212   AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
1213                 {kUsageConsumer + 0xc1});
1214   AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
1215                 {kUsageConsumer + 0xc2});
1216   AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
1217                 {kUsageConsumer + 0xc3});
1218   AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
1219                 {kUsageConsumer + 0xc4});
1220   AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
1221                 {kUsageConsumer + 0xc5});
1222   AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
1223                 {kUsageConsumer + 0xc6});
1224   AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
1225                 {kUsageConsumer + 0xc7});
1226   AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
1227                 {kUsageConsumer + 0xc8});
1228   SetReportId(0x02);
1229   auto* mode_collection =
1230       AddChild(gamepad, kUsageConsumerControl, kCollectionTypeApplication);
1231   SetLogicalAndPhysicalBounds(0, 1, 0, 0);
1232   SetReportSizeAndCount(1, 1);
1233   AddReportItem(mode_collection, kInput, kAbsoluteVariable,
1234                 {kUsageConsumerACHome});
1235   SetLogicalAndPhysicalBounds(0, 0, 0, 0);
1236   SetReportSizeAndCount(7, 1);
1237   AddReportConstant(mode_collection, kInput, kConstant);
1238   SetReportId(0x03);
1239   auto* pid_collection =
1240       AddChild(gamepad, kUsagePidSetEffectReport, kCollectionTypeLogical);
1241   SetLogicalAndPhysicalBounds(0, 1, 0, 0);
1242   SetReportSizeAndCount(4, 1);
1243   AddReportItem(pid_collection, kOutput, kAbsoluteVariable,
1244                 {kUsagePidDCEnableActuators});
1245   SetLogicalAndPhysicalBounds(0, 0, 0, 0);
1246   AddReportConstant(pid_collection, kOutput, kConstant);
1247   SetLogicalAndPhysicalBounds(0, 100, 0, 0);
1248   SetReportSizeAndCount(8, 4);
1249   AddReportItem(pid_collection, kOutput, kAbsoluteVariable,
1250                 {kUsagePidMagnitude});
1251   SetLogicalAndPhysicalBounds(0, 255, 0, 0);
1252   SetUnitAndUnitExponent(kUnitSecond, 0x0e);
1253   SetReportSizeAndCount(8, 1);
1254   AddReportItem(pid_collection, kOutput, kAbsoluteVariable,
1255                 {kUsagePidDuration});
1256   AddReportItem(pid_collection, kOutput, kAbsoluteVariable,
1257                 {kUsagePidStartDelay});
1258   SetUnitAndUnitExponent(0, 0);
1259   AddReportItem(pid_collection, kOutput, kAbsoluteVariable,
1260                 {kUsagePidLoopCount});
1261   SetReportId(0x04);
1262   AddReportItem(gamepad, kInput, kAbsoluteVariable,
1263                 {kUsageGenericDeviceBatteryStrength});
1264   SetReportId(0x06);
1265   auto* report_06_collection =
1266       AddChild(gamepad, kUsageVendor + 0x01, kCollectionTypeLogical);
1267   SetLogicalAndPhysicalBounds(0, 100, 0, 0);
1268   AddReportItem(report_06_collection, kFeature, kAbsoluteVariable,
1269                 {kUsageVendor + 0x01});
1270   AddReportItem(report_06_collection, kFeature, kAbsoluteVariable,
1271                 {kUsageVendor + 0x02});
1272   SetLogicalAndPhysicalBounds(0, 255, 0, 0);
1273   AddReportItem(report_06_collection, kFeature, kAbsoluteVariable,
1274                 {kUsageVendor + 0x03});
1275   SetReportSizeAndCount(8, 60);
1276   AddReportItem(report_06_collection, kFeature, kBufferedBytes,
1277                 {kUsageVendor + 0x04});
1278   SetReportId(0x07);
1279   auto* report_07_collection =
1280       AddChild(gamepad, kUsageVendor + 0x02, kCollectionTypeLogical);
1281   SetLogicalAndPhysicalBounds(0, 100, 0, 0);
1282   SetReportSizeAndCount(8, 1);
1283   AddReportItem(report_07_collection, kFeature, kAbsoluteVariable,
1284                 {kUsageVendor + 0x05});
1285   AddReportItem(report_07_collection, kFeature, kAbsoluteVariable,
1286                 {kUsageVendor + 0x06});
1287   AddReportItem(report_07_collection, kFeature, kAbsoluteVariable,
1288                 {kUsageVendor + 0x07});
1289   SetReportId(0x08);
1290   auto* report_08_collection =
1291       AddChild(gamepad, kUsageVendor + 0x03, kCollectionTypeLogical);
1292   AddReportItem(report_08_collection, kFeature, kAbsoluteVariable,
1293                 {kUsageVendor + 0x08});
1294   AddReportItem(report_08_collection, kFeature, kAbsoluteVariable,
1295                 {kUsageVendor + 0x09});
1296   SetLogicalAndPhysicalBounds(0, 255, 0, 0);
1297   AddReportItem(report_08_collection, kFeature, kAbsoluteVariable,
1298                 {kUsageVendor + 0x0a});
1299   SetReportId(0x09);
1300   auto* report_09_collection =
1301       AddChild(gamepad, kUsageVendor + 0x04, kCollectionTypeApplication);
1302   SetLogicalAndPhysicalBounds(0, 100, 0, 0);
1303   AddReportItem(report_09_collection, kFeature, kAbsoluteVariable,
1304                 {kUsageVendor + 0x0b});
1305   AddReportItem(report_09_collection, kFeature, kAbsoluteVariable,
1306                 {kUsageVendor + 0x0c});
1307   AddReportItem(report_09_collection, kFeature, kAbsoluteVariable,
1308                 {kUsageVendor + 0x0d});
1309   SetLogicalAndPhysicalBounds(0, 255, 0, 0);
1310   AddReportItem(report_09_collection, kFeature, kAbsoluteVariable,
1311                 {kUsageVendor + 0x0e});
1312   SetReportSizeAndCount(8, 60);
1313   AddReportItem(report_09_collection, kFeature, kBufferedBytes,
1314                 {kUsageVendor + 0x0f});
1315   SetReportId(0x0a);
1316   auto* report_0a_collection =
1317       AddChild(gamepad, kUsageVendor + 0x05, kCollectionTypeApplication);
1318   SetLogicalAndPhysicalBounds(0, 0x7fffffff, 0, 0);
1319   SetReportSizeAndCount(32, 1);
1320   AddReportItem(report_0a_collection, kInput, kAbsoluteVariable,
1321                 {kUsageVendor + 0x10});
1322   AddReportItem(report_0a_collection, kInput, kAbsoluteVariable,
1323                 {kUsageVendor + 0x11});
1324   SetLogicalAndPhysicalBounds(0, 255, 0, 0);
1325   SetReportSizeAndCount(8, 2);
1326   AddReportItem(report_0a_collection, kInput, kAbsoluteVariable,
1327                 {kUsageVendor + 0x12});
1328   SetReportSizeAndCount(8, 1);
1329   AddReportItem(report_0a_collection, kInput, kAbsoluteVariable,
1330                 {kUsageVendor + 0x13});
1331   SetReportId(0x0b);
1332   auto* report_0b_collection =
1333       AddChild(gamepad, kUsageVendor + 0x06, kCollectionTypeLogical);
1334   SetLogicalAndPhysicalBounds(0, 100, 0, 0);
1335 
1336   AddReportItem(report_0b_collection, kFeature, kAbsoluteVariable,
1337                 {kUsageVendor + 0x14});
1338   SetReportId(0x05);
1339   auto* keyboard = AddTopCollection(kUsageGenericDesktopKeyboard,
1340                                     kCollectionTypeApplication);
1341   SetLogicalAndPhysicalBounds(0, 1, 0, 0);
1342   SetReportSizeAndCount(1, 8);
1343   AddReportItemRange(keyboard, kInput, kAbsoluteVariable,
1344                      kUsageKeyboardLeftControl, kUsageKeyboardRightGui);
1345   SetReportSizeAndCount(8, 1);
1346   AddReportConstant(keyboard, kInput, kConstant);
1347   SetLogicalAndPhysicalBounds(0, 101, 0, 0);
1348   SetReportSizeAndCount(8, 6);
1349   AddReportItemRange(keyboard, kInput, kNonNullableArray, kUsageKeyboard,
1350                      kUsageKeyboardApplication);
1351   ValidateCollections(kMicrosoftXboxAdaptiveController,
1352                       kMicrosoftXboxAdaptiveControllerSize);
1353 }
1354 
TEST_F(HidReportDescriptorTest,ValidateDetails_NexusPlayerController)1355 TEST_F(HidReportDescriptorTest, ValidateDetails_NexusPlayerController) {
1356   auto gamepad_info = HidCollectionInfo::New();
1357   gamepad_info->usage = HidUsageAndPage::New(mojom::kGenericDesktopGamePad,
1358                                              mojom::kPageGenericDesktop);
1359   ASSERT_EQ(IsProtected(*gamepad_info->usage), false);
1360   gamepad_info->report_ids = {0x01, 0x02};
1361   auto status_info = HidCollectionInfo::New();
1362   status_info->usage = HidUsageAndPage::New(mojom::kGenericDesktopGamePad,
1363                                             mojom::kPageGenericDesktop);
1364   ASSERT_EQ(IsProtected(*status_info->usage), false);
1365   status_info->report_ids = {0x03};
1366   AddTopCollectionInfo(std::move(gamepad_info));
1367   AddTopCollectionInfo(std::move(status_info));
1368   ValidateDetails(true, 8, 1, 0, kNexusPlayerController,
1369                   kNexusPlayerControllerSize);
1370 }
1371 
TEST_F(HidReportDescriptorTest,ValidateCollections_NexusPlayerController)1372 TEST_F(HidReportDescriptorTest, ValidateCollections_NexusPlayerController) {
1373   auto* gamepad =
1374       AddTopCollection(kUsageGenericDesktopGamePad, kCollectionTypeApplication);
1375   SetReportId(0x01);
1376   SetLogicalAndPhysicalBounds(0, 1, 0, 0);
1377   SetReportSizeAndCount(1, 11);
1378   AddReportItem(
1379       gamepad, kInput, kAbsoluteVariable,
1380       {kUsageButton + 1, kUsageButton + 2, kUsageButton + 4, kUsageButton + 5,
1381        kUsageButton + 7, kUsageButton + 8, kUsageButton + 14, kUsageButton + 15,
1382        kUsageButton + 13, kUsageConsumerACBack, kUsageConsumerACHome});
1383   SetReportSizeAndCount(1, 1);
1384   AddReportConstant(gamepad, kInput, kConstant);
1385   SetLogicalAndPhysicalBounds(0, 7, 0, 315);
1386   SetUnitAndUnitExponent(kUnitDegrees, 0);
1387   SetReportSizeAndCount(4, 1);
1388   AddReportItem(gamepad, kInput, kNullableAbsoluteVariable,
1389                 {kUsageGenericDesktopHatSwitch});
1390   SetUnitAndUnitExponent(0, 0);
1391   auto* axes_collection =
1392       AddChild(gamepad, kUsageGenericDesktop, kCollectionTypePhysical);
1393   SetLogicalAndPhysicalBounds(0, 255, 0, 255);
1394   SetReportSizeAndCount(8, 6);
1395   AddReportItem(axes_collection, kInput, kAbsoluteVariable,
1396                 {kUsageGenericDesktopX, kUsageGenericDesktopY,
1397                  kUsageGenericDesktopZ, kUsageGenericDesktopRz,
1398                  kUsageSimulationBrake, kUsageSimulationAccelerator});
1399   SetReportId(0x02);
1400   SetLogicalAndPhysicalBounds(0, 1, 0, 255);
1401   SetReportSizeAndCount(1, 4);
1402   AddReportItem(gamepad, kOutput, kAbsoluteVariable,
1403                 {kUsageLedNumLock, kUsageLedCapsLock, kUsageLedScrollLock,
1404                  kUsageLedCompose});
1405   SetReportSizeAndCount(4, 1);
1406   AddReportConstant(gamepad, kOutput, kConstant);
1407   SetReportId(0x03);
1408   auto* status =
1409       AddTopCollection(kUsageGenericDesktopGamePad, kCollectionTypeApplication);
1410   SetLogicalAndPhysicalBounds(0, 255, 0, 255);
1411   SetReportSizeAndCount(8, 1);
1412   AddReportItem(status, kInput, kAbsoluteVariable,
1413                 {kUsageGenericDeviceBatteryStrength});
1414   SetReportSizeAndCount(8, 6);
1415   AddReportItem(status, kInput, kAbsoluteVariable, {0xffbcbdad});
1416   ValidateCollections(kNexusPlayerController, kNexusPlayerControllerSize);
1417 }
1418 
TEST_F(HidReportDescriptorTest,ValidateDetails_SteamControllerKeyboard)1419 TEST_F(HidReportDescriptorTest, ValidateDetails_SteamControllerKeyboard) {
1420   auto info = HidCollectionInfo::New();
1421   info->usage = HidUsageAndPage::New(mojom::kGenericDesktopKeyboard,
1422                                      mojom::kPageGenericDesktop);
1423   ASSERT_EQ(IsProtected(*info->usage), true);
1424   AddTopCollectionInfo(std::move(info));
1425   ValidateDetails(false, 8, 1, 0, kSteamControllerKeyboard,
1426                   kSteamControllerKeyboardSize);
1427 }
1428 
TEST_F(HidReportDescriptorTest,ValidateCollections_SteamControllerKeyboard)1429 TEST_F(HidReportDescriptorTest, ValidateCollections_SteamControllerKeyboard) {
1430   auto* top = AddTopCollection(kUsageGenericDesktopKeyboard,
1431                                kCollectionTypeApplication);
1432   SetLogicalAndPhysicalBounds(0, 1, 0, 0);
1433   SetReportSizeAndCount(1, 8);
1434   AddReportItemRange(top, kInput, kAbsoluteVariable, kUsageKeyboardLeftControl,
1435                      kUsageKeyboardRightGui);
1436   SetReportSizeAndCount(8, 1);
1437   AddReportConstant(top, kInput, kConstantArray);
1438   SetReportSizeAndCount(1, 5);
1439   AddReportItemRange(top, kOutput, kAbsoluteVariable, kUsageLedNumLock,
1440                      kUsageLedKana);
1441   SetReportSizeAndCount(3, 1);
1442   AddReportConstant(top, kOutput, kConstantArray);
1443   SetReportSizeAndCount(8, 6);
1444   SetLogicalAndPhysicalBounds(0, 101, 0, 0);
1445   AddReportItemRange(top, kInput, kNonNullableArray, kUsageKeyboard,
1446                      kUsageKeyboardApplication);
1447   ValidateCollections(kSteamControllerKeyboard, kSteamControllerKeyboardSize);
1448 }
1449 
TEST_F(HidReportDescriptorTest,ValidateDetails_SteamControllerMouse)1450 TEST_F(HidReportDescriptorTest, ValidateDetails_SteamControllerMouse) {
1451   auto info = HidCollectionInfo::New();
1452   info->usage = HidUsageAndPage::New(mojom::kGenericDesktopMouse,
1453                                      mojom::kPageGenericDesktop);
1454   ASSERT_EQ(IsProtected(*info->usage), true);
1455   AddTopCollectionInfo(std::move(info));
1456   ValidateDetails(false, 4, 0, 0, kSteamControllerMouse,
1457                   kSteamControllerMouseSize);
1458 }
1459 
TEST_F(HidReportDescriptorTest,ValidateCollections_SteamControllerMouse)1460 TEST_F(HidReportDescriptorTest, ValidateCollections_SteamControllerMouse) {
1461   auto* top =
1462       AddTopCollection(kUsageGenericDesktopMouse, kCollectionTypeApplication);
1463   auto* pointer =
1464       AddChild(top, kUsageGenericDesktopPointer, kCollectionTypePhysical);
1465   SetLogicalAndPhysicalBounds(0, 1, 0, 0);
1466   SetReportSizeAndCount(1, 5);
1467   AddReportItemRange(pointer, kInput, kAbsoluteVariable, kUsageButton + 1,
1468                      kUsageButton + 5);
1469   SetReportSizeAndCount(3, 1);
1470   AddReportConstant(pointer, kInput, kConstantArray);
1471   SetLogicalAndPhysicalBounds(0x81, 0x7f, 0, 0);
1472   SetReportSizeAndCount(8, 3);
1473   AddReportItem(pointer, kInput, kRelativeVariable,
1474                 {kUsageGenericDesktopX, kUsageGenericDesktopY,
1475                  kUsageGenericDesktopWheel});
1476   ValidateCollections(kSteamControllerMouse, kSteamControllerMouseSize);
1477 }
1478 
TEST_F(HidReportDescriptorTest,ValidateDetails_SteamControllerVendor)1479 TEST_F(HidReportDescriptorTest, ValidateDetails_SteamControllerVendor) {
1480   auto info = HidCollectionInfo::New();
1481   info->usage = HidUsageAndPage::New(0x01, mojom::kPageVendor);
1482   ASSERT_EQ(IsProtected(*info->usage), false);
1483   AddTopCollectionInfo(std::move(info));
1484   ValidateDetails(false, 64, 64, 64, kSteamControllerVendor,
1485                   kSteamControllerVendorSize);
1486 }
1487 
TEST_F(HidReportDescriptorTest,ValidateCollections_SteamControllerVendor)1488 TEST_F(HidReportDescriptorTest, ValidateCollections_SteamControllerVendor) {
1489   auto* top = AddTopCollection(kUsageVendor + 0x01, kCollectionTypeApplication);
1490   SetLogicalAndPhysicalBounds(0, 255, 0, 0);
1491   SetReportSizeAndCount(8, 64);
1492   AddReportItem(top, kInput, kAbsoluteVariable, {kUsageVendor + 0x01});
1493   AddReportItem(top, kOutput, kAbsoluteVariable, {kUsageVendor + 0x01});
1494   AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor + 0x01});
1495   ValidateCollections(kSteamControllerVendor, kSteamControllerVendorSize);
1496 }
1497 
TEST_F(HidReportDescriptorTest,ValidateDetails_XSkillsUsbAdapter)1498 TEST_F(HidReportDescriptorTest, ValidateDetails_XSkillsUsbAdapter) {
1499   auto info = HidCollectionInfo::New();
1500   info->usage = HidUsageAndPage::New(mojom::kGenericDesktopJoystick,
1501                                      mojom::kPageGenericDesktop);
1502   ASSERT_EQ(IsProtected(*info->usage), false);
1503   AddTopCollectionInfo(std::move(info));
1504   ValidateDetails(false, 7, 4, 0, kXSkillsUsbAdapter, kXSkillsUsbAdapterSize);
1505 }
1506 
TEST_F(HidReportDescriptorTest,ValidateCollections_XSkillsUsbAdapter)1507 TEST_F(HidReportDescriptorTest, ValidateCollections_XSkillsUsbAdapter) {
1508   auto* top = AddTopCollection(kUsageGenericDesktopJoystick,
1509                                kCollectionTypeApplication);
1510   SetLogicalAndPhysicalBounds(0, 1, 0, 1);
1511   SetReportSizeAndCount(1, 12);
1512   AddReportItemRange(top, kInput, kAbsoluteVariable, kUsageButton + 1,
1513                      kUsageButton + 12);
1514   SetReportSizeAndCount(1, 4);
1515   AddReportConstant(top, kInput, kConstant);
1516   SetLogicalAndPhysicalBounds(0, 255, 0, 255);
1517   SetReportSizeAndCount(8, 4);
1518   AddReportItem(top, kInput, kAbsoluteVariable,
1519                 {kUsageGenericDesktopX, kUsageGenericDesktopY,
1520                  kUsageGenericDesktopRz, kUsageGenericDesktopZ});
1521   SetLogicalAndPhysicalBounds(0, 15, 0, 15);
1522   SetReportSizeAndCount(4, 2);
1523   AddReportItem(top, kInput, kAbsoluteVariable,
1524                 {kUsageGenericDesktopRx, kUsageGenericDesktopRy});
1525   SetReportSizeAndCount(8, 4);
1526   AddReportItemRange(top, kOutput, kAbsoluteVariable, kUsageVendor + 0x01,
1527                      kUsageVendor + 0x04);
1528   ValidateCollections(kXSkillsUsbAdapter, kXSkillsUsbAdapterSize);
1529 }
1530 
TEST_F(HidReportDescriptorTest,ValidateDetails_BelkinNostromoKeyboard)1531 TEST_F(HidReportDescriptorTest, ValidateDetails_BelkinNostromoKeyboard) {
1532   auto info = HidCollectionInfo::New();
1533   info->usage = HidUsageAndPage::New(mojom::kGenericDesktopKeyboard,
1534                                      mojom::kPageGenericDesktop);
1535   ASSERT_EQ(IsProtected(*info->usage), true);
1536   AddTopCollectionInfo(std::move(info));
1537   ValidateDetails(false, 8, 0, 0, kBelkinNostromoKeyboard,
1538                   kBelkinNostromoKeyboardSize);
1539 }
1540 
TEST_F(HidReportDescriptorTest,ValidateCollections_BelkinNostromoKeyboard)1541 TEST_F(HidReportDescriptorTest, ValidateCollections_BelkinNostromoKeyboard) {
1542   auto* top = AddTopCollection(kUsageGenericDesktopKeyboard,
1543                                kCollectionTypeApplication);
1544   SetLogicalAndPhysicalBounds(0, 1, 0, 0);
1545   SetReportSizeAndCount(1, 8);
1546   AddReportItemRange(top, kInput, kAbsoluteVariable, kUsageKeyboardLeftControl,
1547                      kUsageKeyboardRightGui);
1548   SetReportSizeAndCount(8, 1);
1549   AddReportConstant(top, kInput, kConstantArray);
1550   SetLogicalAndPhysicalBounds(0, 101, 0, 0);
1551   SetReportSizeAndCount(8, 6);
1552   AddReportItemRange(top, kInput, kNonNullableArray, kUsageKeyboard,
1553                      kUsageKeyboardApplication);
1554   ValidateCollections(kBelkinNostromoKeyboard, kBelkinNostromoKeyboardSize);
1555 }
1556 
TEST_F(HidReportDescriptorTest,ValidateDetails_BelkinNostromoMouseAndExtra)1557 TEST_F(HidReportDescriptorTest, ValidateDetails_BelkinNostromoMouseAndExtra) {
1558   auto info = HidCollectionInfo::New();
1559   info->usage = HidUsageAndPage::New(mojom::kGenericDesktopMouse,
1560                                      mojom::kPageGenericDesktop);
1561   ASSERT_EQ(IsProtected(*info->usage), true);
1562   AddTopCollectionInfo(std::move(info));
1563   ValidateDetails(false, 4, 1, 0, kBelkinNostromoMouseAndExtra,
1564                   kBelkinNostromoMouseAndExtraSize);
1565 }
1566 
TEST_F(HidReportDescriptorTest,ValidateCollections_BelkinNostromoMouseAndExtra)1567 TEST_F(HidReportDescriptorTest,
1568        ValidateCollections_BelkinNostromoMouseAndExtra) {
1569   auto* top =
1570       AddTopCollection(kUsageGenericDesktopMouse, kCollectionTypeApplication);
1571   auto* pointer =
1572       AddChild(top, kUsageGenericDesktopPointer, kCollectionTypePhysical);
1573   SetLogicalAndPhysicalBounds(0, 1, 0, 0);
1574   SetReportSizeAndCount(1, 3);
1575   AddReportItemRange(pointer, kInput, kAbsoluteVariable, kUsageButton + 1,
1576                      kUsageButton + 3);
1577   SetReportSizeAndCount(5, 1);
1578   AddReportConstant(pointer, kInput, kConstantArray);
1579   SetLogicalAndPhysicalBounds(0x81, 0x7f, 0, 0);
1580   SetReportSizeAndCount(8, 3);
1581   AddReportItem(pointer, kInput, kRelativeVariable,
1582                 {kUsageGenericDesktopX, kUsageGenericDesktopY,
1583                  kUsageGenericDesktopWheel});
1584   SetLogicalAndPhysicalBounds(0, 1, 0, 1);
1585   SetReportSizeAndCount(1, 3);
1586   AddReportItemRange(pointer, kOutput, kAbsoluteVariable, kUsageLedNumLock,
1587                      kUsageLedScrollLock);
1588   SetReportSizeAndCount(5, 1);
1589   AddReportConstant(pointer, kOutput, kConstantArray);
1590   ValidateCollections(kBelkinNostromoMouseAndExtra,
1591                       kBelkinNostromoMouseAndExtraSize);
1592 }
1593 
TEST_F(HidReportDescriptorTest,InvalidReportSizeIgnored)1594 TEST_F(HidReportDescriptorTest, InvalidReportSizeIgnored) {
1595   // Report size can be at most 32 bits. Make sure a report item with invalid
1596   // size does not affect the maximum report size. The descriptor below
1597   // describes a report with one 64-bit constant field.
1598   static const uint8_t kInvalidReportSizeDescriptor[] = {
1599       0xA0,        // Collection
1600       0x95, 0x01,  //   Report Count (1)
1601       0x75, 0x40,  //   Report Size (64)
1602       0x90         //   Output
1603   };
1604   static const size_t kInvalidReportSizeDescriptorSize =
1605       base::size(kInvalidReportSizeDescriptor);
1606   auto info = HidCollectionInfo::New();
1607   info->usage = HidUsageAndPage::New(0, 0);
1608   AddTopCollectionInfo(std::move(info));
1609   // Maximum report sizes should not be affected by the invalid report item.
1610   ValidateDetails(false, 0, 0, 0, kInvalidReportSizeDescriptor,
1611                   kInvalidReportSizeDescriptorSize);
1612 
1613   // The report item with invalid size should still be included in the
1614   // collection info.
1615   auto* top = AddTopCollection(0, kCollectionTypePhysical);
1616   SetReportSizeAndCount(64, 1);
1617   AddReportConstant(top, kOutput, kNonNullableArray);
1618   ValidateCollections(kInvalidReportSizeDescriptor,
1619                       kInvalidReportSizeDescriptorSize);
1620 }
1621 
TEST_F(HidReportDescriptorTest,ReasonablyHugeReportNotIgnored)1622 TEST_F(HidReportDescriptorTest, ReasonablyHugeReportNotIgnored) {
1623   // The descriptor below defines a 2^16-1 byte output report. Larger reports
1624   // are considered unreasonable and are ignored in the max report size
1625   // calculation.
1626   static const uint8_t kReasonablyHugeReportDescriptor[] = {
1627       0xA0,              // Collection
1628       0x96, 0xff, 0xff,  //   Report Count (65535)
1629       0x75, 0x08,        //   Report Size (8)
1630       0x90               //   Output
1631   };
1632   static const size_t kReasonablyHugeReportDescriptorSize =
1633       base::size(kReasonablyHugeReportDescriptor);
1634   auto info = HidCollectionInfo::New();
1635   info->usage = HidUsageAndPage::New(0, 0);
1636   AddTopCollectionInfo(std::move(info));
1637   // Maximum report sizes should include the huge report.
1638   ValidateDetails(false, 0, 65535, 0, kReasonablyHugeReportDescriptor,
1639                   kReasonablyHugeReportDescriptorSize);
1640 
1641   auto* top = AddTopCollection(0, kCollectionTypePhysical);
1642   SetReportSizeAndCount(8, 65535);
1643   AddReportConstant(top, kOutput, kNonNullableArray);
1644   ValidateCollections(kReasonablyHugeReportDescriptor,
1645                       kReasonablyHugeReportDescriptorSize);
1646 }
1647 
TEST_F(HidReportDescriptorTest,UnreasonablyHugeReportIgnored)1648 TEST_F(HidReportDescriptorTest, UnreasonablyHugeReportIgnored) {
1649   // The descriptor below defines a 2^16 byte output report. The report is
1650   // larger than the maximum report size considered reasonable and will be
1651   // ignored when computing the max report size.
1652   static const uint8_t kUnreasonablyHugeReportDescriptor[] = {
1653       0xA0,                          // Collection
1654       0x97, 0x00, 0x00, 0x01, 0x00,  //   Report Count (65536)
1655       0x75, 0x08,                    //   Report Size (8)
1656       0x90                           //   Output
1657   };
1658   static const size_t kUnreasonablyHugeReportDescriptorSize =
1659       base::size(kUnreasonablyHugeReportDescriptor);
1660   auto info = HidCollectionInfo::New();
1661   info->usage = HidUsageAndPage::New(0, 0);
1662   AddTopCollectionInfo(std::move(info));
1663   // Maximum report sizes should not be affected by the huge report.
1664   ValidateDetails(false, 0, 0, 0, kUnreasonablyHugeReportDescriptor,
1665                   kUnreasonablyHugeReportDescriptorSize);
1666 
1667   // The unreasonably huge report item should still be included in the
1668   // collection info.
1669   auto* top = AddTopCollection(0, kCollectionTypePhysical);
1670   SetReportSizeAndCount(8, 65536);
1671   AddReportConstant(top, kOutput, kNonNullableArray);
1672   ValidateCollections(kUnreasonablyHugeReportDescriptor,
1673                       kUnreasonablyHugeReportDescriptorSize);
1674 }
1675 
TEST_F(HidReportDescriptorTest,HighlyNestedReportLimitsDepth)1676 TEST_F(HidReportDescriptorTest, HighlyNestedReportLimitsDepth) {
1677   // The HID report descriptor parser sets a maximum depth to prevent issues
1678   // with descriptors that define many nested collections. The descriptor below
1679   // nests a single constant inside 51 collections.
1680   static const uint8_t kHighlyNestedReportDescriptor[] = {
1681       0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0,
1682       0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0,
1683       0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0,
1684       0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0,
1685       0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0,
1686 
1687       0x95, 0x01,  // Report Count (1)
1688       0x75, 0x08,  // Report Size (8)
1689       0x90         // Output
1690   };
1691   static const size_t kHighlyNestedReportDescriptorSize =
1692       base::size(kHighlyNestedReportDescriptor);
1693   auto info = HidCollectionInfo::New();
1694   info->usage = HidUsageAndPage::New(0, 0);
1695   AddTopCollectionInfo(std::move(info));
1696   // The item in the innermost collection should still be reflected in the
1697   // maximum report size.
1698   ValidateDetails(false, 0, 1, 0, kHighlyNestedReportDescriptor,
1699                   kHighlyNestedReportDescriptorSize);
1700 
1701   // Construct nested collections up to the depth limit. The item from the
1702   // innermost collection should be propagated to all its parents even though
1703   // the depth limit has been reached.
1704   auto* parent = AddTopCollection(0, kCollectionTypePhysical);
1705   for (size_t i = 1; i < 50; ++i)
1706     parent = AddChild(parent, 0, kCollectionTypePhysical);
1707   SetReportSizeAndCount(8, 1);
1708   AddReportConstant(parent, kOutput, kNonNullableArray);
1709   ValidateCollections(kHighlyNestedReportDescriptor,
1710                       kHighlyNestedReportDescriptorSize);
1711 }
1712 
TEST_F(HidReportDescriptorTest,ExtraEndCollectionIgnored)1713 TEST_F(HidReportDescriptorTest, ExtraEndCollectionIgnored) {
1714   // When the report descriptor parser encounters an End Collection item,
1715   // it should decrement the collection depth only if a matching Collection
1716   // item was previously encountered. If no Collection item was encountered,
1717   // the End Collection item should be ignored.
1718   static const uint8_t kExtraEndCollectionDescriptor[] = {
1719       0xC0,  // End Collection
1720 
1721       0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0,
1722       0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0,
1723       0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0,
1724       0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0,
1725       0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0};
1726   static const size_t kExtraEndCollectionDescriptorSize =
1727       base::size(kExtraEndCollectionDescriptor);
1728 
1729   // Construct nested collections up to the depth limit. If the extra End
1730   // Collection item was ignored, the depth limit should have prevented the
1731   // innermost collection from being created.
1732   auto* parent = AddTopCollection(0, kCollectionTypePhysical);
1733   for (size_t i = 1; i < 50; ++i)
1734     parent = AddChild(parent, 0, kCollectionTypePhysical);
1735   ValidateCollections(kExtraEndCollectionDescriptor,
1736                       kExtraEndCollectionDescriptorSize);
1737 }
1738 
1739 }  // namespace device
1740