tests/test_properties.c

changeset 924
3c90dfc35f06
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test_properties.c	Sat Oct 12 19:34:19 2024 +0200
@@ -0,0 +1,380 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2024 Mike Becker, Olaf Wintermann All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "cx/test.h"
+
+#include "cx/properties.h"
+
+CX_TEST(test_cx_properties_init) {
+    CxProperties prop;
+    CX_TEST_DO {
+        cxPropertiesInitDefault(&prop);
+
+        CX_TEST_ASSERT(prop.config.delimiter == '=');
+        CX_TEST_ASSERT(prop.config.comment1 == '#');
+        CX_TEST_ASSERT(prop.config.comment2 == 0);
+        CX_TEST_ASSERT(prop.config.comment3 == 0);
+        CX_TEST_ASSERT(prop.flags == 0);
+        CX_TEST_ASSERT(prop.text == NULL);
+        CX_TEST_ASSERT(prop.buf == NULL);
+
+        cxPropertiesDestroy(&prop);
+    }
+}
+
+CX_TEST(test_cx_properties_next) {
+    const char *tests[] = {
+        "name = value\n",
+        "name=value\n",
+        "n=value\n",
+        "name=v\n",
+        "n=v\n",
+        "name = value # comment\n",
+        "#comment\nn=v\n",
+        "# comment1\n# comment2\n\n    \n\nname = value\n",
+        "    name     =      value\n",
+        "name = value\n\n"
+    };
+
+    const char *keys[] = {
+        "name",
+        "name",
+        "n",
+        "name",
+        "n",
+        "name",
+        "n",
+        "name",
+        "name",
+        "name"
+    };
+
+    const char *values[] = {
+        "value",
+        "value",
+        "value",
+        "v",
+        "v",
+        "value",
+        "v",
+        "value",
+        "value",
+        "value"
+    };
+
+    CxProperties prop;
+    cxPropertiesInitDefault(&prop);
+    enum cx_properties_status result;
+    cxstring key;
+    cxstring value;
+    CX_TEST_DO {
+        for (int i = 0; i < 10; i++) {
+            cxPropertiesInput(&prop, tests[i], strlen(tests[i]));
+            CX_TEST_ASSERT(prop.text == tests[i]);
+            CX_TEST_ASSERT(prop.text_size == strlen(tests[i]));
+            CX_TEST_ASSERT(prop.text_pos == 0);
+
+            result = cxPropertiesNext(&prop, &key, &value);
+            cxstring k = cx_str(keys[i]);
+            cxstring v = cx_str(values[i]);
+            CX_TEST_ASSERT(result == CX_PROPERTIES_NO_ERROR);
+            CX_TEST_ASSERT(0 == cx_strcmp(key, k));
+            CX_TEST_ASSERT(0 == cx_strcmp(value, v));
+
+            result = cxPropertiesNext(&prop, &key, &value);
+            CX_TEST_ASSERT(result == CX_PROPERTIES_NO_DATA);
+        }
+    }
+    cxPropertiesDestroy(&prop);
+}
+
+CX_TEST(test_cx_properties_next_multi) {
+    const char *keys[] = {
+        "a",
+        "b",
+        "c",
+        "uap",
+        "name",
+        "key1",
+        "key2",
+        "key3"
+    };
+
+    const char *values[] = {
+        "a value",
+        "b value",
+        "core",
+        "core",
+        "ucx",
+        "value1",
+        "value2",
+        "value3"
+    };
+
+    const char *str = "#\n"
+        "# properties\n"
+        "# contains key/value pairs\n"
+        "#\n"
+        "a = a value\n"
+        "b = b value\n"
+        "c = core\n"
+        "\n# test\n"
+        "uap = core\n"
+        "name = ucx\n"
+        "# no = property\n"
+        "key1 = value1\n"
+        "#key1 = wrong value\n"
+        "#key2 = not value 2\n"
+        "key2 = value2\n"
+        "\n\n\n        \n           key3=value3\n";
+
+    CxProperties prop;
+    cxPropertiesInitDefault(&prop);
+    enum cx_properties_status result;
+    cxstring key;
+    cxstring value;
+
+    CX_TEST_DO {
+        result = cxPropertiesNext(&prop, &key, &value);
+        CX_TEST_ASSERT(result == CX_PROPERTIES_NULL_INPUT);
+        cxPropertiesInput(&prop, str, strlen(str));
+        for (int i = 0; i < 8; i++) {
+            result = cxPropertiesNext(&prop, &key, &value);
+            CX_TEST_ASSERT(result == CX_PROPERTIES_NO_ERROR);
+            CX_TEST_ASSERT(!cx_strcmp(key, cx_str(keys[i])));
+            CX_TEST_ASSERT(!cx_strcmp(value, cx_str(values[i])));
+        }
+        result = cxPropertiesNext(&prop, &key, &value);
+        CX_TEST_ASSERT(result == CX_PROPERTIES_NO_DATA);
+    }
+    cxPropertiesDestroy(&prop);
+}
+
+CX_TEST(test_cx_properties_next_part) {
+    CxProperties prop;
+    cxPropertiesInitDefault(&prop);
+    enum cx_properties_status result;
+    cxstring key;
+    cxstring value;
+    const char *str;
+
+    CX_TEST_DO {
+        str = "";
+        cxPropertiesFill(&prop, str, strlen(str));
+        result = cxPropertiesNext(&prop, &key,  &value);
+        CX_TEST_ASSERT(result == CX_PROPERTIES_NO_DATA);
+
+        str = "  \n";
+        cxPropertiesFill(&prop, str, strlen(str));
+        result = cxPropertiesNext(&prop, &key,  &value);
+        CX_TEST_ASSERT(result == CX_PROPERTIES_NO_DATA);
+
+        str = "name";
+        cxPropertiesFill(&prop, str, strlen(str));
+        result = cxPropertiesNext(&prop, &key,  &value);
+        CX_TEST_ASSERT(result == CX_PROPERTIES_INCOMPLETE_DATA);
+
+        str = "    ";
+        cxPropertiesFill(&prop, str, strlen(str));
+        result = cxPropertiesNext(&prop, &key,  &value);
+        CX_TEST_ASSERT(result == CX_PROPERTIES_INCOMPLETE_DATA);
+
+        // call fill twice in a row
+        str = "= ";
+        cxPropertiesFill(&prop, str, strlen(str));
+        str = "value";
+        cxPropertiesFill(&prop, str, strlen(str));
+        result = cxPropertiesNext(&prop, &key,  &value);
+        CX_TEST_ASSERT(result == CX_PROPERTIES_INCOMPLETE_DATA);
+
+        str = "\n";
+        cxPropertiesFill(&prop, str, strlen(str));
+        result = cxPropertiesNext(&prop, &key,  &value);
+        CX_TEST_ASSERT(result == CX_PROPERTIES_NO_ERROR);
+        CX_TEST_ASSERT(0 == cx_strcmp(key, cx_str("name")));
+        CX_TEST_ASSERT(0 == cx_strcmp(value, cx_str("value")));
+
+        // second round
+        str = "#comment\n";
+        cxPropertiesFill(&prop, str, strlen(str));
+        result = cxPropertiesNext(&prop, &key,  &value);
+        CX_TEST_ASSERT(result == CX_PROPERTIES_NO_DATA);
+
+        str = "#comment\nname2 = ";
+        cxPropertiesFill(&prop, str, strlen(str));
+        result = cxPropertiesNext(&prop, &key,  &value);
+        CX_TEST_ASSERT(result == CX_PROPERTIES_INCOMPLETE_DATA);
+
+        str = "value2\na = b\n";
+        cxPropertiesFill(&prop, str, strlen(str));
+        result = cxPropertiesNext(&prop, &key,  &value);
+        CX_TEST_ASSERT(result == CX_PROPERTIES_NO_ERROR);
+        CX_TEST_ASSERT(0 == cx_strcmp(key, cx_str("name2")));
+        CX_TEST_ASSERT(0 == cx_strcmp(value, cx_str("value2")));
+
+        result = cxPropertiesNext(&prop, &key,  &value);
+        CX_TEST_ASSERT(result == CX_PROPERTIES_NO_ERROR);
+        CX_TEST_ASSERT(0 == cx_strcmp(key, cx_str("a")));
+        CX_TEST_ASSERT(0 == cx_strcmp(value, cx_str("b")));
+
+        str = "# comment\n#\n#\ntests = ";
+        cxPropertiesFill(&prop, str, strlen(str));
+        result = cxPropertiesNext(&prop, &key,  &value);
+        CX_TEST_ASSERT(result == CX_PROPERTIES_INCOMPLETE_DATA);
+
+        str = "test1 ";
+        cxPropertiesFill(&prop, str, strlen(str));
+        result = cxPropertiesNext(&prop, &key,  &value);
+        CX_TEST_ASSERT(result == CX_PROPERTIES_INCOMPLETE_DATA);
+
+        str = "test2 test3 test4\n";
+        cxPropertiesFill(&prop, str, strlen(str));
+        result = cxPropertiesNext(&prop, &key,  &value);
+        CX_TEST_ASSERT(result == CX_PROPERTIES_NO_ERROR);
+        CX_TEST_ASSERT(0 == cx_strcmp(key, cx_str("tests")));
+        CX_TEST_ASSERT(0 == cx_strcmp(value, cx_str("test1 test2 test3 test4")));
+
+        // test if cxPropertiesNext finds a name/value after a comment
+        str = "# just a comment";
+        cxPropertiesFill(&prop, str, strlen(str));
+        result = cxPropertiesNext(&prop, &key,  &value);
+        CX_TEST_ASSERT(result == CX_PROPERTIES_INCOMPLETE_DATA);
+
+        str = " in 3";
+        cxPropertiesFill(&prop, str, strlen(str));
+        result = cxPropertiesNext(&prop, &key,  &value);
+        CX_TEST_ASSERT(result == CX_PROPERTIES_INCOMPLETE_DATA);
+
+        str = " parts\nx = 1\n";
+        cxPropertiesFill(&prop, str, strlen(str));
+        result = cxPropertiesNext(&prop, &key,  &value);
+        CX_TEST_ASSERT(result == CX_PROPERTIES_NO_ERROR);
+        CX_TEST_ASSERT(0 == cx_strcmp(key, cx_str("x")));
+        CX_TEST_ASSERT(0 == cx_strcmp(value, cx_str("1")));
+        
+        // finally we are done
+        result = cxPropertiesNext(&prop, &key,  &value);
+        CX_TEST_ASSERT(result == CX_PROPERTIES_NO_DATA);
+    }
+    cxPropertiesDestroy(&prop);
+}
+
+CX_TEST(test_ucx_properties_next_long_lines) {
+    CxProperties prop;
+    cxPropertiesInitDefault(&prop);
+    enum cx_properties_status result;
+    cxstring key;
+    cxstring value;
+    
+    size_t key_len = 512;
+    char *long_key = (char*)malloc(key_len);
+    memset(long_key, 'a', 70);
+    memset(long_key + 70, 'b', 242);
+    memset(long_key + 312, 'c', 200);
+
+    size_t value_len = 2048;
+    char *long_value = (char*)malloc(value_len);
+    memset(long_value, 'x', 1024);
+    memset(long_value+1024, 'y', 1024);
+
+    CX_TEST_DO {
+        cxPropertiesFill(&prop, long_key, 10);
+        result = cxPropertiesNext(&prop, &key, &value);
+        CX_TEST_ASSERT(result == CX_PROPERTIES_INCOMPLETE_DATA);
+
+        cxPropertiesFill(&prop, long_key + 10, 202);
+        result = cxPropertiesNext(&prop, &key, &value);
+        CX_TEST_ASSERT(result == CX_PROPERTIES_INCOMPLETE_DATA);
+
+        cxPropertiesFill(&prop, long_key + 212, 200);
+        result = cxPropertiesNext(&prop, &key, &value);
+        CX_TEST_ASSERT(result == CX_PROPERTIES_INCOMPLETE_DATA);
+
+        cxPropertiesFill(&prop, long_key + 412, 100);
+        result = cxPropertiesNext(&prop, &key, &value);
+        CX_TEST_ASSERT(result == CX_PROPERTIES_INCOMPLETE_DATA);
+
+        const char *str = " = ";
+        cxPropertiesFill(&prop, str, strlen(str));
+        result = cxPropertiesNext(&prop, &key, &value);
+        CX_TEST_ASSERT(result == CX_PROPERTIES_INCOMPLETE_DATA);
+
+        cxPropertiesFill(&prop, long_value, 512);
+        result = cxPropertiesNext(&prop, &key, &value);
+        CX_TEST_ASSERT(result == CX_PROPERTIES_INCOMPLETE_DATA);
+
+        cxPropertiesFill(&prop, long_value + 512, 1024);
+        result = cxPropertiesNext(&prop, &key, &value);
+        CX_TEST_ASSERT(result == CX_PROPERTIES_INCOMPLETE_DATA);
+
+        cxPropertiesFill(&prop, long_value + 1536, 512);
+        result = cxPropertiesNext(&prop, &key, &value);
+        CX_TEST_ASSERT(result == CX_PROPERTIES_INCOMPLETE_DATA);
+
+        str = "\n#comment\nkey = value\n";
+        cxPropertiesFill(&prop, str, strlen(str));
+        result = cxPropertiesNext(&prop, &key, &value);
+        cxstring k = cx_strn(long_key, key_len);
+        cxstring v = cx_strn(long_value, value_len);
+        CX_TEST_ASSERT(result == CX_PROPERTIES_NO_ERROR);
+        CX_TEST_ASSERT(0 == cx_strcmp(key, k));
+        CX_TEST_ASSERT(0 == cx_strcmp(value, v));
+
+        result = cxPropertiesNext(&prop, &key, &value);
+        CX_TEST_ASSERT(result == CX_PROPERTIES_NO_ERROR);
+        CX_TEST_ASSERT(0 == cx_strcmp(key, cx_str("key")));
+        CX_TEST_ASSERT(0 == cx_strcmp(value, cx_str("value")));
+
+        result = cxPropertiesNext(&prop, &key, &value);
+        CX_TEST_ASSERT(result == CX_PROPERTIES_NO_DATA);
+
+        CX_TEST_ASSERT(prop.buf != NULL);
+        CX_TEST_ASSERT(prop.buf_capacity > 0);
+        CX_TEST_ASSERT(prop.buf_size == 0);
+        cxPropertiesDestroy(&prop);
+
+        CX_TEST_ASSERT(prop.buf == NULL);
+        CX_TEST_ASSERT(prop.buf_capacity == 0);
+        CX_TEST_ASSERT(prop.buf_size == 0);
+    }
+
+    free(long_key);
+    free(long_value);
+}
+
+CxTestSuite *cx_test_suite_properties(void) {
+    CxTestSuite *suite = cx_test_suite_new("properties");
+
+    cx_test_register(suite, test_cx_properties_init);
+    cx_test_register(suite, test_cx_properties_next);
+    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);
+
+    return suite;
+}

mercurial