diff -r 71e7e9ba4b97 -r d2d42cb1d59e tests/test_properties.c --- a/tests/test_properties.c Sun Oct 13 15:19:12 2024 +0200 +++ b/tests/test_properties.c Sun Oct 13 16:44:29 2024 +0200 @@ -27,8 +27,10 @@ */ #include "cx/test.h" +#include "util_allocator.h" #include "cx/properties.h" +#include "cx/hash_map.h" CX_TEST(test_cx_properties_init) { CxProperties prop; @@ -89,7 +91,7 @@ CxProperties prop; cxPropertiesInitDefault(&prop); - enum cx_properties_status result; + CxPropertiesStatus result; cxstring key; cxstring value; CX_TEST_DO { @@ -155,7 +157,7 @@ CxProperties prop; cxPropertiesInitDefault(&prop); - enum cx_properties_status result; + CxPropertiesStatus result; cxstring key; cxstring value; @@ -178,7 +180,7 @@ CX_TEST(test_cx_properties_next_part) { CxProperties prop; cxPropertiesInitDefault(&prop); - enum cx_properties_status result; + CxPropertiesStatus result; cxstring key; cxstring value; const char *str; @@ -287,7 +289,7 @@ CX_TEST(test_ucx_properties_next_long_lines) { CxProperties prop; cxPropertiesInitDefault(&prop); - enum cx_properties_status result; + CxPropertiesStatus result; cxstring key; cxstring value; @@ -367,6 +369,139 @@ free(long_value); } +CX_TEST(test_cx_properties_load_string_to_map) { + CxTestingAllocator talloc; + cx_testing_allocator_init(&talloc); + CxAllocator *alloc = &talloc.base; + CX_TEST_DO { + const char *str = "key1 = value1\nkey2 = value2\n\n#comment\n\nkey3 = value3\n"; + + CxMap *map = cxHashMapCreateSimple(CX_STORE_POINTERS); + cxDefineAdvancedDestructor(map, cxFree, alloc); + CxProperties prop; + cxPropertiesInitDefault(&prop); + CxPropertiesSink sink = cxPropertiesMapSink(map); + sink.data = alloc; // use the testing allocator + CxPropertiesSource src = cxPropertiesCstrSource(str); + CxPropertiesStatus status = cxPropertiesLoad(&prop, sink, src); + + CX_TEST_ASSERT(status == CX_PROPERTIES_NO_ERROR); + CX_TEST_ASSERT(cxMapSize(map) == 3); + + char *v1 = cxMapGet(map, "key1"); + char *v2 = cxMapGet(map, "key2"); + char *v3 = cxMapGet(map, "key3"); + + CX_TEST_ASSERTM(v1, "value for key1 not found"); + CX_TEST_ASSERTM(v2, "value for key2 not found"); + CX_TEST_ASSERTM(v3, "value for key3 not found"); + + CX_TEST_ASSERT(!strcmp(v1, "value1")); + CX_TEST_ASSERT(!strcmp(v2, "value2")); + CX_TEST_ASSERT(!strcmp(v3, "value3")); + + // second test + cxMapClear(map); + + str = "\n#comment\n"; + src = cxPropertiesCstrnSource(str, strlen(str)); + status = cxPropertiesLoad(&prop, sink, src); + + CX_TEST_ASSERT(status == CX_PROPERTIES_NO_DATA); + CX_TEST_ASSERT(cxMapSize(map) == 0); + + str = "key1 = value1\nsyntax error line\n"; + src = cxPropertiesStringSource(cx_str(str)); + status = cxPropertiesLoad(&prop, sink, src); + + CX_TEST_ASSERT(status == CX_PROPERTIES_INVALID_MISSING_DELIMITER); + + // the successfully read k/v-pair is in the map, nevertheless + CX_TEST_ASSERT(cxMapSize(map) == 1); + char *v = cxMapGet(map, "key1"); + CX_TEST_ASSERT(!strcmp(v, "value1")); + + cxMapDestroy(map); + cxPropertiesDestroy(&prop); + + CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc)); + } + cx_testing_allocator_destroy(&talloc); +} + +CX_TEST(test_cx_properties_load_file_to_map) { + CxTestingAllocator talloc; + cx_testing_allocator_init(&talloc); + CxAllocator *alloc = &talloc.base; + CX_TEST_DO { + FILE *f = tmpfile(); + CX_TEST_ASSERTM(f, "test file cannot be opened, test aborted"); + fprintf(f, "# properties file\n\nkey1 = value1\nkey2 = value2\n"); + fprintf(f, "\n\nkey3 = value3\n\n"); + + size_t key_len = 512; + char *long_key = (char *) malloc(key_len); + memset(long_key, 'k', 512); + + size_t value_len = 2048; + char *long_value = (char *) malloc(value_len); + memset(long_value, 'v', 2048); + + fwrite(long_key, 1, key_len, f); + fprintf(f, " = "); + fwrite(long_value, 1, value_len, f); + fprintf(f, " \n"); + + fprintf(f, "\n\n\n\nlast_key = property value\n"); + + fflush(f); + fseek(f, 0, SEEK_SET); + + // preparation of test file complete + + CxMap *map = cxHashMapCreateSimple(CX_STORE_POINTERS); + cxDefineAdvancedDestructor(map, cxFree, alloc); + CxProperties prop; + cxPropertiesInitDefault(&prop); + CxPropertiesSink sink = cxPropertiesMapSink(map); + sink.data = alloc; // use the testing allocator + CxPropertiesSource src = cxPropertiesFileSource(f, 512); + CxPropertiesStatus status = cxPropertiesLoad(&prop, sink, src); + fclose(f); + + CX_TEST_ASSERT(status == CX_PROPERTIES_NO_ERROR); + CX_TEST_ASSERT(cxMapSize(map) == 5); + + char *v1 = cxMapGet(map, "key1"); + char *v2 = cxMapGet(map, cx_str("key2")); + char *v3 = cxMapGet(map, "key3"); + char *lv = cxMapGet(map, cx_strn(long_key, key_len)); + char *lk = cxMapGet(map, "last_key"); + + CX_TEST_ASSERTM(v1, "value for key1 not found"); + CX_TEST_ASSERTM(v2, "value for key2 not found"); + CX_TEST_ASSERTM(v3, "value for key3 not found"); + CX_TEST_ASSERTM(lv, "value for long key not found"); + CX_TEST_ASSERTM(lk, "value for last_key not found"); + + CX_TEST_ASSERT(!strcmp(v1, "value1")); + CX_TEST_ASSERT(!strcmp(v2, "value2")); + CX_TEST_ASSERT(!strcmp(v3, "value3")); + cxstring expected = cx_strn(long_value, value_len); + cxstring actual = cx_str(lv); + CX_TEST_ASSERT(!cx_strcmp(expected, actual)); + CX_TEST_ASSERT(!strcmp(lk, "property value")); + + free(long_key); + free(long_value); + cxMapDestroy(map); + cxPropertiesDestroy(&prop); + + CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc)); + } + cx_testing_allocator_destroy(&talloc); +} + CxTestSuite *cx_test_suite_properties(void) { CxTestSuite *suite = cx_test_suite_new("properties"); @@ -375,6 +510,8 @@ cx_test_register(suite, test_cx_properties_next_multi); cx_test_register(suite, test_cx_properties_next_part); cx_test_register(suite, test_ucx_properties_next_long_lines); + cx_test_register(suite, test_cx_properties_load_string_to_map); + cx_test_register(suite, test_cx_properties_load_file_to_map); return suite; }