blob: b8f411e054b233f30c2d76e267f869f24b4d0e9e [file]
/// Copyright 2025 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <bitset>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "libec/ec_command.h"
#include "libec/fingerprint/fp_info_command.h"
namespace ec {
namespace {
using ::testing::ElementsAre;
using ::testing::Eq;
using ::testing::Return;
TEST(FpInfoCommand_v2, FpInfoCommand_v2) {
auto cmd = std::make_unique<FpInfoCommand_v2>();
EXPECT_TRUE(cmd);
EXPECT_EQ(cmd->Version(), 2);
EXPECT_EQ(cmd->Command(), EC_CMD_FP_INFO);
EXPECT_EQ(cmd->RespSize(),
sizeof(struct fp_info::Header_v2) +
FP_MAX_CAPTURE_TYPES * sizeof(struct fp_image_frame_params));
}
/**
* Tests FpInfoCommand_v2's "errors()" method.
*/
class FpInfoCommand_v2_ErrorsTest : public testing::Test {
public:
class MockFpInfoCommand_v2 : public FpInfoCommand_v2 {
public:
MOCK_METHOD(fp_info::Params_v2*, Resp, (), (override));
};
MockFpInfoCommand_v2 mock_fp_info_command_;
};
TEST_F(FpInfoCommand_v2_ErrorsTest, Errors_None) {
EXPECT_CALL(mock_fp_info_command_, Resp).WillOnce(Return(nullptr));
EXPECT_EQ(mock_fp_info_command_.GetFpSensorErrors(), FpSensorErrors::kNone);
}
TEST_F(FpInfoCommand_v2_ErrorsTest, Errors_NoIrq) {
struct fp_info::Params_v2 resp = {
.info = {.sensor_info = {.errors = FP_ERROR_NO_IRQ |
FP_ERROR_DEAD_PIXELS_UNKNOWN}}};
EXPECT_CALL(mock_fp_info_command_, Resp).WillRepeatedly(Return(&resp));
EXPECT_EQ(mock_fp_info_command_.GetFpSensorErrors(), FpSensorErrors::kNoIrq);
}
TEST_F(FpInfoCommand_v2_ErrorsTest, Errors_SpiCommunication) {
struct fp_info::Params_v2 resp = {
.info = {.sensor_info = {.errors = FP_ERROR_SPI_COMM |
FP_ERROR_DEAD_PIXELS_UNKNOWN}}};
EXPECT_CALL(mock_fp_info_command_, Resp).WillRepeatedly(Return(&resp));
EXPECT_EQ(mock_fp_info_command_.GetFpSensorErrors(),
FpSensorErrors::kSpiCommunication);
}
TEST_F(FpInfoCommand_v2_ErrorsTest, Errors_BadHardwareID) {
struct fp_info::Params_v2 resp = {
.info = {.sensor_info = {.errors = FP_ERROR_BAD_HWID |
FP_ERROR_DEAD_PIXELS_UNKNOWN}}};
EXPECT_CALL(mock_fp_info_command_, Resp).WillRepeatedly(Return(&resp));
EXPECT_EQ(mock_fp_info_command_.GetFpSensorErrors(),
FpSensorErrors::kBadHardwareID);
}
TEST_F(FpInfoCommand_v2_ErrorsTest, Errors_InitializationFailure) {
struct fp_info::Params_v2 resp = {
.info = {.sensor_info = {.errors = FP_ERROR_INIT_FAIL |
FP_ERROR_DEAD_PIXELS_UNKNOWN}}};
EXPECT_CALL(mock_fp_info_command_, Resp).WillRepeatedly(Return(&resp));
EXPECT_EQ(mock_fp_info_command_.GetFpSensorErrors(),
FpSensorErrors::kInitializationFailure);
}
TEST_F(FpInfoCommand_v2_ErrorsTest, Errors_DeadPixels_0) {
struct fp_info::Params_v2 resp = {
.info = {.sensor_info = {.errors = FP_ERROR_DEAD_PIXELS(0)}}};
EXPECT_CALL(mock_fp_info_command_, Resp).WillRepeatedly(Return(&resp));
EXPECT_EQ(mock_fp_info_command_.GetFpSensorErrors(), FpSensorErrors::kNone);
}
TEST_F(FpInfoCommand_v2_ErrorsTest, Errors_DeadPixels_1) {
struct fp_info::Params_v2 resp = {
.info = {.sensor_info = {.errors = FP_ERROR_DEAD_PIXELS(1)}}};
EXPECT_CALL(mock_fp_info_command_, Resp).WillRepeatedly(Return(&resp));
EXPECT_EQ(mock_fp_info_command_.GetFpSensorErrors(),
FpSensorErrors::kDeadPixels);
}
TEST_F(FpInfoCommand_v2_ErrorsTest, Errors_Multiple) {
struct fp_info::Params_v2 resp = {
.info = {.sensor_info = {.errors = FP_ERROR_DEAD_PIXELS(1) |
FP_ERROR_BAD_HWID}}};
EXPECT_CALL(mock_fp_info_command_, Resp).WillRepeatedly(Return(&resp));
EXPECT_EQ(mock_fp_info_command_.GetFpSensorErrors(),
FpSensorErrors::kDeadPixels | FpSensorErrors::kBadHardwareID);
}
/** Tests FpInfoCommand_v2's "NumDeadPixels()" method. */
class FpInfoCommand_v2_NumDeadPixelsTest : public testing::Test {
public:
class MockFpInfoCommand_v2 : public FpInfoCommand_v2 {
public:
MOCK_METHOD(fp_info::Params_v2*, Resp, (), (override));
};
MockFpInfoCommand_v2 mock_fp_info_command_;
};
TEST_F(FpInfoCommand_v2_NumDeadPixelsTest, NoResponse) {
EXPECT_CALL(mock_fp_info_command_, Resp).WillRepeatedly(Return(nullptr));
const auto expected = FpInfoCommand::kDeadPixelsUnknown;
EXPECT_EQ(mock_fp_info_command_.NumDeadPixels(), expected);
}
TEST_F(FpInfoCommand_v2_NumDeadPixelsTest, DeadPixelsUnknown) {
struct fp_info::Params_v2 resp = {
.info = {.sensor_info = {.errors = FP_ERROR_BAD_HWID |
FP_ERROR_DEAD_PIXELS_UNKNOWN}}};
EXPECT_CALL(mock_fp_info_command_, Resp).WillRepeatedly(Return(&resp));
const auto expected = FpInfoCommand::kDeadPixelsUnknown;
EXPECT_EQ(mock_fp_info_command_.NumDeadPixels(), expected);
}
TEST_F(FpInfoCommand_v2_NumDeadPixelsTest, ZeroDeadPixels) {
struct fp_info::Params_v2 resp = {
.info = {.sensor_info = {.errors = FP_ERROR_INIT_FAIL |
FP_ERROR_DEAD_PIXELS(0)}}};
EXPECT_CALL(mock_fp_info_command_, Resp).WillRepeatedly(Return(&resp));
EXPECT_EQ(mock_fp_info_command_.NumDeadPixels(), 0);
}
TEST_F(FpInfoCommand_v2_NumDeadPixelsTest, OneDeadPixel) {
struct fp_info::Params_v2 resp = {
.info = {.sensor_info = {.errors = FP_ERROR_SPI_COMM |
FP_ERROR_DEAD_PIXELS(1)}}};
EXPECT_CALL(mock_fp_info_command_, Resp).WillRepeatedly(Return(&resp));
EXPECT_EQ(mock_fp_info_command_.NumDeadPixels(), 1);
}
/**
* Tests FpInfoCommand_v2's "sensor_id" method.
*/
class FpInfoCommand_v2_SensorIdTest : public testing::Test {
public:
class MockFpInfoCommand_v2 : public FpInfoCommand_v2 {
public:
MOCK_METHOD(fp_info::Params_v2*, Resp, (), (override));
};
MockFpInfoCommand_v2 mock_fp_info_command;
};
TEST_F(FpInfoCommand_v2_SensorIdTest, NullResponse) {
EXPECT_CALL(mock_fp_info_command, Resp).WillRepeatedly(Return(nullptr));
EXPECT_EQ(mock_fp_info_command.sensor_id(), std::nullopt);
}
TEST_F(FpInfoCommand_v2_SensorIdTest, ValidSensorId) {
struct fp_info::Params_v2 resp = {.info = {.sensor_info = {.vendor_id = 1,
.product_id = 2,
.model_id = 3,
.version = 4}}};
EXPECT_CALL(mock_fp_info_command, Resp).WillRepeatedly(Return(&resp));
EXPECT_THAT(mock_fp_info_command.sensor_id().value(), Eq(SensorId{
.vendor_id = 1,
.product_id = 2,
.model_id = 3,
.version = 4,
}));
}
/**
* Tests FpInfoCommand_v2's "sensor_image" method.
*/
class FpInfoCommand_v2_SensorImageTest : public testing::Test {
public:
class MockFpInfoCommand_v2 : public FpInfoCommand_v2 {
public:
MOCK_METHOD(fp_info::Params_v2*, Resp, (), (override));
};
MockFpInfoCommand_v2 mock_fp_info_command;
};
TEST_F(FpInfoCommand_v2_SensorImageTest, NullResponse) {
EXPECT_CALL(mock_fp_info_command, Resp).WillRepeatedly(Return(nullptr));
EXPECT_TRUE(mock_fp_info_command.sensor_image().empty());
}
TEST_F(FpInfoCommand_v2_SensorImageTest, ZeroCaptureImages) {
struct fp_info::Params_v2 resp = {.info = {.sensor_info = {
.num_capture_types = 0,
}}};
EXPECT_CALL(mock_fp_info_command, Resp).WillRepeatedly(Return(&resp));
EXPECT_TRUE(mock_fp_info_command.sensor_image().empty());
}
TEST_F(FpInfoCommand_v2_SensorImageTest, ValidSensorImage) {
struct fp_info::Params_v2 resp;
resp.info.sensor_info.num_capture_types = 2;
resp.image_frame_params[0] = {.frame_size = 5120,
.pixel_format = 0x59455247,
.width = 64,
.height = 80,
.bpp = 8,
.fp_capture_type = FP_CAPTURE_SIMPLE_IMAGE};
resp.image_frame_params[1] = {.frame_size = 36864,
.pixel_format = 0x59455247,
.width = 192,
.height = 96,
.bpp = 16,
.fp_capture_type = FP_CAPTURE_PATTERN0};
EXPECT_CALL(mock_fp_info_command, Resp).WillRepeatedly(Return(&resp));
EXPECT_THAT(
mock_fp_info_command.sensor_image(),
ElementsAre(SensorImage{.width = 64,
.height = 80,
.frame_size = 5120,
.pixel_format = 0x59455247,
.bpp = 8,
.fp_capture_type = FP_CAPTURE_SIMPLE_IMAGE},
SensorImage{.width = 192,
.height = 96,
.frame_size = 36864,
.pixel_format = 0x59455247,
.bpp = 16,
.fp_capture_type = FP_CAPTURE_PATTERN0}));
}
/**
* Tests FpInfoCommand_v2's "template_info" method.
*/
class FpInfoCommand_v2_TemplateInfoTest : public testing::Test {
public:
class MockFpInfoCommand_v2 : public FpInfoCommand_v2 {
public:
MOCK_METHOD(fp_info::Params_v2*, Resp, (), (override));
};
MockFpInfoCommand_v2 mock_fp_info_command;
};
TEST_F(FpInfoCommand_v2_TemplateInfoTest, NullResponse) {
EXPECT_CALL(mock_fp_info_command, Resp).WillRepeatedly(Return(nullptr));
EXPECT_EQ(mock_fp_info_command.template_info(), std::nullopt);
}
TEST_F(FpInfoCommand_v2_TemplateInfoTest, ValidTemplateInfo) {
struct fp_info::Params_v2 resp = {
.info = {.template_info = {.template_size = 1024,
.template_max = 4,
.template_valid = 3,
.template_dirty = 1 << 3,
.template_version = 1}}};
EXPECT_CALL(mock_fp_info_command, Resp).WillRepeatedly(Return(&resp));
EXPECT_THAT(mock_fp_info_command.template_info().value(),
Eq(TemplateInfo{
.version = 1,
.size = 1024,
.max_templates = 4,
.num_valid = 3,
.dirty = std::bitset<32>(1 << 3),
}));
}
} // namespace
} // namespace ec