text: // Copyright (c) 2014 The Chromium Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  #include <sstream>
  
  #include "device/hid/hid_report_descriptor.h"
  #include "testing/gmock/include/gmock/gmock.h"
  #include "testing/gtest/include/gtest/gtest.h"
  
  using namespace testing;
  
  namespace device {
  
  namespace {
  
  // Digitizer descriptor from HID descriptor tool
  // http://www.usb.org/developers/hidpage/dt2_4.zip
  const uint8_t kDigitizer[] = {
      0x05, 0x0d,        // Usage Page (Digitizer)
      0x09, 0x01,        // Usage (0x1)
      0xa1, 0x01,        // Collection (Application)
      0x85, 0x01,        //  Report ID (0x1)
      0x09, 0x21,        //  Usage (0x21)
      0xa1, 0x00,        //  Collection (Physical)
      0x05, 0x01,        //   Usage Page (Generic Desktop)
      0x09, 0x30,        //   Usage (0x30)
      0x09, 0x31,        //   Usage (0x31)
      0x75, 0x10,        //   Report Size (16)
      0x95, 0x02,        //   Report Count (2)
      0x15, 0x00,        //   Logical Minimum (0)
      0x26, 0xe0, 0x2e,  //   Logical Maximum (12000)
      0x35, 0x00,        //   Physical Minimum (0)
      0x45, 0x0c,        //   Physical Maximum (12)
      0x65, 0x13,        //   Unit (19)
      0x55, 0x00,        //   Unit Exponent (0)
      0xa4,              //   Push
      0x81, 0x02,        //   Input (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)
      0x05, 0x0d,        //   Usage Page (Digitizer)
      0x09, 0x32,        //   Usage (0x32)
      0x09, 0x44,        //   Usage (0x44)
      0x09, 0x42,        //   Usage (0x42)
      0x15, 0x00,        //   Logical Minimum (0)
      0x25, 0x01,        //   Logical Maximum (1)
      0x35, 0x00,        //   Physical Minimum (0)
      0x45, 0x01,        //   Physical Maximum (1)
      0x75, 0x01,        //   Report Size (1)
      0x95, 0x03,        //   Report Count (3)
      0x65, 0x00,        //   Unit (0)
      0x81, 0x02,        //   Input (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)
      0x95, 0x01,        //   Report Count (1)
      0x75, 0x05,        //   Report Size (5)
      0x81, 0x03,        //   Input (Con|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)
      0xc0,              //  End Collection
      0x85, 0x02,        //  Report ID (0x2)
      0x09, 0x20,        //  Usage (0x20)
      0xa1, 0x00,        //  Collection (Physical)
      0xb4,              //   Pop
      0xa4,              //   Push
      0x09, 0x30,        //   Usage (0x30)
      0x09, 0x31,        //   Usage (0x31)
      0x81, 0x02,        //   Input (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)
      0x05, 0x0d,        //   Usage Page (Digitizer)
      0x09, 0x32,        //   Usage (0x32)
      0x15, 0x00,        //   Logical Minimum (0)
      0x25, 0x01,        //   Logical Maximum (1)
      0x35, 0x00,        //   Physical Minimum (0)
      0x45, 0x01,        //   Physical Maximum (1)
      0x65, 0x00,        //   Unit (0)
      0x75, 0x01,        //   Report Size (1)
      0x81, 0x02,        //   Input (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)
      0x05, 0x09,        //   Usage Page (Button)
      0x19, 0x00,        //   Usage Minimum (0)
      0x29, 0x10,        //   Usage Maximum (16)
      0x25, 0x10,        //   Logical Maximum (16)
      0x75, 0x05,        //   Report Size (5)
      0x81, 0x40,        //   Input (Dat|Var|Rel|NoWrp|Lin|Prf|Null|BitF)
      0x75, 0x02,        //   Report Size (2)
      0x81, 0x01,        //   Input (Con|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)
      0xc0,              //  End Collection
      0x85, 0x03,        //  Report ID (0x3)
      0x05, 0x0d,        //  Usage Page (Digitizer)
      0x09, 0x20,        //  Usage (0x20)
      0xa1, 0x00,        //  Collection (Physical)
      0xb4,              //   Pop
      0x09, 0x30,        //   Usage (0x30)
      0x09, 0x31,        //   Usage (0x31)
      0x81, 0x02,        //   Input (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)
      0x05, 0x0d,        //   Usage Page (Digitizer)
      0x09, 0x32,        //   Usage (0x32)
      0x09, 0x44,        //   Usage (0x44)
      0x75, 0x01,        //   Report Size (1)
      0x15, 0x00,        //   Logical Minimum (0)
      0x25, 0x01,        //   Logical Maximum (1)
      0x35, 0x00,        //   Physical Minimum (0)
      0x45, 0x01,        //   Physical Maximum (1)
      0x65, 0x00,        //   Unit (0)
      0x81, 0x02,        //   Input (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)
      0x95, 0x06,        //   Report Count (6)
      0x81, 0x03,        //   Input (Con|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)
      0x09, 0x30,        //   Usage (0x30)
      0x15, 0x00,        //   Logical Minimum (0)
      0x25, 0x7f,        //   Logical Maximum (127)
      0x35, 0x00,        //   Physical Minimum (0)
      0x45, 0x2d,        //   Physical Maximum (45)
      0x67, 0x11, 0xe1,  //   Unit (57617)
      0x00, 0x00,        //   Default
      0x55, 0x04,        //   Unit Exponent (4)
      0x75, 0x08,        //   Report Size (8)
      0x95, 0x01,        //   Report Count (1)
      0x81, 0x12,        //   Input (Dat|Arr|Rel|NoWrp|NoLin|Prf|NoNull|BitF)
      0xc0,              //  End Collection
      0xc0               // End Collection
  };
  
  // Keyboard descriptor from HID descriptor tool
  // http://www.usb.org/developers/hidpage/dt2_4.zip
  const uint8_t kKeyboard[] = {
      0x05, 0x01,  // Usage Page (Generic Desktop)
      0x09, 0x06,  // Usage (0x6)
      0xa1, 0x01,  // Collection (Application)
      0x05, 0x07,  //  Usage Page (Keyboard)
      0x19, 0xe0,  //  Usage Minimum (224)
      0x29, 0xe7,  //  Usage Maximum (231)
      0x15, 0x00,  //  Logical Minimum (0)
      0x25, 0x01,  //  Logical Maximum (1)
      0x75, 0x01,  //  Report Size (1)
      0x95, 0x08,  //  Report Count (8)
      0x81, 0x02,  //  Input (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)
      0x95, 0x01,  //  Report Count (1)
      0x75, 0x08,  //  Report Size (8)
      0x81, 0x03,  //  Input (Con|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)
      0x95, 0x05,  //  Report Count (5)
      0x75, 0x01,  //  Report Size (1)
      0x05, 0x08,  //  Usage Page (Led)
      0x19, 0x01,  //  Usage Minimum (1)
      0x29, 0x05,  //  Usage Maximum (5)
      0x91, 0x02,  //  Output (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)
      0x95, 0x01,  //  Report Count (1)
      0x75, 0x03,  //  Report Size (3)
      0x91, 0x03,  //  Output (Con|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)
      0x95, 0x06,  //  Report Count (6)
      0x75, 0x08,  //  Report Size (8)
      0x15, 0x00,  //  Logical Minimum (0)
      0x25, 0x65,  //  Logical Maximum (101)
      0x05, 0x07,  //  Usage Page (Keyboard)
      0x19, 0x00,  //  Usage Minimum (0)
      0x29, 0x65,  //  Usage Maximum (101)
      0x81, 0x00,  //  Input (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)
      0xc0         // End Collection
  };
  
  // Monitor descriptor from HID descriptor tool
  // http://www.usb.org/developers/hidpage/dt2_4.zip
  const uint8_t kMonitor[] = {
      0x05, 0x80,        // Usage Page (Monitor 0)
      0x09, 0x01,        // Usage (0x1)
      0xa1, 0x01,        // Collection (Application)
      0x85, 0x01,        //  Report ID (0x1)
      0x15, 0x00,        //  Logical Minimum (0)
      0x26, 0xff, 0x00,  //  Logical Maximum (255)
      0x75, 0x08,        //  Report Size (8)
      0x95, 0x80,        //  Report Count (128)
      0x09, 0x02,        //  Usage (0x2)
      0xb2, 0x02, 0x01,  //  Feature (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|Buff)
      0x85, 0x02,        //  Report ID (0x2)
      0x95, 0xf3,        //  Report Count (243)
      0x09, 0x03,        //  Usage (0x3)
      0xb2, 0x02, 0x01,  //  Feature (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|Buff)
      0x85, 0x03,        //  Report ID (0x3)
      0x05, 0x82,        //  Usage Page (Monitor 2)
      0x95, 0x01,        //  Report Count (1)
      0x75, 0x10,        //  Report Size (16)
      0x26, 0xc8, 0x00,  //  Logical Maximum (200)
      0x09, 0x10,        //  Usage (0x10)
      0xb1, 0x02,        //  Feature (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)
      0x85, 0x04,        //  Report ID (0x4)
      0x25, 0x64,        //  Logical Maximum (100)
      0x09, 0x12,        //  Usage (0x12)
      0xb1, 0x02,        //  Feature (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)
      0x95, 0x06,        //  Report Count (6)
      0x26, 0xff, 0x00,  //  Logical Maximum (255)
      0x09, 0x16,        //  Usage (0x16)
      0x09, 0x18,        //  Usage (0x18)
      0x09, 0x1a,        //  Usage (0x1A)
      0x09, 0x6c,        //  Usage (0x6C)
      0x09, 0x6e,        //  Usage (0x6E)
      0x09, 0x70,        //  Usage (0x70)
      0xb1, 0x02,        //  Feature (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)
      0x85, 0x05,        //  Report ID (0x5)
      0x25, 0x7f,        //  Logical Maximum (127)
      0x09, 0x20,        //  Usage (0x20)
      0x09, 0x22,        //  Usage (0x22)
      0x09, 0x30,        //  Usage (0x30)
      0x09, 0x32,        //  Usage (0x32)
      0x09, 0x42,        //  Usage (0x42)
      0x09, 0x44,        //  Usage (0x44)
      0xb1, 0x02,        //  Feature (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)
      0xc0               // End Collection
  };
  
  // Mouse descriptor from HID descriptor tool
  // http://www.usb.org/developers/hidpage/dt2_4.zip
  const uint8_t kMouse[] = {
      0x05, 0x01,  // Usage Page (Generic Desktop)
      0x09, 0x02,  // Usage (0x2)
      0xa1, 0x01,  // Collection (Application)
      0x09, 0x01,  //  Usage (0x1)
      0xa1, 0x00,  //  Collection (Physical)
      0x05, 0x09,  //   Usage Page (Button)
      0x19, 0x01,  //   Usage Minimum (1)
      0x29, 0x03,  //   Usage Maximum (3)
      0x15, 0x00,  //   Logical Minimum (0)
      0x25, 0x01,  //   Logical Maximum (1)
      0x95, 0x03,  //   Report Count (3)
      0x75, 0x01,  //   Report Size (1)
      0x81, 0x02,  //   Input (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)
      0x95, 0x01,  //   Report Count (1)
      0x75, 0x05,  //   Report Size (5)
      0x81, 0x03,  //   Input (Con|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)
      0x05, 0x01,  //   Usage Page (Generic Desktop)
      0x09, 0x30,  //   Usage (0x30)
      0x09, 0x31,  //   Usage (0x31)
      0x15, 0x81,  //   Logical Minimum (129)
      0x25, 0x7f,  //   Logical Maximum (127)
      0x75, 0x08,  //   Report Size (8)
      0x95, 0x02,  //   Report Count (2)
      0x81, 0x06,  //   Input (Dat|Arr|Abs|NoWrp|Lin|Prf|NoNull|BitF)
      0xc0,        //  End Collection
      0xc0         // End Collection
  };
  
  // Logitech Unifying receiver descriptor
  const uint8_t kLogitechUnifyingReceiver[] = {
      0x06, 0x00, 0xFF,  // Usage Page (Vendor)
      0x09, 0x01,        // Usage (0x1)
      0xA1, 0x01,        // Collection (Application)
      0x85, 0x10,        //  Report ID (0x10)
      0x75, 0x08,        //  Report Size (8)
      0x95, 0x06,        //  Report Count (6)
      0x15, 0x00,        //  Logical Minimum (0)
      0x26, 0xFF, 0x00,  //  Logical Maximum (255)
      0x09, 0x01,        //  Usage (0x1)
      0x81, 0x00,        //  Input (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)
      0x09, 0x01,        //  Usage (0x1)
      0x91, 0x00,        //  Output (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)
      0xC0,              // End Collection
      0x06, 0x00, 0xFF,  // Usage Page (Vendor)
      0x09, 0x02,        // Usage (0x2)
      0xA1, 0x01,        // Collection (Application)
      0x85, 0x11,        //  Report ID (0x11)
      0x75, 0x08,        //  Report Size (8)
      0x95, 0x13,        //  Report Count (19)
      0x15, 0x00,        //  Logical Minimum (0)
      0x26, 0xFF, 0x00,  //  Logical Maximum (255)
      0x09, 0x02,        //  Usage (0x2)
      0x81, 0x00,        //  Input (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)
      0x09, 0x02,        //  Usage (0x2)
      0x91, 0x00,        //  Output (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)
      0xC0,              // End Collection
      0x06, 0x00, 0xFF,  // Usage Page (Vendor)
      0x09, 0x04,        // Usage (0x4)
      0xA1, 0x01,        // Collection (Application)
      0x85, 0x20,        //  Report ID (0x20)
      0x75, 0x08,        //  Report Size (8)
      0x95, 0x0E,        //  Report Count (14)
      0x15, 0x00,        //  Logical Minimum (0)
      0x26, 0xFF, 0x00,  //  Logical Maximum (255)
      0x09, 0x41,        //  Usage (0x41)
      0x81, 0x00,        //  Input (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)
      0x09, 0x41,        //  Usage (0x41)
      0x91, 0x00,        //  Output (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)
      0x85, 0x21,        //  Report ID (0x21)
      0x95, 0x1F,        //  Report Count (31)
      0x15, 0x00,        //  Logical Minimum (0)
      0x26, 0xFF, 0x00,  //  Logical Maximum (255)
      0x09, 0x42,        //  Usage (0x42)
      0x81, 0x00,        //  Input (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)
      0x09, 0x42,        //  Usage (0x42)
      0x91, 0x00,        //  Output (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)
      0xC0               // End Collection
  };
  
  }  // namespace
  
  class HidReportDescriptorTest : public testing::Test {
  
   protected:
    void SetUp() override { descriptor_ = NULL; }
  
    void TearDown() override {
      if (descriptor_) {
        delete descriptor_;
      }
    }
  
   public:
    void ValidateDetails(
        const std::vector<HidCollectionInfo>& expected_collections,
        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) {
      descriptor_ = new HidReportDescriptor(bytes, size);
  
      std::vector<HidCollectionInfo> actual_collections;
      bool actual_has_report_id;
      size_t actual_max_input_report_size;
      size_t actual_max_output_report_size;
      size_t actual_max_feature_report_size;
      descriptor_->GetDetails(&actual_collections,
                              &actual_has_report_id,
                              &actual_max_input_report_size,
                              &actual_max_output_report_size,
                              &actual_max_feature_report_size);
  
      ASSERT_EQ(expected_collections.size(), actual_collections.size());
  
      std::vector<HidCollectionInfo>::const_iterator actual_collections_iter =
          actual_collections.begin();
      std::vector<HidCollectionInfo>::const_iterator expected_collections_iter =
          expected_collections.begin();
  
      while (expected_collections_iter != expected_collections.end() &&
             actual_collections_iter != actual_collections.end()) {
        HidCollectionInfo expected_collection = *expected_collections_iter;
        HidCollectionInfo actual_collection = *actual_collections_iter;
  
        ASSERT_EQ(expected_collection.usage.usage_page,
                  actual_collection.usage.usage_page);
        ASSERT_EQ(expected_collection.usage.usage, actual_collection.usage.usage);
        ASSERT_THAT(actual_collection.report_ids,
                    ContainerEq(expected_collection.report_ids));
  
        expected_collections_iter++;
        actual_collections_iter++;
      }
  
      ASSERT_EQ(expected_has_report_id, actual_has_report_id);
      ASSERT_EQ(expected_max_input_report_size, actual_max_input_report_size);
      ASSERT_EQ(expected_max_output_report_size, actual_max_output_report_size);
      ASSERT_EQ(expected_max_feature_report_size, actual_max_feature_report_size);
    }
  
   private:
    HidReportDescriptor* descriptor_;
  };
  
  TEST_F(HidReportDescriptorTest, ValidateDetails_Digitizer) {
    HidCollectionInfo digitizer;
    digitizer.usage = HidUsageAndPage(0x01, HidUsageAndPage::kPageDigitizer);
    digitizer.report_ids.insert(1);
    digitizer.report_ids.insert(2);
    digitizer.report_ids.insert(3);
    HidCollectionInfo expected[] = {digitizer};
    ValidateDetails(std::vector<HidCollectionInfo>(
                        expected, expected + arraysize(expected)),
                    true,
                    6,
                    0,
                    0,
                    kDigitizer,
                    sizeof(kDigitizer));
  }
  
  TEST_F(HidReportDescriptorTest, ValidateDetails_Keyboard) {
    HidCollectionInfo keyboard;
    keyboard.usage = HidUsageAndPage(0x06, HidUsageAndPage::kPageGenericDesktop);
    HidCollectionInfo expected[] = {keyboard};
    ValidateDetails(std::vector<HidCollectionInfo>(
                        expected, expected + arraysize(expected)),
                    false,
                    8,
                    1,
                    0,
                    kKeyboard,
                    sizeof(kKeyboard));
  }
  
  TEST_F(HidReportDescriptorTest, ValidateDetails_Monitor) {
    HidCollectionInfo monitor;
    monitor.usage = HidUsageAndPage(0x01, HidUsageAndPage::kPageMonitor0);
    monitor.report_ids.insert(1);
    monitor.report_ids.insert(2);
    monitor.report_ids.insert(3);
    monitor.report_ids.insert(4);
    monitor.report_ids.insert(5);
    HidCollectionInfo expected[] = {monitor};
    ValidateDetails(std::vector<HidCollectionInfo>(
                        expected, expected + arraysize(expected)),
                    true,
                    0,
                    0,
                    243,
                    kMonitor,
                    sizeof(kMonitor));
  }
  
  TEST_F(HidReportDescriptorTest, ValidateDetails_Mouse) {
    HidCollectionInfo mouse;
    mouse.usage = HidUsageAndPage(0x02, HidUsageAndPage::kPageGenericDesktop);
    HidCollectionInfo expected[] = {mouse};
    ValidateDetails(std::vector<HidCollectionInfo>(
                        expected, expected + arraysize(expected)),
                    false,
                    3,
                    0,
                    0,
                    kMouse,
                    sizeof(kMouse));
  }
  
  TEST_F(HidReportDescriptorTest, ValidateDetails_LogitechUnifyingReceiver) {
    HidCollectionInfo hidpp_short;
    hidpp_short.usage = HidUsageAndPage(0x01, HidUsageAndPage::kPageVendor);
    hidpp_short.report_ids.insert(0x10);
    HidCollectionInfo hidpp_long;
    hidpp_long.usage = HidUsageAndPage(0x02, HidUsageAndPage::kPageVendor);
    hidpp_long.report_ids.insert(0x11);
    HidCollectionInfo hidpp_dj;
    hidpp_dj.usage = HidUsageAndPage(0x04, HidUsageAndPage::kPageVendor);
    hidpp_dj.report_ids.insert(0x20);
    hidpp_dj.report_ids.insert(0x21);
  
    HidCollectionInfo expected[] = {hidpp_short, hidpp_long, hidpp_dj};
    ValidateDetails(std::vector<HidCollectionInfo>(
                        expected, expected + arraysize(expected)),
                    true,
                    31,
                    31,
                    0,
                    kLogitechUnifyingReceiver,
                    sizeof(kLogitechUnifyingReceiver));
  }
  
  }  // namespace device
  