diff options
Diffstat (limited to 'tests/utests/basic/test_xml.c')
-rw-r--r-- | tests/utests/basic/test_xml.c | 690 |
1 files changed, 690 insertions, 0 deletions
diff --git a/tests/utests/basic/test_xml.c b/tests/utests/basic/test_xml.c new file mode 100644 index 0000000..668de4b --- /dev/null +++ b/tests/utests/basic/test_xml.c @@ -0,0 +1,690 @@ +/* + * @file test_xml.c + * @author: Radek Krejci <rkrejci@cesnet.cz> + * @brief unit tests for functions from xml.c + * + * Copyright (c) 2018 CESNET, z.s.p.o. + * + * This source code is licensed under BSD 3-Clause License (the "License"). + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + */ +#define _UTEST_MAIN_ +#include "utests.h" + +#define _POSIX_C_SOURCE 200809L /* strdup */ + +#include <string.h> + +#include "context.h" +#include "in_internal.h" +#include "xml.h" + +LY_ERR lyxml_ns_add(struct lyxml_ctx *xmlctx, const char *prefix, size_t prefix_len, char *uri); + +static void +test_element(void **state) +{ + struct lyxml_ctx *xmlctx; + struct ly_in *in; + const char *str; + + /* empty */ + str = ""; + assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in)); + assert_int_equal(LY_SUCCESS, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx)); + assert_int_equal(LYXML_END, xmlctx->status); + lyxml_ctx_free(xmlctx); + ly_in_free(in, 0); + + /* end element */ + str = "</element>"; + assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in)); + assert_int_equal(LY_EVALID, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx)); + CHECK_LOG_CTX("Stray closing element tag (\"element\").", "Line number 1."); + ly_in_free(in, 0); + + /* no element */ + UTEST_LOG_CLEAN; + str = "no data present"; + assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in)); + assert_int_equal(LY_EVALID, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx)); + CHECK_LOG_CTX("Invalid character sequence \"no data present\", expected element tag start ('<').", "Line number 1."); + ly_in_free(in, 0); + + /* not supported DOCTYPE */ + str = "<!DOCTYPE greeting SYSTEM \"hello.dtd\"><greeting/>"; + assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in)); + assert_int_equal(LY_EVALID, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx)); + CHECK_LOG_CTX("Document Type Declaration not supported.", "Line number 1."); + ly_in_free(in, 0); + + /* invalid XML */ + str = "<!NONSENSE/>"; + assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in)); + assert_int_equal(LY_EVALID, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx)); + CHECK_LOG_CTX("Unknown XML section \"<!NONSENSE/>\".", "Line number 1."); + ly_in_free(in, 0); + + /* namespace ambiguity */ + str = "<element xmlns=\"urn1\" xmlns=\"urn2\"/>"; + assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in)); + assert_int_equal(LY_EVALID, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx)); + CHECK_LOG_CTX("Duplicate default XML namespaces \"urn1\" and \"urn2\".", "Line number 1."); + ly_in_free(in, 0); + + /* prefix duplicate */ + str = "<element xmlns:a=\"urn1\" xmlns:a=\"urn2\"/>"; + assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in)); + assert_int_equal(LY_EVALID, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx)); + CHECK_LOG_CTX("Duplicate XML NS prefix \"a\" used for namespaces \"urn1\" and \"urn2\".", "Line number 1."); + ly_in_free(in, 0); + + /* unqualified element */ + str = " < element/>"; + assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in)); + assert_int_equal(LY_SUCCESS, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx)); + assert_int_equal(LYXML_ELEMENT, xmlctx->status); + assert_null(xmlctx->prefix); + assert_true(!strncmp("element", xmlctx->name, xmlctx->name_len)); + assert_int_equal(1, xmlctx->elements.count); + + assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx)); + assert_int_equal(LYXML_ELEM_CONTENT, xmlctx->status); + assert_true(!strncmp("", xmlctx->value, xmlctx->value_len)); + + assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx)); + assert_int_equal(LYXML_ELEM_CLOSE, xmlctx->status); + + assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx)); + assert_int_equal(LYXML_END, xmlctx->status); + lyxml_ctx_free(xmlctx); + ly_in_free(in, 0); + + /* element with attribute */ + str = " < element attr=\'x\'/>"; + assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in)); + assert_int_equal(LY_SUCCESS, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx)); + assert_int_equal(LYXML_ELEMENT, xmlctx->status); + assert_true(!strncmp("element", xmlctx->name, xmlctx->name_len)); + assert_null(xmlctx->prefix); + assert_int_equal(1, xmlctx->elements.count); + + assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx)); + assert_int_equal(LYXML_ATTRIBUTE, xmlctx->status); + assert_true(!strncmp("attr", xmlctx->name, xmlctx->name_len)); + assert_null(xmlctx->prefix); + + assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx)); + assert_int_equal(LYXML_ATTR_CONTENT, xmlctx->status); + assert_int_equal(1, xmlctx->elements.count); + assert_true(!strncmp("x", xmlctx->value, xmlctx->value_len)); + + assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx)); + assert_int_equal(LYXML_ELEM_CONTENT, xmlctx->status); + + assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx)); + assert_int_equal(LYXML_ELEM_CLOSE, xmlctx->status); + assert_int_equal(0, xmlctx->elements.count); + + assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx)); + assert_int_equal(LYXML_END, xmlctx->status); + lyxml_ctx_free(xmlctx); + ly_in_free(in, 0); + + /* headers and comments */ + str = "<?xml version=\"1.0\"?> <!-- comment --> <?TEST xxx?> <element/>"; + assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in)); + assert_int_equal(LY_SUCCESS, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx)); + assert_int_equal(LYXML_ELEMENT, xmlctx->status); + assert_true(!strncmp("element", xmlctx->name, xmlctx->name_len)); + assert_null(xmlctx->prefix); + assert_int_equal(1, xmlctx->elements.count); + + assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx)); + assert_int_equal(LYXML_ELEM_CONTENT, xmlctx->status); + + assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx)); + assert_int_equal(LYXML_ELEM_CLOSE, xmlctx->status); + + assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx)); + assert_int_equal(LYXML_END, xmlctx->status); + lyxml_ctx_free(xmlctx); + ly_in_free(in, 0); + + /* separate opening and closing tags, neamespaced parsed internally */ + str = "<element xmlns=\"urn\"></element>"; + assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in)); + assert_int_equal(LY_SUCCESS, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx)); + assert_int_equal(LYXML_ELEMENT, xmlctx->status); + assert_true(!strncmp("element", xmlctx->name, xmlctx->name_len)); + assert_null(xmlctx->prefix); + assert_int_equal(1, xmlctx->elements.count); + assert_int_equal(1, xmlctx->ns.count); + + assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx)); + assert_int_equal(LYXML_ELEM_CONTENT, xmlctx->status); + + assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx)); + assert_int_equal(LYXML_ELEM_CLOSE, xmlctx->status); + assert_int_equal(0, xmlctx->elements.count); + assert_int_equal(0, xmlctx->ns.count); + + assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx)); + assert_int_equal(LYXML_END, xmlctx->status); + lyxml_ctx_free(xmlctx); + ly_in_free(in, 0); + + /* qualified element */ + str = " < yin:element/>"; + assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in)); + assert_int_equal(LY_SUCCESS, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx)); + assert_int_equal(LYXML_ELEMENT, xmlctx->status); + assert_true(!strncmp("element", xmlctx->name, xmlctx->name_len)); + assert_true(!strncmp("yin", xmlctx->prefix, xmlctx->prefix_len)); + + assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx)); + assert_int_equal(LYXML_ELEM_CONTENT, xmlctx->status); + + assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx)); + assert_int_equal(LYXML_ELEM_CLOSE, xmlctx->status); + + assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx)); + assert_int_equal(LYXML_END, xmlctx->status); + lyxml_ctx_free(xmlctx); + ly_in_free(in, 0); + + /* non-matching closing tag */ + str = "<yin:element xmlns=\"urn\"></element>"; + assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in)); + assert_int_equal(LY_SUCCESS, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx)); + assert_int_equal(LYXML_ELEMENT, xmlctx->status); + assert_true(!strncmp("element", xmlctx->name, xmlctx->name_len)); + assert_true(!strncmp("yin", xmlctx->prefix, xmlctx->prefix_len)); + assert_int_equal(1, xmlctx->elements.count); + assert_int_equal(1, xmlctx->ns.count); + + assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx)); + assert_int_equal(LYXML_ELEM_CONTENT, xmlctx->status); + + assert_int_equal(LY_EVALID, lyxml_ctx_next(xmlctx)); + CHECK_LOG_CTX("Opening (\"yin:element\") and closing (\"element\") elements tag mismatch.", "Line number 1."); + lyxml_ctx_free(xmlctx); + ly_in_free(in, 0); + + /* invalid closing tag */ + str = "<yin:element xmlns=\"urn\"></yin:element/>"; + assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in)); + assert_int_equal(LY_SUCCESS, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx)); + assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx)); + assert_int_equal(LY_EVALID, lyxml_ctx_next(xmlctx)); + CHECK_LOG_CTX("Invalid character sequence \"/>\", expected element tag termination ('>').", "Line number 1."); + lyxml_ctx_free(xmlctx); + ly_in_free(in, 0); + + /* UTF8 characters */ + str = "<𠜎€𠜎Øn:𠜎€𠜎Øn/>"; + assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in)); + assert_int_equal(LY_SUCCESS, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx)); + assert_true(!strncmp("𠜎€𠜎Øn", xmlctx->name, xmlctx->name_len)); + assert_true(!strncmp("𠜎€𠜎Øn", xmlctx->prefix, xmlctx->prefix_len)); + + assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx)); + assert_int_equal(LYXML_ELEM_CONTENT, xmlctx->status); + + assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx)); + assert_int_equal(LYXML_ELEM_CLOSE, xmlctx->status); + + assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx)); + assert_int_equal(LYXML_END, xmlctx->status); + lyxml_ctx_free(xmlctx); + ly_in_free(in, 0); + + /* invalid UTF-8 characters */ + str = "<¢:element>"; + assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in)); + assert_int_equal(LY_EVALID, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx)); + CHECK_LOG_CTX("Identifier \"¢:element>\" starts with an invalid character.", "Line number 1."); + ly_in_free(in, 0); + + str = "<yin:c⁐element>"; + assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in)); + assert_int_equal(LY_SUCCESS, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx)); + assert_int_equal(LY_EVALID, lyxml_ctx_next(xmlctx)); + CHECK_LOG_CTX("Invalid character sequence \"⁐element>\", expected element tag end ('>' or '/>') or an attribute.", "Line number 1."); + lyxml_ctx_free(xmlctx); + ly_in_free(in, 0); + + /* mixed content */ + str = "<a>text <b>x</b></a>"; + assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in)); + assert_int_equal(LY_SUCCESS, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx)); + assert_int_equal(LYXML_ELEMENT, xmlctx->status); + assert_true(!strncmp("a", xmlctx->name, xmlctx->name_len)); + assert_null(xmlctx->prefix); + + assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx)); + assert_int_equal(LYXML_ELEM_CONTENT, xmlctx->status); + assert_true(!strncmp("text ", xmlctx->value, xmlctx->value_len)); + + assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx)); + assert_int_equal(LYXML_ELEMENT, xmlctx->status); + assert_true(!strncmp("b", xmlctx->name, xmlctx->name_len)); + assert_null(xmlctx->prefix); + + assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx)); + assert_int_equal(LYXML_ELEM_CONTENT, xmlctx->status); + assert_true(!strncmp("x", xmlctx->value, xmlctx->value_len)); + + assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx)); + assert_int_equal(LYXML_ELEM_CLOSE, xmlctx->status); + + assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx)); + assert_int_equal(LYXML_ELEM_CLOSE, xmlctx->status); + + assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx)); + assert_int_equal(LYXML_END, xmlctx->status); + lyxml_ctx_free(xmlctx); + ly_in_free(in, 0); + + /* tag mismatch */ + str = "<a>text</b>"; + assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in)); + assert_int_equal(LY_SUCCESS, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx)); + assert_int_equal(LYXML_ELEMENT, xmlctx->status); + assert_true(!strncmp("a", xmlctx->name, xmlctx->name_len)); + assert_null(xmlctx->prefix); + + assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx)); + assert_int_equal(LYXML_ELEM_CONTENT, xmlctx->status); + assert_true(!strncmp("text", xmlctx->value, xmlctx->value_len)); + + assert_int_equal(LY_EVALID, lyxml_ctx_next(xmlctx)); + CHECK_LOG_CTX("Opening (\"a\") and closing (\"b\") elements tag mismatch.", "Line number 1."); + lyxml_ctx_free(xmlctx); + ly_in_free(in, 0); +} + +static void +test_attribute(void **state) +{ + const char *str; + struct lyxml_ctx *xmlctx; + struct ly_in *in; + struct lyxml_ns *ns; + + /* not an attribute */ + str = "<e unknown/>"; + assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in)); + assert_int_equal(LY_EVALID, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx)); + CHECK_LOG_CTX("Invalid character sequence \"/>\", expected '='.", "Line number 1."); + ly_in_free(in, 0); + + str = "<e xxx=/>"; + assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in)); + assert_int_equal(LY_EVALID, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx)); + CHECK_LOG_CTX("Invalid character sequence \"/>\", expected either single or double quotation mark.", "Line number 1."); + ly_in_free(in, 0); + + str = "<e xxx\n = yyy/>"; + assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in)); + assert_int_equal(LY_EVALID, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx)); + CHECK_LOG_CTX("Invalid character sequence \"yyy/>\", expected either single or double quotation mark.", "Line number 2."); + ly_in_free(in, 0); + + /* valid attribute */ + str = "<e attr=\"val\""; + assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in)); + assert_int_equal(LY_SUCCESS, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx)); + assert_int_equal(LYXML_ELEMENT, xmlctx->status); + assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx)); + assert_int_equal(LYXML_ATTRIBUTE, xmlctx->status); + assert_true(!strncmp("attr", xmlctx->name, xmlctx->name_len)); + assert_null(xmlctx->prefix); + + assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx)); + assert_int_equal(LYXML_ATTR_CONTENT, xmlctx->status); + assert_true(!strncmp("val", xmlctx->value, xmlctx->value_len)); + assert_int_equal(xmlctx->ws_only, 0); + assert_int_equal(xmlctx->dynamic, 0); + lyxml_ctx_free(xmlctx); + ly_in_free(in, 0); + + /* valid namespace with prefix */ + str = "<e xmlns:nc\n = \'urn\'/>"; + assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in)); + assert_int_equal(LY_SUCCESS, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx)); + assert_int_equal(LYXML_ELEMENT, xmlctx->status); + assert_int_equal(1, xmlctx->ns.count); + ns = (struct lyxml_ns *)xmlctx->ns.objs[0]; + assert_string_equal(ns->prefix, "nc"); + assert_string_equal(ns->uri, "urn"); + lyxml_ctx_free(xmlctx); + ly_in_free(in, 0); +} + +static void +test_text(void **state) +{ + const char *str; + struct lyxml_ctx *xmlctx; + struct ly_in *in; + + /* empty attribute value */ + str = "<e a=\"\""; + assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in)); + assert_int_equal(LY_SUCCESS, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx)); + assert_int_equal(LYXML_ELEMENT, xmlctx->status); + assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx)); + assert_int_equal(LYXML_ATTRIBUTE, xmlctx->status); + + assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx)); + assert_int_equal(LYXML_ATTR_CONTENT, xmlctx->status); + assert_true(!strncmp("", xmlctx->value, xmlctx->value_len)); + assert_int_equal(xmlctx->ws_only, 1); + assert_int_equal(xmlctx->dynamic, 0); + ly_in_free(in, 0); + + /* empty value but in single quotes */ + assert_int_equal(LY_SUCCESS, ly_in_new_memory("=\'\'", &in)); + xmlctx->in = in; + LOG_LOCSET(NULL, NULL, NULL, in); + xmlctx->status = LYXML_ATTRIBUTE; + assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx)); + assert_int_equal(LYXML_ATTR_CONTENT, xmlctx->status); + assert_true(!strncmp("", xmlctx->value, xmlctx->value_len)); + assert_int_equal(xmlctx->ws_only, 1); + assert_int_equal(xmlctx->dynamic, 0); + ly_in_free(in, 0); + + /* empty element content - only formating before defining child */ + assert_int_equal(LY_SUCCESS, ly_in_new_memory(">\n <y>", &in)); + xmlctx->in = in; + LOG_LOCSET(NULL, NULL, NULL, in); + xmlctx->status = LYXML_ELEMENT; + assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx)); + assert_int_equal(LYXML_ELEM_CONTENT, xmlctx->status); + assert_true(!strncmp("\n ", xmlctx->value, xmlctx->value_len)); + assert_int_equal(xmlctx->ws_only, 1); + assert_int_equal(xmlctx->dynamic, 0); + ly_in_free(in, 0); + + /* empty element content is invalid - missing content terminating character < */ + assert_int_equal(LY_SUCCESS, ly_in_new_memory("", &in)); + xmlctx->in = in; + LOG_LOCSET(NULL, NULL, NULL, in); + xmlctx->status = LYXML_ELEM_CONTENT; + assert_int_equal(LY_EVALID, lyxml_ctx_next(xmlctx)); + CHECK_LOG_CTX("Unexpected end-of-input.", "Line number 1."); + ly_in_free(in, 0); + + assert_int_equal(LY_SUCCESS, ly_in_new_memory("xxx", &in)); + xmlctx->in = in; + LOG_LOCSET(NULL, NULL, NULL, in); + xmlctx->status = LYXML_ELEM_CONTENT; + assert_int_equal(LY_EVALID, lyxml_ctx_next(xmlctx)); + CHECK_LOG_CTX("Invalid character sequence \"xxx\", expected element tag start ('<').", "Line number 1."); + ly_in_free(in, 0); + + lyxml_ctx_free(xmlctx); + LOG_LOCBACK(0, 0, 0, 4); + + /* valid strings */ + str = "<a>€𠜎Øn \n<&"'> ROK</a>"; + assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in)); + assert_int_equal(LY_SUCCESS, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx)); + assert_int_equal(LYXML_ELEMENT, xmlctx->status); + + assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx)); + assert_int_equal(LYXML_ELEM_CONTENT, xmlctx->status); + assert_true(!strncmp("€𠜎Øn \n<&\"\'> ROK", xmlctx->value, xmlctx->value_len)); + assert_int_equal(xmlctx->ws_only, 0); + assert_int_equal(xmlctx->dynamic, 1); + free((char *)xmlctx->value); + ly_in_free(in, 0); + + /* test using n-bytes UTF8 hexadecimal code points */ + assert_int_equal(LY_SUCCESS, ly_in_new_memory("=\'$¢€𐍈\'", &in)); + xmlctx->in = in; + LOG_LOCSET(NULL, NULL, NULL, in); + xmlctx->status = LYXML_ATTRIBUTE; + assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx)); + assert_int_equal(LYXML_ATTR_CONTENT, xmlctx->status); + assert_true(!strncmp("$¢€𐍈", xmlctx->value, xmlctx->value_len)); + assert_int_equal(xmlctx->ws_only, 0); + assert_int_equal(xmlctx->dynamic, 1); + ly_in_free(in, 0); + + /* CDATA value */ + assert_int_equal(LY_SUCCESS, ly_in_new_memory("> <![CDATA[ special non-escaped chars <>&\"' ]]> </a>", &in)); + xmlctx->in = in; + LOG_LOCSET(NULL, NULL, NULL, in); + xmlctx->status = LYXML_ATTR_CONTENT; + assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx)); + assert_int_equal(LYXML_ELEM_CONTENT, xmlctx->status); + assert_true(!strncmp(" special non-escaped chars <>&\"' ", xmlctx->value, xmlctx->value_len)); + assert_int_equal(xmlctx->ws_only, 0); + assert_int_equal(xmlctx->dynamic, 1); + free((char *)xmlctx->value); + ly_in_free(in, 0); + + /* invalid characters in string */ + assert_int_equal(LY_SUCCESS, ly_in_new_memory("=\'R\'", &in)); + xmlctx->in = in; + LOG_LOCSET(NULL, NULL, NULL, in); + xmlctx->status = LYXML_ATTRIBUTE; + assert_int_equal(LY_EVALID, lyxml_ctx_next(xmlctx)); + CHECK_LOG_CTX("Invalid character sequence \"'\", expected ;.", "Line number 1."); + ly_in_free(in, 0); + + assert_int_equal(LY_SUCCESS, ly_in_new_memory("=\"R\"", &in)); + xmlctx->in = in; + LOG_LOCSET(NULL, NULL, NULL, in); + xmlctx->status = LYXML_ATTRIBUTE; + assert_int_equal(LY_EVALID, lyxml_ctx_next(xmlctx)); + CHECK_LOG_CTX("Invalid character sequence \"\"\", expected ;.", "Line number 1."); + ly_in_free(in, 0); + + assert_int_equal(LY_SUCCESS, ly_in_new_memory("=\"&nonsense;\"", &in)); + xmlctx->in = in; + LOG_LOCSET(NULL, NULL, NULL, in); + xmlctx->status = LYXML_ATTRIBUTE; + assert_int_equal(LY_EVALID, lyxml_ctx_next(xmlctx)); + CHECK_LOG_CTX("Entity reference \"&nonsense;\" not supported, only predefined references allowed.", "Line number 1."); + ly_in_free(in, 0); + + assert_int_equal(LY_SUCCESS, ly_in_new_memory(">&#o122;", &in)); + xmlctx->in = in; + LOG_LOCSET(NULL, NULL, NULL, in); + xmlctx->status = LYXML_ELEMENT; + assert_int_equal(LY_EVALID, lyxml_ctx_next(xmlctx)); + CHECK_LOG_CTX("Invalid character reference \"&#o122;\".", "Line number 1."); + ly_in_free(in, 0); + + assert_int_equal(LY_SUCCESS, ly_in_new_memory("=\'\'", &in)); + xmlctx->in = in; + LOG_LOCSET(NULL, NULL, NULL, in); + xmlctx->status = LYXML_ATTRIBUTE; + assert_int_equal(LY_EVALID, lyxml_ctx_next(xmlctx)); + CHECK_LOG_CTX("Invalid character reference \"\'\" (0x00000006).", "Line number 1."); + ly_in_free(in, 0); + + assert_int_equal(LY_SUCCESS, ly_in_new_memory("=\'\'", &in)); + xmlctx->in = in; + LOG_LOCSET(NULL, NULL, NULL, in); + xmlctx->status = LYXML_ATTRIBUTE; + assert_int_equal(LY_EVALID, lyxml_ctx_next(xmlctx)); + CHECK_LOG_CTX("Invalid character reference \"\'\" (0x0000fdd0).", "Line number 1."); + ly_in_free(in, 0); + + assert_int_equal(LY_SUCCESS, ly_in_new_memory("=\'\'", &in)); + xmlctx->in = in; + LOG_LOCSET(NULL, NULL, NULL, in); + xmlctx->status = LYXML_ATTRIBUTE; + assert_int_equal(LY_EVALID, lyxml_ctx_next(xmlctx)); + CHECK_LOG_CTX("Invalid character reference \"\'\" (0x0000ffff).", "Line number 1."); + ly_in_free(in, 0); + + lyxml_ctx_free(xmlctx); + LOG_LOCBACK(0, 0, 0, 9); +} + +static void +test_ns(void **state) +{ + const char *str; + struct lyxml_ctx *xmlctx; + struct ly_in *in; + const struct lyxml_ns *ns; + + /* opening element1 */ + str = "<element1/>"; + assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in)); + assert_int_equal(LY_SUCCESS, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx)); + + /* processing namespace definitions */ + assert_int_equal(LY_SUCCESS, lyxml_ns_add(xmlctx, NULL, 0, strdup("urn:default"))); + assert_int_equal(LY_SUCCESS, lyxml_ns_add(xmlctx, "nc", 2, strdup("urn:nc1"))); + /* simulate adding open element2 into context */ + xmlctx->elements.count++; + /* processing namespace definitions */ + assert_int_equal(LY_SUCCESS, lyxml_ns_add(xmlctx, "nc", 2, strdup("urn:nc2"))); + assert_int_equal(3, xmlctx->ns.count); + assert_int_not_equal(0, xmlctx->ns.size); + + ns = lyxml_ns_get(&xmlctx->ns, NULL, 0); + assert_non_null(ns); + assert_null(ns->prefix); + assert_string_equal("urn:default", ns->uri); + + ns = lyxml_ns_get(&xmlctx->ns, "nc", 2); + assert_non_null(ns); + assert_string_equal("nc", ns->prefix); + assert_string_equal("urn:nc2", ns->uri); + + /* simulate closing element2 */ + xmlctx->elements.count--; + lyxml_ns_rm(xmlctx); + assert_int_equal(2, xmlctx->ns.count); + + ns = lyxml_ns_get(&xmlctx->ns, "nc", 2); + assert_non_null(ns); + assert_string_equal("nc", ns->prefix); + assert_string_equal("urn:nc1", ns->uri); + + /* close element1 */ + assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx)); + assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx)); + assert_int_equal(0, xmlctx->ns.count); + + assert_null(lyxml_ns_get(&xmlctx->ns, "nc", 2)); + assert_null(lyxml_ns_get(&xmlctx->ns, NULL, 0)); + + lyxml_ctx_free(xmlctx); + ly_in_free(in, 0); +} + +static void +test_ns2(void **state) +{ + const char *str; + struct lyxml_ctx *xmlctx; + struct ly_in *in; + + /* opening element1 */ + str = "<element1/>"; + assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in)); + assert_int_equal(LY_SUCCESS, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx)); + + /* default namespace defined in parent element1 */ + assert_int_equal(LY_SUCCESS, lyxml_ns_add(xmlctx, NULL, 0, strdup("urn:default"))); + assert_int_equal(1, xmlctx->ns.count); + /* going into child element1 */ + /* simulate adding open element1 into context */ + xmlctx->elements.count++; + /* no namespace defined, going out (first, simulate closing of so far open element) */ + xmlctx->elements.count--; + lyxml_ns_rm(xmlctx); + assert_int_equal(1, xmlctx->ns.count); + + /* nothing else, going out of the parent element1 */ + assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx)); + assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx)); + assert_int_equal(0, xmlctx->ns.count); + + lyxml_ctx_free(xmlctx); + ly_in_free(in, 0); +} + +static void +test_simple_xml(void **state) +{ + struct lyxml_ctx *xmlctx; + struct ly_in *in; + const char *test_input = "<elem1 attr1=\"value\"> <elem2 attr2=\"value\" /> </elem1>"; + + assert_int_equal(LY_SUCCESS, ly_in_new_memory(test_input, &in)); + assert_int_equal(LY_SUCCESS, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx)); + assert_int_equal(LYXML_ELEMENT, xmlctx->status); + assert_string_equal(xmlctx->in->current, "attr1=\"value\"> <elem2 attr2=\"value\" /> </elem1>"); + + assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx)); + assert_int_equal(LYXML_ATTRIBUTE, xmlctx->status); + assert_string_equal(xmlctx->in->current, "=\"value\"> <elem2 attr2=\"value\" /> </elem1>"); + + assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx)); + assert_int_equal(LYXML_ATTR_CONTENT, xmlctx->status); + assert_string_equal(xmlctx->in->current, "> <elem2 attr2=\"value\" /> </elem1>"); + + assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx)); + assert_int_equal(LYXML_ELEM_CONTENT, xmlctx->status); + assert_string_equal(xmlctx->in->current, "<elem2 attr2=\"value\" /> </elem1>"); + + assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx)); + assert_int_equal(LYXML_ELEMENT, xmlctx->status); + assert_string_equal(xmlctx->in->current, "attr2=\"value\" /> </elem1>"); + + assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx)); + assert_int_equal(LYXML_ATTRIBUTE, xmlctx->status); + assert_string_equal(xmlctx->in->current, "=\"value\" /> </elem1>"); + + assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx)); + assert_int_equal(LYXML_ATTR_CONTENT, xmlctx->status); + assert_string_equal(xmlctx->in->current, " /> </elem1>"); + + assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx)); + assert_int_equal(LYXML_ELEM_CONTENT, xmlctx->status); + assert_string_equal(xmlctx->in->current, "/> </elem1>"); + + assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx)); + assert_int_equal(LYXML_ELEM_CLOSE, xmlctx->status); + assert_string_equal(xmlctx->in->current, " </elem1>"); + + assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx)); + assert_int_equal(LYXML_ELEM_CLOSE, xmlctx->status); + assert_string_equal(xmlctx->in->current, ""); + + assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx)); + assert_int_equal(LYXML_END, xmlctx->status); + assert_string_equal(xmlctx->in->current, ""); + + lyxml_ctx_free(xmlctx); + ly_in_free(in, 0); +} + +int +main(void) +{ + const struct CMUnitTest tests[] = { + UTEST(test_element), + UTEST(test_attribute), + UTEST(test_text), + UTEST(test_ns), + UTEST(test_ns2), + UTEST(test_simple_xml), + }; + + return cmocka_run_group_tests(tests, NULL, NULL); +} |