/* * Unit tests for validity sensor identification and HAL tables * * Copyright (C) 2024 libfprint contributors * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. */ #include #include #include "fpi-byte-utils.h" #include "drivers/validity/validity_sensor.h" /* ================================================================ * T4.1: test_identify_sensor_parse * * Verify that a valid cmd 0x75 response is parsed correctly into * a ValiditySensorIdent (hw_major + hw_version). * * Wire format (after 2-byte status stripped): * [zeroes:4 LE] [version:2 LE] [major:2 LE] * ================================================================ */ static void test_identify_sensor_parse (void) { ValiditySensorIdent ident; /* Build synthetic response: zeroes=0, version=0x13, major=0x004a */ guint8 data[8]; FP_WRITE_UINT32_LE (&data[0], 0); /* zeroes */ FP_WRITE_UINT16_LE (&data[4], 0x0013); /* version */ FP_WRITE_UINT16_LE (&data[6], 0x004a); /* major */ gboolean ok = validity_sensor_parse_identify (data, sizeof (data), &ident); g_assert_true (ok); g_assert_cmpuint (ident.hw_major, ==, 0x004a); g_assert_cmpuint (ident.hw_version, ==, 0x0013); } /* ================================================================ * T4.2: test_identify_sensor_parse_truncated * * Verify that a response shorter than 8 bytes returns FALSE. * ================================================================ */ static void test_identify_sensor_parse_truncated (void) { ValiditySensorIdent ident; guint8 data[7] = { 0 }; g_assert_false (validity_sensor_parse_identify (data, sizeof (data), &ident)); /* Also test with 0 length */ g_assert_false (validity_sensor_parse_identify (data, 0, &ident)); } /* ================================================================ * T4.3: test_device_info_lookup_exact * * Verify that lookup with major=0x004a, version=0x13 returns the * correct DeviceInfo for the ThinkPad T480s sensor. * ================================================================ */ static void test_device_info_lookup_exact (void) { const ValidityDeviceInfo *info; info = validity_device_info_lookup (0x004a, 0x13); g_assert_nonnull (info); g_assert_cmpuint (info->major, ==, 0x004a); g_assert_cmpuint (info->type, ==, 0x00b5); g_assert_cmpuint (info->version, ==, 0x13); g_assert_cmpstr (info->name, ==, "SYN 57K0 FM3297-02"); } /* ================================================================ * T4.4: test_device_info_lookup_another * * Verify that lookup with major=0x0071, version=0x01 returns * the VSI 55E entry (type 0xdb). * ================================================================ */ static void test_device_info_lookup_another (void) { const ValidityDeviceInfo *info; info = validity_device_info_lookup (0x0071, 0x01); g_assert_nonnull (info); g_assert_cmpuint (info->type, ==, 0x00db); g_assert_cmpstr (info->name, ==, "VSI 55E FM72-001"); } /* ================================================================ * T4.5: test_device_info_lookup_unknown * * Verify that a completely unknown major returns NULL. * ================================================================ */ static void test_device_info_lookup_unknown (void) { const ValidityDeviceInfo *info; info = validity_device_info_lookup (0xffff, 0x01); g_assert_null (info); } /* ================================================================ * T4.6: test_device_info_lookup_fuzzy * * Verify that when version_mask == 0x00, the entry matches any * version (fuzzy match). * ================================================================ */ static void test_device_info_lookup_fuzzy (void) { const ValidityDeviceInfo *info; /* major=0x0000 entries have version_mask=0x00 → always fuzzy match. * But major=0x0000 needs to match the lookup major. */ info = validity_device_info_lookup (0x0000, 0x42); /* Should match one of the wildcard entries */ g_assert_nonnull (info); g_assert_cmpuint (info->major, ==, 0x0000); } /* ================================================================ * T4.7: test_sensor_type_info_lookup * * Verify lookup of sensor type 0x00b5 returns correct geometry. * ================================================================ */ static void test_sensor_type_info_lookup (void) { const ValiditySensorTypeInfo *info; info = validity_sensor_type_info_lookup (0x00b5); g_assert_nonnull (info); g_assert_cmpuint (info->sensor_type, ==, 0x00b5); g_assert_cmpuint (info->bytes_per_line, ==, 0x78); g_assert_cmpuint (info->repeat_multiplier, ==, 2); g_assert_cmpuint (info->lines_per_calibration_data, ==, 112); g_assert_cmpuint (info->line_width, ==, 112); g_assert_nonnull (info->calibration_blob); g_assert_cmpuint (info->calibration_blob_len, ==, 112); } /* ================================================================ * T4.8: test_sensor_type_info_lookup_db * * Verify lookup of sensor type 0x00db (55E) returns correct geometry. * ================================================================ */ static void test_sensor_type_info_lookup_db (void) { const ValiditySensorTypeInfo *info; info = validity_sensor_type_info_lookup (0x00db); g_assert_nonnull (info); g_assert_cmpuint (info->bytes_per_line, ==, 0x98); g_assert_cmpuint (info->repeat_multiplier, ==, 1); g_assert_cmpuint (info->lines_per_calibration_data, ==, 144); g_assert_cmpuint (info->line_width, ==, 144); } /* ================================================================ * T4.9: test_sensor_type_info_lookup_unknown * * Verify that an unknown sensor type returns NULL. * ================================================================ */ static void test_sensor_type_info_lookup_unknown (void) { g_assert_null (validity_sensor_type_info_lookup (0xbeef)); } /* ================================================================ * T4.10: test_factory_bits_cmd_format * * Verify that the factory bits command is built correctly. * Expected: [0x6f] [0x00 0x0e] [0x00 0x00] [0x00 0x00 0x00 0x00] * ================================================================ */ static void test_factory_bits_cmd_format (void) { guint8 buf[16]; gsize len; len = validity_sensor_build_factory_bits_cmd (0x0e00, buf, sizeof (buf)); g_assert_cmpuint (len, ==, 9); g_assert_cmpuint (buf[0], ==, 0x6f); /* tag = 0x0e00 LE */ g_assert_cmpuint (buf[1], ==, 0x00); g_assert_cmpuint (buf[2], ==, 0x0e); /* pad 2 bytes */ g_assert_cmpuint (buf[3], ==, 0x00); g_assert_cmpuint (buf[4], ==, 0x00); /* pad 4 bytes */ g_assert_cmpuint (buf[5], ==, 0x00); g_assert_cmpuint (buf[6], ==, 0x00); g_assert_cmpuint (buf[7], ==, 0x00); g_assert_cmpuint (buf[8], ==, 0x00); } /* ================================================================ * T4.11: test_factory_bits_cmd_buffer_too_small * * Verify that a too-small buffer returns 0. * ================================================================ */ static void test_factory_bits_cmd_buffer_too_small (void) { guint8 buf[4]; gsize len; len = validity_sensor_build_factory_bits_cmd (0x0e00, buf, sizeof (buf)); g_assert_cmpuint (len, ==, 0); } /* ================================================================ * T4.12: test_identify_then_lookup * * End-to-end: parse identify_sensor response → DeviceInfo lookup → * SensorTypeInfo lookup. Simulates the T480s sensor (06cb:009a). * ================================================================ */ static void test_identify_then_lookup (void) { ValiditySensorIdent ident; const ValidityDeviceInfo *dev_info; const ValiditySensorTypeInfo *type_info; /* Simulate cmd 0x75 response for T480s: major=0x004a, version=0x13 */ guint8 data[8]; FP_WRITE_UINT32_LE (&data[0], 0); FP_WRITE_UINT16_LE (&data[4], 0x0013); FP_WRITE_UINT16_LE (&data[6], 0x004a); g_assert_true (validity_sensor_parse_identify (data, sizeof (data), &ident)); g_assert_cmpuint (ident.hw_major, ==, 0x004a); g_assert_cmpuint (ident.hw_version, ==, 0x0013); dev_info = validity_device_info_lookup (ident.hw_major, ident.hw_version); g_assert_nonnull (dev_info); g_assert_cmpuint (dev_info->type, ==, 0x00b5); type_info = validity_sensor_type_info_lookup (dev_info->type); g_assert_nonnull (type_info); g_assert_cmpuint (type_info->bytes_per_line, ==, 0x78); g_assert_cmpuint (type_info->line_width, ==, 112); } /* ================================================================ * T4.13: test_sensor_state_lifecycle * * Verify that init zeros the state and clear frees allocated data. * ================================================================ */ static void test_sensor_state_lifecycle (void) { ValiditySensorState state; validity_sensor_state_init (&state); g_assert_null (state.device_info); g_assert_null (state.type_info); g_assert_null (state.factory_bits); g_assert_cmpuint (state.factory_bits_len, ==, 0); /* Simulate storing factory bits */ state.factory_bits = g_memdup2 ("\x01\x02\x03", 3); state.factory_bits_len = 3; validity_sensor_state_clear (&state); g_assert_null (state.factory_bits); g_assert_cmpuint (state.factory_bits_len, ==, 0); } /* ================================================================ * T4.14: test_calibration_blob_present * * Verify that the calibration blob for type 0x00b5 has expected * first and last bytes (from python-validity generated_tables). * ================================================================ */ static void test_calibration_blob_present (void) { const ValiditySensorTypeInfo *info; info = validity_sensor_type_info_lookup (0x00b5); g_assert_nonnull (info); g_assert_nonnull (info->calibration_blob); g_assert_cmpuint (info->calibration_blob_len, ==, 112); /* First byte: 0x9b, last byte: 0x06 */ g_assert_cmpuint (info->calibration_blob[0], ==, 0x9b); g_assert_cmpuint (info->calibration_blob[111], ==, 0x06); } int main (int argc, char *argv[]) { g_test_init (&argc, &argv, NULL); g_test_add_func ("/validity/sensor/identify/parse", test_identify_sensor_parse); g_test_add_func ("/validity/sensor/identify/truncated", test_identify_sensor_parse_truncated); g_test_add_func ("/validity/sensor/devinfo/lookup_exact", test_device_info_lookup_exact); g_test_add_func ("/validity/sensor/devinfo/lookup_another", test_device_info_lookup_another); g_test_add_func ("/validity/sensor/devinfo/lookup_unknown", test_device_info_lookup_unknown); g_test_add_func ("/validity/sensor/devinfo/lookup_fuzzy", test_device_info_lookup_fuzzy); g_test_add_func ("/validity/sensor/typeinfo/lookup", test_sensor_type_info_lookup); g_test_add_func ("/validity/sensor/typeinfo/lookup_db", test_sensor_type_info_lookup_db); g_test_add_func ("/validity/sensor/typeinfo/lookup_unknown", test_sensor_type_info_lookup_unknown); g_test_add_func ("/validity/sensor/factory_bits/cmd_format", test_factory_bits_cmd_format); g_test_add_func ("/validity/sensor/factory_bits/buffer_too_small", test_factory_bits_cmd_buffer_too_small); g_test_add_func ("/validity/sensor/identify_then_lookup", test_identify_then_lookup); g_test_add_func ("/validity/sensor/state_lifecycle", test_sensor_state_lifecycle); g_test_add_func ("/validity/sensor/calibration_blob_present", test_calibration_blob_present); return g_test_run (); }