From 070d0ec22b5e6df36f60cbbfad1a1c8bf127dac7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Farkasv=C3=B6lgyi?= Date: Fri, 13 Sep 2019 18:26:00 +0000 Subject: [PATCH] XML attributes unit test * `strtok_r` is not a standard function, and not available wiht std=c11 so I used a public domain implementation of it. * Added an attribute unit test --- src/xml.c | 74 +++++++++++++++++++++++++++++++++++----- test/CMakeLists.txt | 6 +++- test/test-attributes.xml | 1 + test/test-xml-c.c | 33 +++++++++++++++++- 4 files changed, 104 insertions(+), 10 deletions(-) create mode 100644 test/test-attributes.xml diff --git a/src/xml.c b/src/xml.c index 345a453..6e046a4 100644 --- a/src/xml.c +++ b/src/xml.c @@ -36,6 +36,47 @@ +/* + * public domain strtok_r() by Charlie Gordon + * + * from comp.lang.c 9/14/2007 + * + * http://groups.google.com/group/comp.lang.c/msg/2ab1ecbb86646684 + * + * (Declaration that it's public domain): + * http://groups.google.com/group/comp.lang.c/msg/7c7b39328fefab9c + */ +static char* xml_strtok_r(char *str, const char *delim, char **nextp) { + char *ret; + + if (str == NULL) { + str = *nextp; + } + + str += strspn(str, delim); + + if (*str == '\0') { + return NULL; + } + + ret = str; + + str += strcspn(str, delim); + + if (*str) { + *str++ = '\0'; + } + + *nextp = str; + + return ret; +} + + + + + + /** * [OPAQUE API] * @@ -116,9 +157,26 @@ enum xml_parser_offset { /** * [PRIVATE] * - * @return Number of elements in 0-terminated array + * @return Number of attributes in 0-terminated array + */ +static size_t get_zero_terminated_array_attributes(struct xml_attribute** attributes) { + size_t elements = 0; + + while (attributes[elements]) { + ++elements; + } + + return elements; +} + + + +/** + * [PRIVATE] + * + * @return Number of nodes in 0-terminated array */ -static size_t get_zero_terminated_array_elements(struct xml_node** nodes) { +static size_t get_zero_terminated_array_nodes(struct xml_node** nodes) { size_t elements = 0; while (nodes[elements]) { @@ -398,13 +456,13 @@ static struct xml_attribute** xml_find_attributes(struct xml_parser* parser, str tmp = (char*) xml_string_clone(tag_open); - token = strtok_r(tmp, " ", &rest); // skip the first value + token = xml_strtok_r(tmp, " ", &rest); // skip the first value if(token == NULL) { goto cleanup; } tag_open->length = strlen(token); - for(token=strtok_r(NULL," ", &rest); token!=NULL; token=strtok_r(NULL," ", &rest)) { + for(token=xml_strtok_r(NULL," ", &rest); token!=NULL; token=xml_strtok_r(NULL," ", &rest)) { str_name = malloc(strlen(token)+1); str_content = malloc(strlen(token)+1); // %s=\"%s\" wasn't working for some reason, ugly hack to make it work @@ -427,7 +485,7 @@ static struct xml_attribute** xml_find_attributes(struct xml_parser* parser, str new_attribute->content->buffer = (unsigned char*)start_content; new_attribute->content->length = strlen(str_content); - old_elements = get_zero_terminated_array_elements(attributes); + old_elements = get_zero_terminated_array_attributes(attributes); new_elements = old_elements + 1; attributes = realloc(attributes, (new_elements+1)*sizeof(struct xml_attributes*)); @@ -690,7 +748,7 @@ static struct xml_node* xml_parse_node(struct xml_parser* parser) { /* Grow child array :) */ - size_t old_elements = get_zero_terminated_array_elements(children); + size_t old_elements = get_zero_terminated_array_nodes(children); size_t new_elements = old_elements + 1; children = realloc(children, (new_elements + 1) * sizeof(struct xml_node*)); @@ -892,7 +950,7 @@ struct xml_string* xml_node_content(struct xml_node* node) { * @warning O(n) */ size_t xml_node_children(struct xml_node* node) { - return get_zero_terminated_array_elements(node->children); + return get_zero_terminated_array_nodes(node->children); } @@ -914,7 +972,7 @@ struct xml_node* xml_node_child(struct xml_node* node, size_t child) { * [PUBLIC API] */ size_t xml_node_attributes(struct xml_node* node) { - return get_zero_terminated_array_elements(node->attributes); + return get_zero_terminated_array_attributes(node->attributes); } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 99e50dc..09097d0 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -28,11 +28,15 @@ add_test( -# Test case +# Test cases FILE( COPY "${CMAKE_CURRENT_LIST_DIR}/test.xml" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}" ) +FILE( COPY "${CMAKE_CURRENT_LIST_DIR}/test-attributes.xml" + DESTINATION "${CMAKE_CURRENT_BINARY_DIR}" +) + # Test (C) diff --git a/test/test-attributes.xml b/test/test-attributes.xml new file mode 100644 index 0000000..7832c02 --- /dev/null +++ b/test/test-attributes.xml @@ -0,0 +1 @@ + diff --git a/test/test-xml-c.c b/test/test-xml-c.c index 7b0b8b8..ee54bac 100644 --- a/test/test-xml-c.c +++ b/test/test-xml-c.c @@ -217,6 +217,37 @@ static void test_xml_parse_document_3() { +/** + * Test parsing of attributes + * + * @author Isty001 + * @see https://github.com/Isty001/ + */ +static void test_xml_parse_attributes() { + #define FILE_NAME "test-attributes.xml" + FILE* handle = fopen(FILE_NAME, "rb"); + assert_that(handle, "Cannot open " FILE_NAME); + + struct xml_document* document = xml_open_document(handle); + assert_that(document, "Cannot parse " FILE_NAME); + + struct xml_node* element = xml_easy_child( + xml_document_root(document), 0 + ); + + assert_that(element, "Cannot find Document/Element/With"); + assert_that(2 == xml_node_attributes(element), "Should have 2 attributes"); + + assert_that(string_equals(xml_node_attribute_name(element, 0), "value"), "Content of Document/Element/With must be `Child'"); + assert_that(string_equals(xml_node_attribute_content(element, 0), "2"), "First attribute's content should be \"2\""); + + assert_that(string_equals(xml_node_attribute_name(element, 1), "value_2"), "Content of Document/Element/With must be `Child'"); + assert_that(string_equals(xml_node_attribute_content(element, 1), "Hello"), "Second attribute's content should be Hello"); + + xml_document_free(document, true); + #undef FILE_NAME +} + /** @@ -227,8 +258,8 @@ int main(int argc, char** argv) { test_xml_parse_document_1(); test_xml_parse_document_2(); test_xml_parse_document_3(); + test_xml_parse_attributes(); fprintf(stdout, "All tests passed :-)\n"); exit(EXIT_SUCCESS); } -