libfprint/tests/test-validity-db.c
Leonardo Francisco 4bf976c7b5 validity: fix code style (uncrustify) and test assertions
Apply uncrustify formatting to all validity driver and test files
to pass the CI test_indent check.

Fix two pre-existing test failures:
- test-validity-capture: LED command blobs are 125 bytes, not 128
- test-validity-enroll: add 2-byte length prefix to test data to
  match parser's expected format, fix empty-data assertion (parser
  returns FALSE for data_len < 2)

All 41 tests pass, 0 failures.
2026-04-22 03:06:34 +00:00

764 lines
27 KiB
C

/*
* Unit tests for validity database operations
*
* 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 <glib.h>
#include <string.h>
#include "fpi-byte-utils.h"
#include "drivers/validity/validity_db.h"
#include "drivers/validity/validity.h"
#include "drivers/validity/vcsfw_protocol.h"
/* ================================================================
* T6.1: test_cmd_db_info
*
* Verify cmd 0x45 (DB info) is a single-byte command.
* ================================================================ */
static void
test_cmd_db_info (void)
{
gsize len;
g_autofree guint8 *cmd = validity_db_build_cmd_info (&len);
g_assert_nonnull (cmd);
g_assert_cmpuint (len, ==, 1);
g_assert_cmpuint (cmd[0], ==, VCSFW_CMD_DB_INFO);
}
/* ================================================================
* T6.2: test_cmd_get_user_storage
*
* Verify cmd 0x4B format with a known storage name.
* ================================================================ */
static void
test_cmd_get_user_storage (void)
{
gsize len;
const gchar *name = "StgWindsor";
gsize name_len = strlen (name) + 1; /* includes NUL */
g_autofree guint8 *cmd = validity_db_build_cmd_get_user_storage (name, &len);
g_assert_nonnull (cmd);
g_assert_cmpuint (len, ==, 1 + 2 + 2 + name_len); /* cmd + dbid + name_len + name */
g_assert_cmpuint (cmd[0], ==, VCSFW_CMD_GET_USER_STORAGE);
g_assert_cmpuint (FP_READ_UINT16_LE (&cmd[1]), ==, 0); /* dbid = 0 → lookup by name */
g_assert_cmpuint (FP_READ_UINT16_LE (&cmd[3]), ==, name_len);
g_assert_cmpmem (&cmd[5], name_len, name, name_len);
}
/* ================================================================
* T6.3: test_cmd_get_user_storage_null_name
*
* When name is NULL, should produce a command with zero name_len.
* ================================================================ */
static void
test_cmd_get_user_storage_null_name (void)
{
gsize len;
g_autofree guint8 *cmd = validity_db_build_cmd_get_user_storage (NULL, &len);
g_assert_nonnull (cmd);
g_assert_cmpuint (len, ==, 5); /* cmd(1) + dbid(2) + name_len(2) */
g_assert_cmpuint (cmd[0], ==, VCSFW_CMD_GET_USER_STORAGE);
g_assert_cmpuint (FP_READ_UINT16_LE (&cmd[3]), ==, 0); /* name_len = 0 */
}
/* ================================================================
* T6.4: test_cmd_get_user
*
* Verify cmd 0x4A format for get-by-dbid.
* ================================================================ */
static void
test_cmd_get_user (void)
{
gsize len;
g_autofree guint8 *cmd = validity_db_build_cmd_get_user (0x1234, &len);
g_assert_nonnull (cmd);
g_assert_cmpuint (len, ==, 7);
g_assert_cmpuint (cmd[0], ==, VCSFW_CMD_GET_USER);
g_assert_cmpuint (FP_READ_UINT16_LE (&cmd[1]), ==, 0x1234);
g_assert_cmpuint (FP_READ_UINT16_LE (&cmd[3]), ==, 0);
g_assert_cmpuint (FP_READ_UINT16_LE (&cmd[5]), ==, 0);
}
/* ================================================================
* T6.5: test_cmd_lookup_user
*
* Verify cmd 0x4A format for lookup-by-identity.
* ================================================================ */
static void
test_cmd_lookup_user (void)
{
gsize len;
guint8 identity[] = { 0x01, 0x02, 0x03, 0x04 };
g_autofree guint8 *cmd = validity_db_build_cmd_lookup_user (
0x0003, identity, sizeof (identity), &len);
g_assert_nonnull (cmd);
g_assert_cmpuint (len, ==, 7 + sizeof (identity));
g_assert_cmpuint (cmd[0], ==, VCSFW_CMD_GET_USER);
g_assert_cmpuint (FP_READ_UINT16_LE (&cmd[1]), ==, 0); /* dbid = 0 */
g_assert_cmpuint (FP_READ_UINT16_LE (&cmd[3]), ==, 0x0003); /* storage */
g_assert_cmpuint (FP_READ_UINT16_LE (&cmd[5]), ==, sizeof (identity));
g_assert_cmpmem (&cmd[7], sizeof (identity), identity, sizeof (identity));
}
/* ================================================================
* T6.6: test_cmd_new_record
*
* Verify cmd 0x47 format.
* ================================================================ */
static void
test_cmd_new_record (void)
{
gsize len;
guint8 data[] = { 0xAA, 0xBB };
g_autofree guint8 *cmd = validity_db_build_cmd_new_record (
0x0003, 0x0005, 0x0003, data, sizeof (data), &len);
g_assert_nonnull (cmd);
g_assert_cmpuint (len, ==, 9 + sizeof (data));
g_assert_cmpuint (cmd[0], ==, VCSFW_CMD_NEW_RECORD);
g_assert_cmpuint (FP_READ_UINT16_LE (&cmd[1]), ==, 0x0003); /* parent */
g_assert_cmpuint (FP_READ_UINT16_LE (&cmd[3]), ==, 0x0005); /* type */
g_assert_cmpuint (FP_READ_UINT16_LE (&cmd[5]), ==, 0x0003); /* storage */
g_assert_cmpuint (FP_READ_UINT16_LE (&cmd[7]), ==, sizeof (data));
g_assert_cmpmem (&cmd[9], sizeof (data), data, sizeof (data));
}
/* ================================================================
* T6.7: test_cmd_del_record
*
* Verify cmd 0x48 format.
* ================================================================ */
static void
test_cmd_del_record (void)
{
gsize len;
g_autofree guint8 *cmd = validity_db_build_cmd_del_record (0xABCD, &len);
g_assert_nonnull (cmd);
g_assert_cmpuint (len, ==, 3);
g_assert_cmpuint (cmd[0], ==, VCSFW_CMD_DEL_RECORD);
g_assert_cmpuint (FP_READ_UINT16_LE (&cmd[1]), ==, 0xABCD);
}
/* ================================================================
* T6.8: test_cmd_create_enrollment
*
* Verify cmd 0x69 start and end variants.
* ================================================================ */
static void
test_cmd_create_enrollment (void)
{
gsize len;
/* Start enrollment */
g_autofree guint8 *cmd_start = validity_db_build_cmd_create_enrollment (TRUE, &len);
g_assert_nonnull (cmd_start);
g_assert_cmpuint (len, ==, 5);
g_assert_cmpuint (cmd_start[0], ==, VCSFW_CMD_CREATE_ENROLLMENT);
g_assert_cmpuint (FP_READ_UINT32_LE (&cmd_start[1]), ==, 1);
/* End enrollment */
g_autofree guint8 *cmd_end = validity_db_build_cmd_create_enrollment (FALSE, &len);
g_assert_nonnull (cmd_end);
g_assert_cmpuint (len, ==, 5);
g_assert_cmpuint (cmd_end[0], ==, VCSFW_CMD_CREATE_ENROLLMENT);
g_assert_cmpuint (FP_READ_UINT32_LE (&cmd_end[1]), ==, 0);
}
/* ================================================================
* T6.9: test_cmd_enrollment_update_start
*
* Verify cmd 0x68 format.
* ================================================================ */
static void
test_cmd_enrollment_update_start (void)
{
gsize len;
g_autofree guint8 *cmd = validity_db_build_cmd_enrollment_update_start (0x12345678, &len);
g_assert_nonnull (cmd);
g_assert_cmpuint (len, ==, 9);
g_assert_cmpuint (cmd[0], ==, VCSFW_CMD_ENROLLMENT_UPDATE_START);
g_assert_cmpuint (FP_READ_UINT32_LE (&cmd[1]), ==, 0x12345678);
g_assert_cmpuint (FP_READ_UINT32_LE (&cmd[5]), ==, 0);
}
/* ================================================================
* T6.10: test_cmd_match_finger
*
* Verify cmd 0x5E format (13 bytes per python-validity).
* ================================================================ */
static void
test_cmd_match_finger (void)
{
gsize len;
g_autofree guint8 *cmd = validity_db_build_cmd_match_finger (&len);
g_assert_nonnull (cmd);
g_assert_cmpuint (len, ==, 13);
g_assert_cmpuint (cmd[0], ==, VCSFW_CMD_MATCH_FINGER);
g_assert_cmpuint (cmd[1], ==, 0x02);
g_assert_cmpuint (cmd[2], ==, 0xFF);
g_assert_cmpuint (FP_READ_UINT16_LE (&cmd[3]), ==, 0);
g_assert_cmpuint (FP_READ_UINT16_LE (&cmd[5]), ==, 0);
g_assert_cmpuint (FP_READ_UINT16_LE (&cmd[7]), ==, 1);
g_assert_cmpuint (FP_READ_UINT16_LE (&cmd[9]), ==, 0);
g_assert_cmpuint (FP_READ_UINT16_LE (&cmd[11]), ==, 0);
}
/* ================================================================
* T6.11: test_cmd_get_match_result
*
* Verify cmd 0x60 format.
* ================================================================ */
static void
test_cmd_get_match_result (void)
{
gsize len;
g_autofree guint8 *cmd = validity_db_build_cmd_get_match_result (&len);
g_assert_nonnull (cmd);
g_assert_cmpuint (len, ==, 5);
g_assert_cmpuint (cmd[0], ==, VCSFW_CMD_GET_MATCH_RESULT);
/* remaining bytes should be 0 */
g_assert_cmpuint (cmd[1], ==, 0);
g_assert_cmpuint (cmd[2], ==, 0);
g_assert_cmpuint (cmd[3], ==, 0);
g_assert_cmpuint (cmd[4], ==, 0);
}
/* ================================================================
* T6.12: test_cmd_match_cleanup
*
* Verify cmd 0x62 format.
* ================================================================ */
static void
test_cmd_match_cleanup (void)
{
gsize len;
g_autofree guint8 *cmd = validity_db_build_cmd_match_cleanup (&len);
g_assert_nonnull (cmd);
g_assert_cmpuint (len, ==, 5);
g_assert_cmpuint (cmd[0], ==, VCSFW_CMD_MATCH_CLEANUP);
}
/* ================================================================
* T6.13: test_cmd_get_prg_status
*
* Verify cmd 0x51 both normal and extended variant.
* ================================================================ */
static void
test_cmd_get_prg_status (void)
{
gsize len;
g_autofree guint8 *normal = validity_db_build_cmd_get_prg_status (FALSE, &len);
g_assert_cmpuint (len, ==, 5);
g_assert_cmpuint (normal[0], ==, VCSFW_CMD_GET_PRG_STATUS);
/* Normal: 00000000 */
g_assert_cmpuint (normal[1], ==, 0);
g_assert_cmpuint (normal[2], ==, 0);
g_assert_cmpuint (normal[3], ==, 0);
g_assert_cmpuint (normal[4], ==, 0);
g_autofree guint8 *ext = validity_db_build_cmd_get_prg_status (TRUE, &len);
g_assert_cmpuint (len, ==, 5);
g_assert_cmpuint (ext[0], ==, VCSFW_CMD_GET_PRG_STATUS);
/* Extended: 00200000 LE */
g_assert_cmpuint (ext[1], ==, 0x00);
g_assert_cmpuint (ext[2], ==, 0x20);
g_assert_cmpuint (ext[3], ==, 0x00);
g_assert_cmpuint (ext[4], ==, 0x00);
}
/* ================================================================
* T6.14: test_cmd_capture_stop
*
* Verify cmd 0x04 format.
* ================================================================ */
static void
test_cmd_capture_stop (void)
{
gsize len;
g_autofree guint8 *cmd = validity_db_build_cmd_capture_stop (&len);
g_assert_nonnull (cmd);
g_assert_cmpuint (len, ==, 1);
g_assert_cmpuint (cmd[0], ==, VCSFW_CMD_CAPTURE_STOP);
}
/* ================================================================
* T6.15: test_cmd_call_cleanups
*
* Verify cmd 0x1a format.
* ================================================================ */
static void
test_cmd_call_cleanups (void)
{
gsize len;
g_autofree guint8 *cmd = validity_db_build_cmd_call_cleanups (&len);
g_assert_nonnull (cmd);
g_assert_cmpuint (len, ==, 1);
g_assert_cmpuint (cmd[0], ==, 0x1a);
}
/* ================================================================
* T6.16: test_parse_db_info
*
* Construct a known db_info binary response and verify parsing.
* ================================================================ */
static void
test_parse_db_info (void)
{
guint8 data[0x1C]; /* 24 bytes header + 4 bytes for 2 roots */
ValidityDbInfo info;
memset (data, 0, sizeof (data));
/* Header: unknown1=1, unknown0=0, total=65536, used=1024, free=64512, records=10, n_roots=2 */
FP_WRITE_UINT32_LE (&data[0], 1); /* unknown1 */
FP_WRITE_UINT32_LE (&data[4], 0); /* unknown0 */
FP_WRITE_UINT32_LE (&data[8], 65536); /* total */
FP_WRITE_UINT32_LE (&data[12], 1024); /* used */
FP_WRITE_UINT32_LE (&data[16], 64512); /* free */
FP_WRITE_UINT16_LE (&data[20], 10); /* records */
FP_WRITE_UINT16_LE (&data[22], 2); /* n_roots */
FP_WRITE_UINT16_LE (&data[24], 0x0001); /* root[0] */
FP_WRITE_UINT16_LE (&data[26], 0x0003); /* root[1] */
g_assert_true (validity_db_parse_info (data, sizeof (data), &info));
g_assert_cmpuint (info.unknown1, ==, 1);
g_assert_cmpuint (info.unknown0, ==, 0);
g_assert_cmpuint (info.total, ==, 65536);
g_assert_cmpuint (info.used, ==, 1024);
g_assert_cmpuint (info.free_space, ==, 64512);
g_assert_cmpuint (info.records, ==, 10);
g_assert_cmpuint (info.n_roots, ==, 2);
g_assert_nonnull (info.roots);
g_assert_cmpuint (info.roots[0], ==, 1);
g_assert_cmpuint (info.roots[1], ==, 3);
validity_db_info_clear (&info);
}
/* ================================================================
* T6.17: test_parse_db_info_too_short
*
* A response shorter than 24 bytes should fail.
* ================================================================ */
static void
test_parse_db_info_too_short (void)
{
guint8 data[20] = { 0 };
ValidityDbInfo info;
g_assert_false (validity_db_parse_info (data, sizeof (data), &info));
}
/* ================================================================
* T6.18: test_parse_user_storage
*
* Construct a user storage response with 2 users and verify.
* ================================================================ */
static void
test_parse_user_storage (void)
{
/* Header: dbid=3, user_count=2, name_sz=11, unknown=0
* User table: {dbid=10, val_sz=100}, {dbid=11, val_sz=200}
* Name: "StgWindsor\0" */
gsize name_len = strlen ("StgWindsor") + 1;
gsize total = 8 + 2 * 4 + name_len;
g_autofree guint8 *data = g_new0 (guint8, total);
FP_WRITE_UINT16_LE (&data[0], 3); /* dbid */
FP_WRITE_UINT16_LE (&data[2], 2); /* user_count */
FP_WRITE_UINT16_LE (&data[4], name_len); /* name_sz */
FP_WRITE_UINT16_LE (&data[6], 0); /* unknown */
FP_WRITE_UINT16_LE (&data[8], 10); /* user[0].dbid */
FP_WRITE_UINT16_LE (&data[10], 100); /* user[0].val_sz */
FP_WRITE_UINT16_LE (&data[12], 11); /* user[1].dbid */
FP_WRITE_UINT16_LE (&data[14], 200); /* user[1].val_sz */
memcpy (&data[16], "StgWindsor", name_len);
ValidityUserStorage storage;
g_assert_true (validity_db_parse_user_storage (data, total, &storage));
g_assert_cmpuint (storage.dbid, ==, 3);
g_assert_cmpuint (storage.user_count, ==, 2);
g_assert_cmpstr (storage.name, ==, "StgWindsor");
g_assert_nonnull (storage.user_dbids);
g_assert_cmpuint (storage.user_dbids[0], ==, 10);
g_assert_cmpuint (storage.user_dbids[1], ==, 11);
g_assert_cmpuint (storage.user_val_sizes[0], ==, 100);
g_assert_cmpuint (storage.user_val_sizes[1], ==, 200);
validity_user_storage_clear (&storage);
}
/* ================================================================
* T6.19: test_parse_user
*
* Construct a user response with one finger and verify.
* ================================================================ */
static void
test_parse_user (void)
{
guint8 identity_bytes[] = { 0xDE, 0xAD, 0xBE, 0xEF };
/* Header: dbid=10, finger_count=1, unknown=0, identity_sz=4
* Finger: dbid=20, subtype=2, storage=3, value_size=500
* Identity: 4 bytes */
gsize total = 8 + 8 + sizeof (identity_bytes);
g_autofree guint8 *data = g_new0 (guint8, total);
FP_WRITE_UINT16_LE (&data[0], 10); /* dbid */
FP_WRITE_UINT16_LE (&data[2], 1); /* finger_count */
FP_WRITE_UINT16_LE (&data[4], 0); /* unknown */
FP_WRITE_UINT16_LE (&data[6], sizeof (identity_bytes)); /* identity_sz */
/* Finger entry */
FP_WRITE_UINT16_LE (&data[8], 20); /* finger.dbid */
FP_WRITE_UINT16_LE (&data[10], 2); /* finger.subtype = right index */
FP_WRITE_UINT16_LE (&data[12], 3); /* finger.storage */
FP_WRITE_UINT16_LE (&data[14], 500); /* finger.value_size */
memcpy (&data[16], identity_bytes, sizeof (identity_bytes));
ValidityUser user;
g_assert_true (validity_db_parse_user (data, total, &user));
g_assert_cmpuint (user.dbid, ==, 10);
g_assert_cmpuint (user.finger_count, ==, 1);
g_assert_nonnull (user.fingers);
g_assert_cmpuint (user.fingers[0].dbid, ==, 20);
g_assert_cmpuint (user.fingers[0].subtype, ==, 2);
g_assert_cmpuint (user.fingers[0].storage, ==, 3);
g_assert_cmpuint (user.fingers[0].value_size, ==, 500);
g_assert_nonnull (user.identity);
g_assert_cmpuint (user.identity_len, ==, sizeof (identity_bytes));
g_assert_cmpmem (user.identity, user.identity_len,
identity_bytes, sizeof (identity_bytes));
validity_user_clear (&user);
}
/* ================================================================
* T6.20: test_parse_new_record_id
*
* Verify parsing of new_record response (cmd 0x47).
* ================================================================ */
static void
test_parse_new_record_id (void)
{
guint16 record_id;
guint8 data[] = { 0x42, 0x00 };
g_assert_true (validity_db_parse_new_record_id (data, sizeof (data), &record_id));
g_assert_cmpuint (record_id, ==, 0x0042);
}
/* ================================================================
* T6.21: test_parse_new_record_id_too_short
*
* A 1-byte response should fail.
* ================================================================ */
static void
test_parse_new_record_id_too_short (void)
{
guint16 record_id;
guint8 data[] = { 0x42 };
g_assert_false (validity_db_parse_new_record_id (data, sizeof (data), &record_id));
}
/* ================================================================
* T6.22: test_build_identity
*
* Build a UUID identity and verify structure.
* ================================================================ */
static void
test_build_identity (void)
{
gsize len;
const gchar *uuid = "550e8400-e29b-41d4-a716-446655440000";
g_autofree guint8 *id = validity_db_build_identity (uuid, &len);
g_assert_nonnull (id);
/* Minimum size enforced */
g_assert_cmpuint (len, >=, VALIDITY_IDENTITY_MIN_SIZE);
/* type = SID (3) */
g_assert_cmpuint (FP_READ_UINT32_LE (&id[0]), ==, VALIDITY_IDENTITY_TYPE_SID);
/* len field = UUID string length */
gsize uuid_len = strlen (uuid);
g_assert_cmpuint (FP_READ_UINT32_LE (&id[4]), ==, uuid_len);
/* UUID payload */
g_assert_cmpmem (&id[8], uuid_len, uuid, uuid_len);
/* Remaining bytes should be zero-padded */
for (gsize i = 8 + uuid_len; i < len; i++)
g_assert_cmpuint (id[i], ==, 0);
}
/* ================================================================
* T6.23: test_build_finger_data
*
* Build finger data and verify the tagged format.
* ================================================================ */
static void
test_build_finger_data (void)
{
gsize len;
guint8 template[] = { 0x11, 0x22, 0x33 };
guint8 tid[] = { 0xAA, 0xBB };
g_autofree guint8 *fd = validity_db_build_finger_data (
2, template, sizeof (template), tid, sizeof (tid), &len);
g_assert_nonnull (fd);
/* Check header: subtype(2) | flags=3(2) | tinfo_len(2) | 0x20(2) */
g_assert_cmpuint (FP_READ_UINT16_LE (&fd[0]), ==, 2); /* subtype */
g_assert_cmpuint (FP_READ_UINT16_LE (&fd[2]), ==, 3); /* flags */
gsize expected_tinfo_len = 4 + sizeof (template) + 4 + sizeof (tid);
g_assert_cmpuint (FP_READ_UINT16_LE (&fd[4]), ==, expected_tinfo_len);
g_assert_cmpuint (FP_READ_UINT16_LE (&fd[6]), ==, 0x20);
/* Tag 1 (template) at offset 8 */
g_assert_cmpuint (FP_READ_UINT16_LE (&fd[8]), ==, 1);
g_assert_cmpuint (FP_READ_UINT16_LE (&fd[10]), ==, sizeof (template));
g_assert_cmpmem (&fd[12], sizeof (template), template, sizeof (template));
/* Tag 2 (tid) at offset 12+3 = 15 */
gsize tid_offset = 12 + sizeof (template);
g_assert_cmpuint (FP_READ_UINT16_LE (&fd[tid_offset]), ==, 2);
g_assert_cmpuint (FP_READ_UINT16_LE (&fd[tid_offset + 2]), ==, sizeof (tid));
g_assert_cmpmem (&fd[tid_offset + 4], sizeof (tid), tid, sizeof (tid));
/* Total should be header(8) + tinfo + 0x20 padding */
gsize expected_total = 8 + expected_tinfo_len + 0x20;
g_assert_cmpuint (len, ==, expected_total);
}
/* ================================================================
* T6.24: test_db_write_enable_blob
*
* Verify db_write_enable blob accessor returns a valid blob.
* ================================================================ */
static void
test_db_write_enable_blob (void)
{
gsize len;
/* Test with 009a device type (known to have a 3621-byte blob) */
const guint8 *blob = validity_db_get_write_enable_blob (VALIDITY_DEV_9A, &len);
g_assert_nonnull (blob);
g_assert_cmpuint (len, >, 0);
g_assert_cmpuint (len, ==, 3621);
/* Test all supported device types return valid blobs */
const guint dev_types[] = { VALIDITY_DEV_90, VALIDITY_DEV_97,
VALIDITY_DEV_9A, VALIDITY_DEV_9D };
for (guint i = 0; i < G_N_ELEMENTS (dev_types); i++)
{
gsize dbe_len;
const guint8 *dbe = validity_db_get_write_enable_blob (dev_types[i], &dbe_len);
g_assert_nonnull (dbe);
g_assert_cmpuint (dbe_len, >, 0);
}
}
/* ================================================================
* T6.25: test_parse_record_value
*
* Construct a record value response and verify parsing.
* ================================================================ */
static void
test_parse_record_value (void)
{
guint8 value[] = { 0x01, 0x02, 0x03 };
/* Format: dbid(2) type(2) storage(2) sz(2) pad(2) value */
gsize total = 10 + sizeof (value);
g_autofree guint8 *data = g_new0 (guint8, total);
FP_WRITE_UINT16_LE (&data[0], 42); /* dbid */
FP_WRITE_UINT16_LE (&data[2], 8); /* type = DATA */
FP_WRITE_UINT16_LE (&data[4], 3); /* storage */
FP_WRITE_UINT16_LE (&data[6], sizeof (value)); /* sz */
FP_WRITE_UINT16_LE (&data[8], 0); /* pad */
memcpy (&data[10], value, sizeof (value));
ValidityDbRecord record;
g_assert_true (validity_db_parse_record_value (data, total, &record));
g_assert_cmpuint (record.dbid, ==, 42);
g_assert_cmpuint (record.type, ==, 8);
g_assert_cmpuint (record.storage, ==, 3);
g_assert_nonnull (record.value);
g_assert_cmpuint (record.value_len, ==, sizeof (value));
g_assert_cmpmem (record.value, record.value_len, value, sizeof (value));
validity_db_record_clear (&record);
}
/* ================================================================
* T6.26: test_parse_record_children
*
* Construct a record children response and verify parsing.
* ================================================================ */
static void
test_parse_record_children (void)
{
/* Format: dbid(2) type(2) storage(2) sz(2) cnt(2) pad(2)
* children[cnt * 4: dbid(2) type(2)] */
gsize total = 12 + 2 * 4;
g_autofree guint8 *data = g_new0 (guint8, total);
FP_WRITE_UINT16_LE (&data[0], 3); /* dbid */
FP_WRITE_UINT16_LE (&data[2], 4); /* type = STORAGE */
FP_WRITE_UINT16_LE (&data[4], 3); /* storage */
FP_WRITE_UINT16_LE (&data[6], 0); /* sz */
FP_WRITE_UINT16_LE (&data[8], 2); /* child_count */
FP_WRITE_UINT16_LE (&data[10], 0); /* pad */
/* Children */
FP_WRITE_UINT16_LE (&data[12], 10); /* child[0].dbid */
FP_WRITE_UINT16_LE (&data[14], 5); /* child[0].type = USER */
FP_WRITE_UINT16_LE (&data[16], 11); /* child[1].dbid */
FP_WRITE_UINT16_LE (&data[18], 5); /* child[1].type = USER */
ValidityRecordChildren children;
g_assert_true (validity_db_parse_record_children (data, total, &children));
g_assert_cmpuint (children.dbid, ==, 3);
g_assert_cmpuint (children.type, ==, 4);
g_assert_cmpuint (children.storage, ==, 3);
g_assert_cmpuint (children.child_count, ==, 2);
g_assert_nonnull (children.children);
g_assert_cmpuint (children.children[0].dbid, ==, 10);
g_assert_cmpuint (children.children[0].type, ==, 5);
g_assert_cmpuint (children.children[1].dbid, ==, 11);
g_assert_cmpuint (children.children[1].type, ==, 5);
validity_record_children_clear (&children);
}
/* ================================================================
* T6.27: test_cmd_enrollment_update
*
* Verify cmd 0x6B format with template data.
* ================================================================ */
static void
test_cmd_enrollment_update (void)
{
gsize len;
guint8 prev[] = { 0xDE, 0xAD, 0xBE, 0xEF };
g_autofree guint8 *cmd = validity_db_build_cmd_enrollment_update (
prev, sizeof (prev), &len);
g_assert_nonnull (cmd);
g_assert_cmpuint (len, ==, 1 + sizeof (prev));
g_assert_cmpuint (cmd[0], ==, VCSFW_CMD_ENROLLMENT_UPDATE);
g_assert_cmpmem (&cmd[1], sizeof (prev), prev, sizeof (prev));
}
/* ================================================================
* T6.28: test_cmd_get_record_value
*
* Verify cmd 0x49 format.
* ================================================================ */
static void
test_cmd_get_record_value (void)
{
gsize len;
g_autofree guint8 *cmd = validity_db_build_cmd_get_record_value (0x5678, &len);
g_assert_nonnull (cmd);
g_assert_cmpuint (len, ==, 3);
g_assert_cmpuint (cmd[0], ==, VCSFW_CMD_GET_RECORD_VALUE);
g_assert_cmpuint (FP_READ_UINT16_LE (&cmd[1]), ==, 0x5678);
}
/* ================================================================
* T6.29: test_cmd_get_record_children
*
* Verify cmd 0x46 format.
* ================================================================ */
static void
test_cmd_get_record_children (void)
{
gsize len;
g_autofree guint8 *cmd = validity_db_build_cmd_get_record_children (0x1234, &len);
g_assert_nonnull (cmd);
g_assert_cmpuint (len, ==, 3);
g_assert_cmpuint (cmd[0], ==, VCSFW_CMD_GET_RECORD_CHILDREN);
g_assert_cmpuint (FP_READ_UINT16_LE (&cmd[1]), ==, 0x1234);
}
int
main (int argc, char *argv[])
{
g_test_init (&argc, &argv, NULL);
/* Command builder tests */
g_test_add_func ("/validity/db/cmd_db_info", test_cmd_db_info);
g_test_add_func ("/validity/db/cmd_get_user_storage", test_cmd_get_user_storage);
g_test_add_func ("/validity/db/cmd_get_user_storage_null_name", test_cmd_get_user_storage_null_name);
g_test_add_func ("/validity/db/cmd_get_user", test_cmd_get_user);
g_test_add_func ("/validity/db/cmd_lookup_user", test_cmd_lookup_user);
g_test_add_func ("/validity/db/cmd_new_record", test_cmd_new_record);
g_test_add_func ("/validity/db/cmd_del_record", test_cmd_del_record);
g_test_add_func ("/validity/db/cmd_create_enrollment", test_cmd_create_enrollment);
g_test_add_func ("/validity/db/cmd_enrollment_update_start", test_cmd_enrollment_update_start);
g_test_add_func ("/validity/db/cmd_enrollment_update", test_cmd_enrollment_update);
g_test_add_func ("/validity/db/cmd_match_finger", test_cmd_match_finger);
g_test_add_func ("/validity/db/cmd_get_match_result", test_cmd_get_match_result);
g_test_add_func ("/validity/db/cmd_match_cleanup", test_cmd_match_cleanup);
g_test_add_func ("/validity/db/cmd_get_prg_status", test_cmd_get_prg_status);
g_test_add_func ("/validity/db/cmd_capture_stop", test_cmd_capture_stop);
g_test_add_func ("/validity/db/cmd_call_cleanups", test_cmd_call_cleanups);
g_test_add_func ("/validity/db/cmd_get_record_value", test_cmd_get_record_value);
g_test_add_func ("/validity/db/cmd_get_record_children", test_cmd_get_record_children);
/* Response parser tests */
g_test_add_func ("/validity/db/parse_info", test_parse_db_info);
g_test_add_func ("/validity/db/parse_info_too_short", test_parse_db_info_too_short);
g_test_add_func ("/validity/db/parse_user_storage", test_parse_user_storage);
g_test_add_func ("/validity/db/parse_user", test_parse_user);
g_test_add_func ("/validity/db/parse_new_record_id", test_parse_new_record_id);
g_test_add_func ("/validity/db/parse_new_record_id_too_short", test_parse_new_record_id_too_short);
g_test_add_func ("/validity/db/parse_record_value", test_parse_record_value);
g_test_add_func ("/validity/db/parse_record_children", test_parse_record_children);
/* Identity and finger data tests */
g_test_add_func ("/validity/db/build_identity", test_build_identity);
g_test_add_func ("/validity/db/build_finger_data", test_build_finger_data);
/* Blob accessor test */
g_test_add_func ("/validity/db/write_enable_blob", test_db_write_enable_blob);
return g_test_run ();
}