| // Copyright 2024 The ChromiumOS Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "libtouchraw/parser.h" |
| |
| #include <string> |
| |
| #include <base/files/file_util.h> |
| #include <base/test/task_environment.h> |
| #include <gtest/gtest.h> |
| |
| #include "libtouchraw/consumer_interface.h" |
| #include "libtouchraw/mock_consumers.h" |
| |
| namespace touchraw { |
| |
| // TODO: b/275615279 - Add unit tests for ReportDescriptor class. |
| |
| base::FilePath GetTestDataPath(const std::string& name) { |
| base::FilePath src = base::FilePath(getenv("SRC")); |
| src = src.Append("test_data"); |
| return src.Append(name); |
| } |
| |
| class ParserTest : public testing::Test { |
| protected: |
| void SetUp() override { |
| auto mock_consumer = |
| std::make_unique<testing::StrictMock<MockHeatmapChunkConsumer>>(); |
| mock_consumer_ = mock_consumer.get(); |
| parser_ = Parser::CreateForTesting(std::move(mock_consumer)); |
| } |
| |
| base::test::TaskEnvironment task_environment_{ |
| base::test::TaskEnvironment::TimeSource::MOCK_TIME}; |
| |
| MockHeatmapChunkConsumer* mock_consumer_; |
| std::unique_ptr<Parser> parser_; |
| }; |
| |
| // Complete report descriptor that supports heat map. |
| TEST_F(ParserTest, ValidReportDescriptorWithHeatmap) { |
| hidraw_report_descriptor rpt_desc; |
| auto buf = base::ReadFileToBytes(GetTestDataPath("report_descriptor.bin")); |
| ASSERT_TRUE(buf.has_value()); |
| rpt_desc.size = buf->size(); |
| memcpy(rpt_desc.value, buf->data(), buf->size()); |
| |
| EXPECT_TRUE(parser_->ParseHeatmapReportsFromDescriptor(&rpt_desc)); |
| EXPECT_EQ(parser_->usages_.size(), 82); |
| EXPECT_TRUE(parser_->sync_report_offset_.has_value()); |
| EXPECT_EQ(parser_->usages_[parser_->sync_report_offset_.value()].report_id, |
| 144); |
| EXPECT_TRUE(parser_->sub_report_offset_.has_value()); |
| EXPECT_EQ(parser_->usages_[parser_->sub_report_offset_.value()].report_id, |
| 145); |
| |
| // A chunk that has unmatched payload size 5, where the expected size is 7304 |
| // retrieved from the report descriptor. |
| auto hid_data = std::make_unique<HIDData>( |
| HIDData{144, // Report id. |
| { |
| 0x11, 0x22, // Protocol vendor ID. |
| 0x33, 0x44, // Protocol version. |
| 0x55, 0x66, 0x77, 0x88, // Scan time. |
| 0x99, 0xaa, // Sequence ID. |
| 0xbb, 0xcc, 0xdd, 0xee, 0xff, // Frame data. |
| }}); |
| parser_->ParseHIDData(std::move(hid_data)); |
| |
| // Use heat map report descriptor information to parse a valid first chunk. |
| parser_->usages_[parser_->sync_report_offset_.value() + 4].data_size = 3; |
| EXPECT_CALL(*mock_consumer_, Push(testing::_)) |
| .WillOnce([&](std::unique_ptr<const HeatmapChunk> chunk) { |
| EXPECT_EQ(chunk->vendor_id, 0x2211); |
| EXPECT_EQ(chunk->protocol_version, 0x4433); |
| EXPECT_EQ(chunk->scan_time, 0x88776655); |
| EXPECT_EQ(chunk->byte_count, 0xccbbaa99); |
| EXPECT_FALSE(chunk->sequence_id.has_value()); |
| EXPECT_EQ(chunk->report_type, ReportType::kFirst); |
| EXPECT_EQ(chunk->payload.size(), 3); |
| EXPECT_EQ(chunk->payload[0], 0xdd); |
| EXPECT_EQ(chunk->payload[1], 0xee); |
| EXPECT_EQ(chunk->payload[2], 0xff); |
| }); |
| hid_data = std::make_unique<HIDData>( |
| HIDData{144, // Report id. |
| { |
| 0x11, 0x22, // Protocol vendor ID. |
| 0x33, 0x44, // Protocol version. |
| 0x55, 0x66, 0x77, 0x88, // Scan time. |
| 0x99, 0xaa, 0xbb, 0xcc, // Byte count. |
| 0xdd, 0xee, 0xff, // Frame data. |
| }}); |
| parser_->ParseHIDData(std::move(hid_data)); |
| |
| // Use heat map report descriptor information to parse a valid subsequent |
| // chunk. |
| parser_->usages_[parser_->sub_report_offset_.value() + 4].data_size = 5; |
| EXPECT_CALL(*mock_consumer_, Push(testing::_)) |
| .WillOnce([&](std::unique_ptr<const HeatmapChunk> chunk) { |
| EXPECT_EQ(chunk->vendor_id, 0x2211); |
| EXPECT_EQ(chunk->protocol_version, 0x4433); |
| EXPECT_EQ(chunk->scan_time, 0x88776655); |
| EXPECT_FALSE(chunk->byte_count.has_value()); |
| EXPECT_EQ(chunk->sequence_id, 0xaa99); |
| EXPECT_EQ(chunk->report_type, ReportType::kSubsequent); |
| EXPECT_EQ(chunk->payload.size(), 5); |
| EXPECT_EQ(chunk->payload[0], 0xbb); |
| EXPECT_EQ(chunk->payload[1], 0xcc); |
| EXPECT_EQ(chunk->payload[2], 0xdd); |
| }); |
| hid_data = std::make_unique<HIDData>( |
| HIDData{145, // Report id. |
| { |
| 0x11, 0x22, // Protocol vendor ID. |
| 0x33, 0x44, // Protocol version. |
| 0x55, 0x66, 0x77, 0x88, // Scan time. |
| 0x99, 0xaa, // Sequence ID. |
| 0xbb, 0xcc, 0xdd, 0xee, 0xff, // Frame data. |
| }}); |
| parser_->ParseHIDData(std::move(hid_data)); |
| } |
| |
| // Complete report descriptor that does not support heat map. |
| TEST_F(ParserTest, ValidReportDescriptorWithoutHeatmap) { |
| hidraw_report_descriptor rpt_desc; |
| auto buf = base::ReadFileToBytes( |
| GetTestDataPath("report_descriptor_no_heatmap.bin")); |
| ASSERT_TRUE(buf.has_value()); |
| rpt_desc.size = buf->size(); |
| memcpy(rpt_desc.value, buf->data(), buf->size()); |
| |
| EXPECT_FALSE(parser_->ParseHeatmapReportsFromDescriptor(&rpt_desc)); |
| EXPECT_EQ(parser_->usages_.size(), 72); |
| EXPECT_FALSE(parser_->sync_report_offset_.has_value()); |
| EXPECT_FALSE(parser_->sub_report_offset_.has_value()); |
| } |
| |
| // This report descriptor contains heat map related usages with unknown hid type |
| // for scan time (report id 144). |
| TEST_F(ParserTest, UnknownHidType) { |
| hidraw_report_descriptor rpt_desc; |
| auto buf = base::ReadFileToBytes(GetTestDataPath("unknown_hid_type.bin")); |
| ASSERT_TRUE(buf.has_value()); |
| rpt_desc.size = buf->size(); |
| memcpy(rpt_desc.value, buf->data(), buf->size()); |
| |
| EXPECT_TRUE(parser_->ParseHeatmapReportsFromDescriptor(&rpt_desc)); |
| EXPECT_EQ(parser_->usages_.size(), 9); |
| EXPECT_TRUE(parser_->sync_report_offset_.has_value()); |
| EXPECT_EQ(parser_->usages_[parser_->sync_report_offset_.value()].report_id, |
| 144); |
| EXPECT_TRUE(parser_->sub_report_offset_.has_value()); |
| EXPECT_EQ(parser_->usages_[parser_->sub_report_offset_.value()].report_id, |
| 145); |
| |
| // Unsupported report ID. |
| auto hid_data = std::make_unique<HIDData>( |
| HIDData{140, // Report id. |
| { |
| 0x11, 0x22, // Protocol vendor ID. |
| 0x33, 0x44, // Protocol version. |
| 0x55, 0x66, 0x77, 0x88, // Scan time. |
| 0x99, 0xaa, 0xbb, 0xcc, // Byte count. |
| 0xdd, 0xee, 0xff, // Frame data. |
| }}); |
| parser_->ParseHIDData(std::move(hid_data)); |
| |
| // Report descriptor and data do not match. |
| parser_->usages_[parser_->sync_report_offset_.value() + 3].data_size = 7; |
| EXPECT_CALL(*mock_consumer_, Push(testing::_)) |
| .WillOnce([&](std::unique_ptr<const HeatmapChunk> chunk) { |
| EXPECT_EQ(chunk->vendor_id, 0x2211); |
| EXPECT_EQ(chunk->protocol_version, 0x4433); |
| EXPECT_EQ(chunk->scan_time, 0); |
| EXPECT_EQ(chunk->byte_count, 0x88776655); |
| EXPECT_FALSE(chunk->sequence_id.has_value()); |
| EXPECT_EQ(chunk->report_type, ReportType::kFirst); |
| EXPECT_EQ(chunk->payload.size(), 7); |
| EXPECT_EQ(chunk->payload[0], 0x99); |
| EXPECT_EQ(chunk->payload[6], 0xff); |
| }); |
| hid_data = std::make_unique<HIDData>( |
| HIDData{144, // Report id. |
| { |
| 0x11, 0x22, // Protocol vendor ID. |
| 0x33, 0x44, // Protocol version. |
| 0x55, 0x66, 0x77, 0x88, // Scan time. |
| 0x99, 0xaa, 0xbb, 0xcc, // Byte count. |
| 0xdd, 0xee, 0xff, // Frame data. |
| }}); |
| parser_->ParseHIDData(std::move(hid_data)); |
| } |
| |
| } // namespace touchraw |