--- a/tests/test_properties.c Tue Dec 09 19:05:35 2025 +0100 +++ b/tests/test_properties.c Wed Dec 10 13:12:27 2025 +0100 @@ -41,6 +41,7 @@ CX_TEST_ASSERT(prop.config.comment1 == '#'); CX_TEST_ASSERT(prop.config.comment2 == 0); CX_TEST_ASSERT(prop.config.comment3 == 0); + CX_TEST_ASSERT(prop.config.continuation == '\\'); CX_TEST_ASSERT(prop.input.space == NULL); CX_TEST_ASSERT(prop.buffer.space == NULL); @@ -383,6 +384,108 @@ free(long_value); } +CX_TEST(test_properties_next_line_continuation) { + const char *str = + "key1 = multiline \\\nvalue\n" + "key2 = normal\n" + "key3 = multiline \\\n trim \n" + "key4 = m1\\\nm2\\\n m3\\\nm4 \n" + "key5 = no\\continuation\n"; + + CxProperties prop; + cxPropertiesInitDefault(&prop); + + cxstring key; + cxstring value; + + CX_TEST_DO { + CX_TEST_ASSERT(0 == cxPropertiesFill(&prop, str)); + + CX_TEST_ASSERT(cxPropertiesNext(&prop, &key, &value) == CX_PROPERTIES_NO_ERROR); + CX_TEST_ASSERT(!cx_strcmp(key, "key1")); + CX_TEST_ASSERT(!cx_strcmp(value, "multiline value")); + + CX_TEST_ASSERT(cxPropertiesNext(&prop, &key, &value) == CX_PROPERTIES_NO_ERROR); + CX_TEST_ASSERT(!cx_strcmp(key, "key2")); + CX_TEST_ASSERT(!cx_strcmp(value, "normal")); + + CX_TEST_ASSERT(cxPropertiesNext(&prop, &key, &value) == CX_PROPERTIES_NO_ERROR); + CX_TEST_ASSERT(!cx_strcmp(key, "key3")); + CX_TEST_ASSERT(!cx_strcmp(value, "multiline trim")); + + CX_TEST_ASSERT(cxPropertiesNext(&prop, &key, &value) == CX_PROPERTIES_NO_ERROR); + CX_TEST_ASSERT(!cx_strcmp(key, "key4")); + CX_TEST_ASSERT(!cx_strcmp(value, "m1m2m3m4")); + + CX_TEST_ASSERT(cxPropertiesNext(&prop, &key, &value) == CX_PROPERTIES_NO_ERROR); + CX_TEST_ASSERT(!cx_strcmp(key, "key5")); + CX_TEST_ASSERT(!cx_strcmp(value, "no\\continuation")); + } + + cxPropertiesDestroy(&prop); +} + +CX_TEST(test_properties_next_line_continuation_part) { + CxProperties prop; + cxPropertiesInitDefault(&prop); + + cxstring key; + cxstring value; + CxPropertiesStatus result; + const char *str; + + CX_TEST_DO { + // key1 = continue continue ...line + str = "key1 "; + CX_TEST_ASSERT(0 == cxPropertiesFill(&prop, str)); + result = cxPropertiesNext(&prop, &key, &value); + CX_TEST_ASSERT(result == CX_PROPERTIES_INCOMPLETE_DATA); + + str = "= continue \\"; + CX_TEST_ASSERT(0 == cxPropertiesFill(&prop, str)); + result = cxPropertiesNext(&prop, &key, &value); + CX_TEST_ASSERT(result == CX_PROPERTIES_INCOMPLETE_DATA); + + str = "\ncontinue \\\n"; + CX_TEST_ASSERT(0 == cxPropertiesFill(&prop, str)); + result = cxPropertiesNext(&prop, &key, &value); + CX_TEST_ASSERT(result == CX_PROPERTIES_INCOMPLETE_DATA); + + str = "..."; + CX_TEST_ASSERT(0 == cxPropertiesFill(&prop, str)); + result = cxPropertiesNext(&prop, &key, &value); + CX_TEST_ASSERT(result == CX_PROPERTIES_INCOMPLETE_DATA); + + str = "line\nkey2 = value2\n"; + CX_TEST_ASSERT(0 == cxPropertiesFill(&prop, str)); + result = cxPropertiesNext(&prop, &key, &value); + CX_TEST_ASSERT(result == CX_PROPERTIES_NO_ERROR); + CX_TEST_ASSERT(!cx_strcmp(key, "key1")); + CX_TEST_ASSERT(!cx_strcmp(value, "continue continue ...line")); + + // key2 = value2 + result = cxPropertiesNext(&prop, &key, &value); + CX_TEST_ASSERT(!cx_strcmp(key, "key2")); + CX_TEST_ASSERT(!cx_strcmp(value, "value2")); + + // key3 = continue-line + str = "key3=\\\ncontinue-\\\n line"; + size_t len = strlen(str); + for(size_t i=0;i<len;i++) { + CX_TEST_ASSERT(0 == cxPropertiesFill(&prop, cx_strn(str+i, 1))); + result = cxPropertiesNext(&prop, &key, &value); + CX_TEST_ASSERT(result == CX_PROPERTIES_INCOMPLETE_DATA); + } + CX_TEST_ASSERT(0 == cxPropertiesFill(&prop, "\n")); + result = cxPropertiesNext(&prop, &key, &value); + CX_TEST_ASSERT(result == CX_PROPERTIES_NO_ERROR); + CX_TEST_ASSERT(!cx_strcmp(key, "key3")); + CX_TEST_ASSERT(!cx_strcmp(value, "continue-line")); + } + + cxPropertiesDestroy(&prop); +} + CX_TEST(test_properties_load) { CxTestingAllocator talloc; cx_testing_allocator_init(&talloc); @@ -710,6 +813,8 @@ cx_test_register(suite, test_properties_next_multi); cx_test_register(suite, test_properties_next_part); cx_test_register(suite, test_properties_next_long_lines); + cx_test_register(suite, test_properties_next_line_continuation); + cx_test_register(suite, test_properties_next_line_continuation_part); cx_test_register(suite, test_properties_load); cx_test_register(suite, test_properties_load_empty_file); cx_test_register(suite, test_properties_load_only_comments);