/* * Test suite for kvmgr_capture_keys() — P0-14a. * * Tests follow TDD: written BEFORE implementation. * All tests exercise the public API declared in kvmgr.h. */ #include #include #include #include #include #include "kv.h" #include "kvmgr.h" #include "persist.h" #include "utils.h" /* ------------------------------------------------------------------ */ /* helpers */ /* ------------------------------------------------------------------ */ static int find_key_in_captured(slot_key_t* keys, size_t n, const char* target_key, int* index_out) { size_t i; for (i = 0; i < n; i++) { if (strcmp(keys[i].key, target_key) == 0) { if (index_out != NULL) { *index_out = keys[i].index; } return 1; } } return 0; } /* ------------------------------------------------------------------ */ /* test 1: capture from a string-keyed kvmgr with 3 entries */ /* ------------------------------------------------------------------ */ static void test_capture_keys_string_kvmgr(void) { kvmgr_params_t params = { .key_type = KVMGR_KEY_STRING, .nslots = 8, .delta = 4, .datakiller = NULL }; var kvmgr = makeInstance(&xkvmgr_type, ¶ms); TEST_ASSERT_NOT_NULL(kvmgr); /* Add 3 string-keyed entries whose values are arbitrary pointers; the index returned by key_add is the slot index we capture. */ int idx_a = key_add(kvmgr, (void*)"alpha", (void*)"data_alpha"); int idx_b = key_add(kvmgr, (void*)"beta", (void*)"data_beta"); int idx_c = key_add(kvmgr, (void*)"gamma", (void*)"data_gamma"); TEST_ASSERT_TRUE(idx_a >= 0); TEST_ASSERT_TRUE(idx_b >= 0); TEST_ASSERT_TRUE(idx_c >= 0); slot_key_t* keys = NULL; size_t n_keys = 0; int rc = kvmgr_capture_keys(kvmgr, &keys, &n_keys); TEST_ASSERT_EQUAL_INT(0, rc); TEST_ASSERT_EQUAL_size_t(3, n_keys); TEST_ASSERT_NOT_NULL(keys); /* Every inserted key must appear exactly once with the correct index */ int found_idx = -1; TEST_ASSERT_TRUE(find_key_in_captured(keys, n_keys, "alpha", &found_idx)); TEST_ASSERT_EQUAL_INT(idx_a, found_idx); TEST_ASSERT_TRUE(find_key_in_captured(keys, n_keys, "beta", &found_idx)); TEST_ASSERT_EQUAL_INT(idx_b, found_idx); TEST_ASSERT_TRUE(find_key_in_captured(keys, n_keys, "gamma", &found_idx)); TEST_ASSERT_EQUAL_INT(idx_c, found_idx); /* key_len must equal strlen(key)+1 */ size_t i; for (i = 0; i < n_keys; i++) { TEST_ASSERT_EQUAL_size_t(strlen(keys[i].key) + 1, keys[i].key_len); } free(keys); destroy(kvmgr); } /* ------------------------------------------------------------------ */ /* test 2: empty kvmgr returns 0 entries and NULL keys_out */ /* ------------------------------------------------------------------ */ static void test_capture_keys_empty_kvmgr(void) { kvmgr_params_t params = { .key_type = KVMGR_KEY_STRING, .nslots = 4, .delta = 4, .datakiller = NULL }; var kvmgr = makeInstance(&xkvmgr_type, ¶ms); TEST_ASSERT_NOT_NULL(kvmgr); slot_key_t* keys = (slot_key_t*)(uintptr_t)0xdeadbeef; /* sentinel */ size_t n_keys = 99; int rc = kvmgr_capture_keys(kvmgr, &keys, &n_keys); TEST_ASSERT_EQUAL_INT(0, rc); TEST_ASSERT_EQUAL_size_t(0, n_keys); TEST_ASSERT_NULL(keys); destroy(kvmgr); } /* ------------------------------------------------------------------ */ /* test 3: captured keys are deep copies — safe after kvmgr destroyed */ /* ------------------------------------------------------------------ */ static void test_capture_keys_are_deep_copies(void) { kvmgr_params_t params = { .key_type = KVMGR_KEY_STRING, .nslots = 4, .delta = 4, .datakiller = NULL }; var kvmgr = makeInstance(&xkvmgr_type, ¶ms); TEST_ASSERT_NOT_NULL(kvmgr); key_add(kvmgr, (void*)"keyA", (void*)"valA"); key_add(kvmgr, (void*)"keyB", (void*)"valB"); slot_key_t* keys = NULL; size_t n_keys = 0; int rc = kvmgr_capture_keys(kvmgr, &keys, &n_keys); TEST_ASSERT_EQUAL_INT(0, rc); TEST_ASSERT_EQUAL_size_t(2, n_keys); /* Stash manual copies of the captured key strings */ char copy_a[256], copy_b[256]; int found_a = 0, found_b = 0; size_t i; for (i = 0; i < n_keys; i++) { if (strcmp(keys[i].key, "keyA") == 0) { strncpy(copy_a, keys[i].key, sizeof(copy_a) - 1); copy_a[sizeof(copy_a) - 1] = '\0'; found_a = 1; } else if (strcmp(keys[i].key, "keyB") == 0) { strncpy(copy_b, keys[i].key, sizeof(copy_b) - 1); copy_b[sizeof(copy_b) - 1] = '\0'; found_b = 1; } } TEST_ASSERT_TRUE(found_a); TEST_ASSERT_TRUE(found_b); /* Destroy the kvmgr — this frees all kvtab entries including the original key strings. Captured keys[] must remain valid. */ destroy(kvmgr); TEST_ASSERT_EQUAL_STRING("keyA", copy_a); TEST_ASSERT_EQUAL_STRING("keyB", copy_b); /* Directly verify the captured keys array is still readable */ int still_a = 0, still_b = 0; for (i = 0; i < n_keys; i++) { if (strcmp(keys[i].key, "keyA") == 0) still_a = 1; if (strcmp(keys[i].key, "keyB") == 0) still_b = 1; } TEST_ASSERT_TRUE(still_a); TEST_ASSERT_TRUE(still_b); free(keys); } /* ------------------------------------------------------------------ */ /* test 4: capture from an integer-keyed kvmgr with 3 entries */ /* ------------------------------------------------------------------ */ static void test_capture_keys_int_kvmgr(void) { kvmgr_params_t params = { .key_type = KVMGR_KEY_INT, .nslots = 8, .delta = 4, .datakiller = NULL }; var kvmgr = makeInstance(&xkvmgr_type, ¶ms); TEST_ASSERT_NOT_NULL(kvmgr); /* Add 3 integer-keyed entries; the integer keys are jobids. For integer-keyed kvmgrs, key_add expects a (void*)(long)intval. */ int64_t jobid_1001 = 1001; int64_t jobid_1002 = 1002; int64_t jobid_1003 = 1003; int idx_1001 = key_add(kvmgr, (void*)(long)jobid_1001, (void*)"data_1001"); int idx_1002 = key_add(kvmgr, (void*)(long)jobid_1002, (void*)"data_1002"); int idx_1003 = key_add(kvmgr, (void*)(long)jobid_1003, (void*)"data_1003"); TEST_ASSERT_TRUE(idx_1001 >= 0); TEST_ASSERT_TRUE(idx_1002 >= 0); TEST_ASSERT_TRUE(idx_1003 >= 0); slot_key_t* keys = NULL; size_t n_keys = 0; int rc = kvmgr_capture_keys(kvmgr, &keys, &n_keys); TEST_ASSERT_EQUAL_INT(0, rc); TEST_ASSERT_EQUAL_size_t(3, n_keys); TEST_ASSERT_NOT_NULL(keys); /* Every inserted integer key must appear as a decimal string with the correct index */ int found_idx = -1; TEST_ASSERT_TRUE(find_key_in_captured(keys, n_keys, "1001", &found_idx)); TEST_ASSERT_EQUAL_INT(idx_1001, found_idx); TEST_ASSERT_TRUE(find_key_in_captured(keys, n_keys, "1002", &found_idx)); TEST_ASSERT_EQUAL_INT(idx_1002, found_idx); TEST_ASSERT_TRUE(find_key_in_captured(keys, n_keys, "1003", &found_idx)); TEST_ASSERT_EQUAL_INT(idx_1003, found_idx); /* key_len must equal strlen(key)+1 */ size_t i; for (i = 0; i < n_keys; i++) { TEST_ASSERT_EQUAL_size_t(strlen(keys[i].key) + 1, keys[i].key_len); } free(keys); destroy(kvmgr); } /* ------------------------------------------------------------------ */ /* entry point called from test.c */ /* ------------------------------------------------------------------ */ void test_kvmgr_capture(void) { printf("\n>> kvmgr_capture_keys test\n"); RUN_TEST(test_capture_keys_string_kvmgr); RUN_TEST(test_capture_keys_empty_kvmgr); RUN_TEST(test_capture_keys_are_deep_copies); RUN_TEST(test_capture_keys_int_kvmgr); }