/* * strmap_test.c * * Unit tests for strmap implementation */ #include "hashfuncs.h" #include "strmap.h" #include #include #include START_TEST(test_create_destroy) { strmap *map = strmap_create(hash_key); ck_assert_ptr_nonnull(map); ck_assert_uint_eq(strmap_size(map), 0); strmap_destroy(map); } END_TEST START_TEST(test_put_get_basic) { strmap *map = strmap_create(hash_key); const char *value; ck_assert_int_eq(strmap_put(map, "key1", "value1"), STRMAP_OK); ck_assert_uint_eq(strmap_size(map), 1); ck_assert_int_eq(strmap_get(map, "key1", &value), STRMAP_OK); ck_assert_str_eq(value, "value1"); strmap_destroy(map); } END_TEST START_TEST(test_put_update) { strmap *map = strmap_create(hash_key); const char *value; ck_assert_int_eq(strmap_put(map, "key1", "value1"), STRMAP_OK); ck_assert_int_eq(strmap_put(map, "key1", "value2"), STRMAP_OK); ck_assert_uint_eq(strmap_size(map), 1); ck_assert_int_eq(strmap_get(map, "key1", &value), STRMAP_OK); ck_assert_str_eq(value, "value2"); strmap_destroy(map); } END_TEST START_TEST(test_get_nonexistent) { strmap *map = strmap_create(hash_key); const char *value; ck_assert_int_eq(strmap_get(map, "nonexistent", &value), STRMAP_NOTFOUND); strmap_destroy(map); } END_TEST START_TEST(test_delete_basic) { strmap *map = strmap_create(hash_key); const char *value; ck_assert_int_eq(strmap_put(map, "key1", "value1"), STRMAP_OK); ck_assert_int_eq(strmap_delete(map, "key1"), STRMAP_OK); ck_assert_uint_eq(strmap_size(map), 0); ck_assert_int_eq(strmap_get(map, "key1", &value), STRMAP_NOTFOUND); strmap_destroy(map); } END_TEST START_TEST(test_delete_nonexistent) { strmap *map = strmap_create(hash_key); ck_assert_int_eq(strmap_delete(map, "nonexistent"), STRMAP_NOTFOUND); strmap_destroy(map); } END_TEST START_TEST(test_delete_multiple) { strmap *map = strmap_create(hash_key); const char *value; // Add multiple items ck_assert_int_eq(strmap_put(map, "key1", "value1"), STRMAP_OK); ck_assert_int_eq(strmap_put(map, "key2", "value2"), STRMAP_OK); ck_assert_int_eq(strmap_put(map, "key3", "value3"), STRMAP_OK); ck_assert_uint_eq(strmap_size(map), 3); // Delete middle item ck_assert_int_eq(strmap_delete(map, "key2"), STRMAP_OK); ck_assert_uint_eq(strmap_size(map), 2); ck_assert_int_eq(strmap_get(map, "key2", &value), STRMAP_NOTFOUND); // Verify remaining items ck_assert_int_eq(strmap_get(map, "key1", &value), STRMAP_OK); ck_assert_str_eq(value, "value1"); ck_assert_int_eq(strmap_get(map, "key3", &value), STRMAP_OK); ck_assert_str_eq(value, "value3"); strmap_destroy(map); } END_TEST START_TEST(test_delete_head) { strmap *map = strmap_create(hash_key); const char *value; // Add items that will likely hash to same bucket ck_assert_int_eq(strmap_put(map, "a", "first"), STRMAP_OK); ck_assert_int_eq(strmap_put(map, "b", "second"), STRMAP_OK); ck_assert_int_eq(strmap_put(map, "c", "third"), STRMAP_OK); // Delete head item ck_assert_int_eq(strmap_delete(map, "c"), STRMAP_OK); ck_assert_uint_eq(strmap_size(map), 2); ck_assert_int_eq(strmap_get(map, "c", &value), STRMAP_NOTFOUND); // Verify remaining items ck_assert_int_eq(strmap_get(map, "a", &value), STRMAP_OK); ck_assert_str_eq(value, "first"); ck_assert_int_eq(strmap_get(map, "b", &value), STRMAP_OK); ck_assert_str_eq(value, "second"); strmap_destroy(map); } END_TEST START_TEST(test_collision_handling) { strmap *map = strmap_create(test_hash); const char *value; /* all keys with the same initial letter should map to the same bucket */ ck_assert_int_eq(strmap_put(map, "key1", "value1"), STRMAP_OK); ck_assert_int_eq(strmap_put(map, "key2", "value2"), STRMAP_OK); ck_assert_int_eq(strmap_put(map, "key3", "value3"), STRMAP_OK); ck_assert_uint_eq(strmap_size(map), 3); // Retrieve all values ck_assert_int_eq(strmap_get(map, "key1", &value), STRMAP_OK); ck_assert_str_eq(value, "value1"); ck_assert_int_eq(strmap_get(map, "key2", &value), STRMAP_OK); ck_assert_str_eq(value, "value2"); ck_assert_int_eq(strmap_get(map, "key3", &value), STRMAP_OK); ck_assert_str_eq(value, "value3"); strmap_destroy(map); } END_TEST START_TEST(test_empty_key_value) { strmap *map = strmap_create(hash_key); const char *value; // Test empty string key ck_assert_int_eq(strmap_put(map, "", "empty_key_value"), STRMAP_OK); ck_assert_int_eq(strmap_get(map, "", &value), STRMAP_OK); ck_assert_str_eq(value, "empty_key_value"); // Test empty string value ck_assert_int_eq(strmap_put(map, "empty_value_key", ""), STRMAP_OK); ck_assert_int_eq(strmap_get(map, "empty_value_key", &value), STRMAP_OK); ck_assert_str_eq(value, ""); strmap_destroy(map); } END_TEST START_TEST(test_put_null_key) { strmap *map = strmap_create(hash_key); // This should ideally be handled gracefully // Behavior depends on your strdup implementation with NULL // For now, we'll assume it fails gracefully ck_assert_int_eq(strmap_put(map, NULL, "value"), STRMAP_ERR); strmap_destroy(map); } END_TEST Suite *strmap_suite(void) { Suite *s; TCase *tc_core; TCase *tc_edge; s = suite_create("Strmap"); /* Core test case */ tc_core = tcase_create("Core"); tcase_add_test(tc_core, test_create_destroy); tcase_add_test(tc_core, test_put_get_basic); tcase_add_test(tc_core, test_put_update); tcase_add_test(tc_core, test_get_nonexistent); tcase_add_test(tc_core, test_delete_basic); tcase_add_test(tc_core, test_delete_nonexistent); tcase_add_test(tc_core, test_delete_multiple); tcase_add_test(tc_core, test_delete_head); tcase_add_test(tc_core, test_collision_handling); /* Edge cases */ tc_edge = tcase_create("Edge"); tcase_add_test(tc_edge, test_empty_key_value); tcase_add_test(tc_edge, test_put_null_key); suite_add_tcase(s, tc_core); suite_add_tcase(s, tc_edge); return s; } int main(void) { int number_failed; Suite *s; SRunner *sr; s = strmap_suite(); sr = srunner_create(s); srunner_run_all(sr, CK_NORMAL); number_failed = srunner_ntests_failed(sr); srunner_free(sr); return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; }