| // 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 <string> | |
| #include <utility> | |
| #include <vector> | |
| #include <base/test/task_environment.h> | |
| #include <gtest/gtest.h> | |
| #include "libtouchraw/crop.h" | |
| #include "libtouchraw/mock_consumers.h" | |
| #include "libtouchraw/reshaper.h" | |
| namespace touchraw { | |
| namespace test { | |
| struct ReshaperTestParam { | |
| uint8_t crop_bottom; | |
| uint8_t crop_left; | |
| uint8_t crop_right; | |
| uint8_t crop_top; | |
| unsigned int expected_heatmap_size; | |
| std::string name; | |
| }; | |
| } // namespace test | |
| class ReshaperTest | |
| : public testing::TestWithParam<touchraw::test::ReshaperTestParam> { | |
| protected: | |
| void validatePayload(const touchraw::test::ReshaperTestParam& param, | |
| const std::unique_ptr<const Heatmap>& heatmap, | |
| const std::vector<uint8_t>& payload, | |
| const unsigned int num_bytes) { | |
| std::vector<uint8_t>::size_type heatmap_index = 0; | |
| std::vector<uint8_t>::size_type expected_value_index = 0; | |
| for (std::vector<uint8_t>::size_type r = param.crop_top; | |
| r < (height - param.crop_bottom); ++r) { | |
| for (std::vector<uint8_t>::size_type c = param.crop_left; | |
| c < (width - param.crop_right); ++c) { | |
| expected_value_index = ((r * width) + c) * num_bytes; | |
| for (unsigned int i = 0; i < num_bytes; ++i) { | |
| EXPECT_EQ(heatmap->payload.at(heatmap_index++), | |
| payload.at(expected_value_index + i)); | |
| } | |
| } | |
| } | |
| } | |
| std::vector<uint8_t> payload_8bit_6_by_5 = { | |
| 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, | |
| 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, | |
| 0x15, 0x16, 0x17, 0x18, 0x19, 0X1A, 0x1B, 0x1C, 0x1D, 0x1E, | |
| }; | |
| std::vector<uint8_t> payload_12bit_6_by_5 = { | |
| 0x01, 0x0F, 0x02, 0x0E, 0x03, 0x0D, 0x04, 0x08, 0x05, 0x0A, 0x06, 0x0F, | |
| 0x07, 0x0F, 0x08, 0x0E, 0x09, 0x0D, 0x0A, 0x08, 0x0B, 0x0A, 0x0C, 0x0F, | |
| 0x0D, 0x0F, 0x0E, 0x0E, 0x0F, 0x0D, 0x10, 0x08, 0x11, 0x0A, 0x12, 0x0F, | |
| 0x13, 0x0F, 0x14, 0x0E, 0x15, 0x0D, 0x16, 0x08, 0x17, 0x0A, 0x18, 0x0F, | |
| 0x19, 0x0F, 0X1A, 0x0E, 0x1B, 0x0D, 0x1C, 0x08, 0x1D, 0x0A, 0x1E, 0x0F, | |
| }; | |
| std::vector<uint8_t> payload_16bit_6_by_5 = { | |
| 0x01, 0x4F, 0x02, 0x5E, 0x03, 0x7D, 0x04, 0x18, 0x05, 0xAA, 0x06, 0xCF, | |
| 0x07, 0x4F, 0x08, 0x5E, 0x09, 0x7D, 0x0A, 0x18, 0x0B, 0xAA, 0x0C, 0xCF, | |
| 0x0D, 0x4F, 0x0E, 0x5E, 0x0F, 0x7D, 0x10, 0x18, 0x11, 0xAA, 0x12, 0xCF, | |
| 0x13, 0x4F, 0x14, 0x5E, 0x15, 0x7D, 0x16, 0x18, 0x17, 0xAA, 0x18, 0xCF, | |
| 0x19, 0x4F, 0X1A, 0x5E, 0x1B, 0x7D, 0x1C, 0x18, 0x1D, 0xAA, 0x1E, 0xCF, | |
| }; | |
| base::test::TaskEnvironment task_environment_{ | |
| base::test::TaskEnvironment::TimeSource::MOCK_TIME}; | |
| const uint8_t height = 5; | |
| const uint8_t width = 6; | |
| }; | |
| class ReshaperBeyondBoundsTest : public ReshaperTest { | |
| protected: | |
| void validatePayload(const std::unique_ptr<const Heatmap>& heatmap, | |
| const std::vector<uint8_t>& payload, | |
| const unsigned int num_bytes) { | |
| std::vector<uint8_t>::size_type heatmap_index = 0; | |
| std::vector<uint8_t>::size_type expected_value_index = 0; | |
| for (std::vector<uint8_t>::size_type r = 0; r < height; ++r) { | |
| for (std::vector<uint8_t>::size_type c = 0; c < width; ++c) { | |
| expected_value_index = ((r * width) + c) * num_bytes; | |
| for (unsigned int i = 0; i < num_bytes; ++i) { | |
| EXPECT_EQ(heatmap->payload.at(heatmap_index++), | |
| payload.at(expected_value_index + i)); | |
| } | |
| } | |
| } | |
| } | |
| }; | |
| TEST_P(ReshaperTest, Crop8BitHeatmap) { | |
| std::unique_ptr<Heatmap> heatmap_8bit = std::make_unique<Heatmap>(Heatmap{ | |
| 0, // Vendor id. | |
| 1, // Protocol version. | |
| 2, // Scan time. | |
| kDiffData, // Encoding. | |
| 8, // Bit Depth. | |
| height, // Height. | |
| width, // Width. | |
| 10, // Threshold. | |
| 30, // Payload length in bytes. | |
| payload_8bit_6_by_5, // Payload. | |
| }); | |
| touchraw::test::ReshaperTestParam param = GetParam(); | |
| auto mock_consumer = | |
| std::make_unique<testing::StrictMock<MockHeatmapConsumer>>(); | |
| auto mock_consumer_ptr = mock_consumer.get(); | |
| EXPECT_CALL(*mock_consumer_ptr, Push(testing::_)) | |
| .WillOnce([&](std::unique_ptr<const Heatmap> heatmap) { | |
| EXPECT_EQ(heatmap->vendor_id, 0); | |
| EXPECT_EQ(heatmap->protocol_version, 1); | |
| EXPECT_EQ(heatmap->scan_time, 2); | |
| EXPECT_EQ(heatmap->encoding, 1); | |
| EXPECT_EQ(heatmap->bit_depth, 8); | |
| EXPECT_EQ(heatmap->threshold, 10); | |
| EXPECT_EQ(heatmap->height, | |
| (height - param.crop_top - param.crop_bottom)); | |
| EXPECT_EQ(heatmap->width, (width - param.crop_left - param.crop_right)); | |
| EXPECT_EQ(heatmap->length, param.expected_heatmap_size); | |
| EXPECT_EQ(heatmap->payload.size(), param.expected_heatmap_size); | |
| // Validate payload. | |
| validatePayload(param, heatmap, payload_8bit_6_by_5, /*num_bytes=*/1); | |
| }); | |
| auto reshaper = std::make_unique<Reshaper>( | |
| Crop{ | |
| param.crop_bottom, | |
| param.crop_left, | |
| param.crop_right, | |
| param.crop_top, | |
| }, | |
| std::move(mock_consumer)); | |
| reshaper->Push(std::move(heatmap_8bit)); | |
| task_environment_.RunUntilIdle(); | |
| } | |
| TEST_P(ReshaperTest, Crop12BitHeatmap) { | |
| std::unique_ptr<Heatmap> heatmap_12bit = std::make_unique<Heatmap>(Heatmap{ | |
| 0, // Vendor id. | |
| 1, // Protocol version. | |
| 3, // Scan time. | |
| kDiffData, // Encoding. | |
| 12, // Bit Depth. | |
| height, // Height. | |
| width, // Width. | |
| 10, // Threshold. | |
| 60, // Payload length in bytes. | |
| payload_12bit_6_by_5, // Payload. | |
| }); | |
| touchraw::test::ReshaperTestParam param = GetParam(); | |
| auto mock_consumer = | |
| std::make_unique<testing::StrictMock<MockHeatmapConsumer>>(); | |
| auto mock_consumer_ptr = mock_consumer.get(); | |
| EXPECT_CALL(*mock_consumer_ptr, Push(testing::_)) | |
| .WillOnce([&](std::unique_ptr<const Heatmap> heatmap) { | |
| EXPECT_EQ(heatmap->vendor_id, 0); | |
| EXPECT_EQ(heatmap->protocol_version, 1); | |
| EXPECT_EQ(heatmap->scan_time, 3); | |
| EXPECT_EQ(heatmap->encoding, 1); | |
| EXPECT_EQ(heatmap->bit_depth, 12); | |
| EXPECT_EQ(heatmap->threshold, 10); | |
| EXPECT_EQ(heatmap->height, | |
| (height - param.crop_top - param.crop_bottom)); | |
| EXPECT_EQ(heatmap->width, (width - param.crop_left - param.crop_right)); | |
| EXPECT_EQ(heatmap->length, 2 * param.expected_heatmap_size); | |
| EXPECT_EQ(heatmap->payload.size(), 2 * param.expected_heatmap_size); | |
| // Validate payload. | |
| validatePayload(param, heatmap, payload_12bit_6_by_5, /*num_bytes=*/2); | |
| }); | |
| auto reshaper = std::make_unique<Reshaper>( | |
| Crop{ | |
| param.crop_bottom, | |
| param.crop_left, | |
| param.crop_right, | |
| param.crop_top, | |
| }, | |
| std::move(mock_consumer)); | |
| reshaper->Push(std::move(heatmap_12bit)); | |
| task_environment_.RunUntilIdle(); | |
| } | |
| TEST_P(ReshaperTest, Crop16BitHeatmap) { | |
| std::unique_ptr<Heatmap> heatmap_16bit = std::make_unique<Heatmap>(Heatmap{ | |
| 0, // Vendor id. | |
| 1, // Protocol version. | |
| 3, // Scan time. | |
| kDiffData, // Encoding. | |
| 16, // Bit Depth. | |
| height, // Height. | |
| width, // Width. | |
| 10, // Threshold. | |
| 60, // Payload length in bytes. | |
| payload_16bit_6_by_5, // Payload. | |
| }); | |
| touchraw::test::ReshaperTestParam param = GetParam(); | |
| auto mock_consumer = | |
| std::make_unique<testing::StrictMock<MockHeatmapConsumer>>(); | |
| auto mock_consumer_ptr = mock_consumer.get(); | |
| EXPECT_CALL(*mock_consumer_ptr, Push(testing::_)) | |
| .WillOnce([&](std::unique_ptr<const Heatmap> heatmap) { | |
| EXPECT_EQ(heatmap->vendor_id, 0); | |
| EXPECT_EQ(heatmap->protocol_version, 1); | |
| EXPECT_EQ(heatmap->scan_time, 3); | |
| EXPECT_EQ(heatmap->encoding, 1); | |
| EXPECT_EQ(heatmap->bit_depth, 16); | |
| EXPECT_EQ(heatmap->threshold, 10); | |
| EXPECT_EQ(heatmap->height, | |
| (height - param.crop_top - param.crop_bottom)); | |
| EXPECT_EQ(heatmap->width, (width - param.crop_left - param.crop_right)); | |
| EXPECT_EQ(heatmap->length, 2 * param.expected_heatmap_size); | |
| EXPECT_EQ(heatmap->payload.size(), 2 * param.expected_heatmap_size); | |
| // Validate payload. | |
| validatePayload(param, heatmap, payload_16bit_6_by_5, /*num_bytes=*/2); | |
| }); | |
| auto reshaper = std::make_unique<Reshaper>( | |
| Crop{ | |
| param.crop_bottom, | |
| param.crop_left, | |
| param.crop_right, | |
| param.crop_top, | |
| }, | |
| std::move(mock_consumer)); | |
| reshaper->Push(std::move(heatmap_16bit)); | |
| task_environment_.RunUntilIdle(); | |
| } | |
| TEST_P(ReshaperBeyondBoundsTest, CropBeyondBounds) { | |
| std::unique_ptr<Heatmap> heatmap_8bit = std::make_unique<Heatmap>(Heatmap{ | |
| 0, // Vendor id. | |
| 1, // Protocol version. | |
| 2, // Scan time. | |
| kDiffData, // Encoding. | |
| 8, // Bit Depth. | |
| height, // Height. | |
| width, // Width. | |
| 10, // Threshold. | |
| 30, // Payload length in bytes. | |
| payload_8bit_6_by_5, // Payload. | |
| }); | |
| touchraw::test::ReshaperTestParam param = GetParam(); | |
| auto mock_consumer = | |
| std::make_unique<testing::StrictMock<MockHeatmapConsumer>>(); | |
| auto mock_consumer_ptr = mock_consumer.get(); | |
| EXPECT_CALL(*mock_consumer_ptr, Push(testing::_)) | |
| .WillOnce([&](std::unique_ptr<const Heatmap> heatmap) { | |
| EXPECT_EQ(heatmap->vendor_id, 0); | |
| EXPECT_EQ(heatmap->protocol_version, 1); | |
| EXPECT_EQ(heatmap->scan_time, 2); | |
| EXPECT_EQ(heatmap->encoding, 1); | |
| EXPECT_EQ(heatmap->bit_depth, 8); | |
| EXPECT_EQ(heatmap->threshold, 10); | |
| EXPECT_EQ(heatmap->height, height); | |
| EXPECT_EQ(heatmap->width, width); | |
| EXPECT_EQ(heatmap->length, param.expected_heatmap_size); | |
| EXPECT_EQ(heatmap->payload.size(), param.expected_heatmap_size); | |
| // Validate payload. | |
| validatePayload(heatmap, payload_8bit_6_by_5, /*num_bytes=*/1); | |
| }); | |
| auto reshaper = std::make_unique<Reshaper>( | |
| Crop{ | |
| param.crop_bottom, | |
| param.crop_left, | |
| param.crop_right, | |
| param.crop_top, | |
| }, | |
| std::move(mock_consumer)); | |
| reshaper->Push(std::move(heatmap_8bit)); | |
| task_environment_.RunUntilIdle(); | |
| } | |
| TEST_P(ReshaperBeyondBoundsTest, Crop12BitBeyondBounds) { | |
| std::unique_ptr<Heatmap> heatmap_12bit = std::make_unique<Heatmap>(Heatmap{ | |
| 0, // Vendor id. | |
| 1, // Protocol version. | |
| 4, // Scan time. | |
| kDiffData, // Encoding. | |
| 12, // Bit Depth. | |
| height, // Height. | |
| width, // Width. | |
| 10, // Threshold. | |
| 60, // Payload length in bytes. | |
| payload_12bit_6_by_5, // Payload. | |
| }); | |
| touchraw::test::ReshaperTestParam param = GetParam(); | |
| auto mock_consumer = | |
| std::make_unique<testing::StrictMock<MockHeatmapConsumer>>(); | |
| auto mock_consumer_ptr = mock_consumer.get(); | |
| EXPECT_CALL(*mock_consumer_ptr, Push(testing::_)) | |
| .WillOnce([&](std::unique_ptr<const Heatmap> heatmap) { | |
| EXPECT_EQ(heatmap->vendor_id, 0); | |
| EXPECT_EQ(heatmap->protocol_version, 1); | |
| EXPECT_EQ(heatmap->scan_time, 4); | |
| EXPECT_EQ(heatmap->encoding, 1); | |
| EXPECT_EQ(heatmap->bit_depth, 12); | |
| EXPECT_EQ(heatmap->threshold, 10); | |
| EXPECT_EQ(heatmap->height, height); | |
| EXPECT_EQ(heatmap->width, width); | |
| EXPECT_EQ(heatmap->length, 2 * param.expected_heatmap_size); | |
| EXPECT_EQ(heatmap->payload.size(), 2 * param.expected_heatmap_size); | |
| // Validate payload. | |
| validatePayload(heatmap, payload_12bit_6_by_5, /*num_bytes=*/2); | |
| }); | |
| auto reshaper = std::make_unique<Reshaper>( | |
| Crop{ | |
| param.crop_bottom, | |
| param.crop_left, | |
| param.crop_right, | |
| param.crop_top, | |
| }, | |
| std::move(mock_consumer)); | |
| reshaper->Push(std::move(heatmap_12bit)); | |
| task_environment_.RunUntilIdle(); | |
| } | |
| TEST_P(ReshaperBeyondBoundsTest, Crop16BitBeyondBounds) { | |
| std::unique_ptr<Heatmap> heatmap_16bit = std::make_unique<Heatmap>(Heatmap{ | |
| 0, // Vendor id. | |
| 1, // Protocol version. | |
| 4, // Scan time. | |
| kDiffData, // Encoding. | |
| 16, // Bit Depth. | |
| height, // Height. | |
| width, // Width. | |
| 10, // Threshold. | |
| 60, // Payload length in bytes. | |
| payload_16bit_6_by_5, // Payload. | |
| }); | |
| touchraw::test::ReshaperTestParam param = GetParam(); | |
| auto mock_consumer = | |
| std::make_unique<testing::StrictMock<MockHeatmapConsumer>>(); | |
| auto mock_consumer_ptr = mock_consumer.get(); | |
| EXPECT_CALL(*mock_consumer_ptr, Push(testing::_)) | |
| .WillOnce([&](std::unique_ptr<const Heatmap> heatmap) { | |
| EXPECT_EQ(heatmap->vendor_id, 0); | |
| EXPECT_EQ(heatmap->protocol_version, 1); | |
| EXPECT_EQ(heatmap->scan_time, 4); | |
| EXPECT_EQ(heatmap->encoding, 1); | |
| EXPECT_EQ(heatmap->bit_depth, 16); | |
| EXPECT_EQ(heatmap->threshold, 10); | |
| EXPECT_EQ(heatmap->height, height); | |
| EXPECT_EQ(heatmap->width, width); | |
| EXPECT_EQ(heatmap->length, 2 * param.expected_heatmap_size); | |
| EXPECT_EQ(heatmap->payload.size(), 2 * param.expected_heatmap_size); | |
| // Validate payload. | |
| validatePayload(heatmap, payload_16bit_6_by_5, /*num_bytes=*/2); | |
| }); | |
| auto reshaper = std::make_unique<Reshaper>( | |
| Crop{ | |
| param.crop_bottom, | |
| param.crop_left, | |
| param.crop_right, | |
| param.crop_top, | |
| }, | |
| std::move(mock_consumer)); | |
| reshaper->Push(std::move(heatmap_16bit)); | |
| task_environment_.RunUntilIdle(); | |
| } | |
| INSTANTIATE_TEST_SUITE_P( | |
| ReshaperSuite, | |
| ReshaperTest, | |
| testing::Values( | |
| touchraw::test::ReshaperTestParam{1, 1, 1, 1, 12, | |
| "CropAllSidesEqually"}, | |
| touchraw::test::ReshaperTestParam{0, 0, 0, 2, 18, "CropTopBy2"}, | |
| touchraw::test::ReshaperTestParam{0, 2, 0, 0, 20, "CropLeftBy2"}, | |
| touchraw::test::ReshaperTestParam{1, 0, 0, 0, 24, "CropBottomBy1"}, | |
| touchraw::test::ReshaperTestParam{0, 0, 1, 0, 25, "CropRightBy1"}, | |
| touchraw::test::ReshaperTestParam{0, 5, 0, 4, 1, | |
| "CropTillBottomRightCell"}, | |
| touchraw::test::ReshaperTestParam{0, 0, 6, 0, 0, "CropAllFromRight"}, | |
| touchraw::test::ReshaperTestParam{5, 0, 0, 0, 0, "CropAllFromBottom"}, | |
| touchraw::test::ReshaperTestParam{5, 0, 6, 0, 0, "CropAllBottomRight"}), | |
| [](const testing::TestParamInfo<ReshaperTest::ParamType>& info) { | |
| return info.param.name; | |
| }); | |
| INSTANTIATE_TEST_SUITE_P( | |
| ReshaperSuite, | |
| ReshaperBeyondBoundsTest, | |
| testing::Values( | |
| touchraw::test::ReshaperTestParam{6, 0, 0, 0, 30, | |
| "CropBeyondBoundsFromBottom"}, | |
| touchraw::test::ReshaperTestParam{0, 7, 0, 0, 30, | |
| "CropBeyondBoundsFromLeft"}), | |
| [](const testing::TestParamInfo<ReshaperTest::ParamType>& info) { | |
| return info.param.name; | |
| }); | |
| } // namespace touchraw |