|
6 | 6 | */ |
7 | 7 | #include "test_framework.h" |
8 | 8 | #include <store/store.h> |
| 9 | +#include <sqlite3.h> |
9 | 10 | #include <string.h> |
10 | 11 | #include <stdlib.h> |
11 | 12 | #include <stdio.h> |
@@ -895,10 +896,75 @@ TEST(store_find_node_ids_by_qns) { |
895 | 896 | PASS(); |
896 | 897 | } |
897 | 898 |
|
| 899 | +/* ── Integrity check tests ──────────────────────────────────────── */ |
| 900 | + |
| 901 | +TEST(store_integrity_clean) { |
| 902 | + /* A fresh store with correct data should pass integrity check */ |
| 903 | + cbm_store_t *s = cbm_store_open_memory(); |
| 904 | + ASSERT_NOT_NULL(s); |
| 905 | + cbm_store_upsert_project(s, "test-proj", "/tmp/test"); |
| 906 | + ASSERT_TRUE(cbm_store_check_integrity(s)); |
| 907 | + cbm_store_close(s); |
| 908 | + PASS(); |
| 909 | +} |
| 910 | + |
| 911 | +TEST(store_integrity_empty) { |
| 912 | + /* An empty store (no project rows) should pass — 0 rows is fine */ |
| 913 | + cbm_store_t *s = cbm_store_open_memory(); |
| 914 | + ASSERT_NOT_NULL(s); |
| 915 | + ASSERT_TRUE(cbm_store_check_integrity(s)); |
| 916 | + cbm_store_close(s); |
| 917 | + PASS(); |
| 918 | +} |
| 919 | + |
| 920 | +TEST(store_integrity_corrupt_bad_path) { |
| 921 | + /* Simulate corruption: root_path is a numeric string (not a real path). |
| 922 | + * This matches the real corruption where node IDs ended up in root_path. */ |
| 923 | + cbm_store_t *s = cbm_store_open_memory(); |
| 924 | + ASSERT_NOT_NULL(s); |
| 925 | + sqlite3 *db = cbm_store_get_db(s); |
| 926 | + sqlite3_exec(db, |
| 927 | + "INSERT INTO projects (name, indexed_at, root_path) " |
| 928 | + "VALUES ('some-project', '2024-01-01', '826');", |
| 929 | + NULL, NULL, NULL); |
| 930 | + ASSERT_FALSE(cbm_store_check_integrity(s)); |
| 931 | + cbm_store_close(s); |
| 932 | + PASS(); |
| 933 | +} |
| 934 | + |
| 935 | +TEST(store_integrity_corrupt_too_many_rows) { |
| 936 | + /* Simulate corruption: >5 rows in projects table */ |
| 937 | + cbm_store_t *s = cbm_store_open_memory(); |
| 938 | + ASSERT_NOT_NULL(s); |
| 939 | + sqlite3 *db = cbm_store_get_db(s); |
| 940 | + for (int i = 0; i < 10; i++) { |
| 941 | + char sql[256]; |
| 942 | + snprintf(sql, sizeof(sql), |
| 943 | + "INSERT INTO projects (name, indexed_at, root_path) " |
| 944 | + "VALUES ('proj-%d', '2024-01-01', '/tmp/%d');", |
| 945 | + i, i); |
| 946 | + sqlite3_exec(db, sql, NULL, NULL, NULL); |
| 947 | + } |
| 948 | + ASSERT_FALSE(cbm_store_check_integrity(s)); |
| 949 | + cbm_store_close(s); |
| 950 | + PASS(); |
| 951 | +} |
| 952 | + |
| 953 | +TEST(store_integrity_null_check) { |
| 954 | + /* NULL store should return false (not crash) */ |
| 955 | + ASSERT_FALSE(cbm_store_check_integrity(NULL)); |
| 956 | + PASS(); |
| 957 | +} |
| 958 | + |
898 | 959 | SUITE(store_nodes) { |
899 | 960 | RUN_TEST(store_open_memory); |
900 | 961 | RUN_TEST(store_close_null); |
901 | 962 | RUN_TEST(store_open_memory_twice); |
| 963 | + RUN_TEST(store_integrity_clean); |
| 964 | + RUN_TEST(store_integrity_empty); |
| 965 | + RUN_TEST(store_integrity_corrupt_bad_path); |
| 966 | + RUN_TEST(store_integrity_corrupt_too_many_rows); |
| 967 | + RUN_TEST(store_integrity_null_check); |
902 | 968 | RUN_TEST(store_project_crud); |
903 | 969 | RUN_TEST(store_project_update); |
904 | 970 | RUN_TEST(store_project_delete); |
|
0 commit comments