blob: 6af5a796bea0d6428214cfd565720a8805eaeb20 [file] [log] [blame]
Radek Krejcid91dbaf2018-09-21 15:51:39 +02001/*
2 * @file xml.c
3 * @author: Radek Krejci <rkrejci@cesnet.cz>
4 * @brief unit tests for functions from xml.c
5 *
6 * Copyright (c) 2018 CESNET, z.s.p.o.
7 *
8 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * https://opensource.org/licenses/BSD-3-Clause
13 */
14
Radek Krejci2d7a47b2019-05-16 13:34:10 +020015#define _DEFAULT_SOURCE
16#define _GNU_SOURCE
Radek Krejcib7db73a2018-10-24 14:18:40 +020017
Radek Krejcid91dbaf2018-09-21 15:51:39 +020018#include <stdarg.h>
19#include <stddef.h>
20#include <setjmp.h>
21#include <cmocka.h>
22
Radek Krejci2d7a47b2019-05-16 13:34:10 +020023#include <stdlib.h>
Radek Krejcid91dbaf2018-09-21 15:51:39 +020024#include <stdio.h>
25#include <string.h>
26
Radek Krejci2d7a47b2019-05-16 13:34:10 +020027#include "../../src/xml.h"
28
29LY_ERR lyxml_ns_add(struct lyxml_context *context, const char *prefix, size_t prefix_len, char *uri);
30LY_ERR lyxml_ns_rm(struct lyxml_context *context);
Radek Krejcid91dbaf2018-09-21 15:51:39 +020031
32#define BUFSIZE 1024
33char logbuf[BUFSIZE] = {0};
34
35/* set to 0 to printing error messages to stderr instead of checking them in code */
36#define ENABLE_LOGGER_CHECKING 1
37
38static void
39logger(LY_LOG_LEVEL level, const char *msg, const char *path)
40{
41 (void) level; /* unused */
42
43 if (path) {
44 snprintf(logbuf, BUFSIZE - 1, "%s %s", msg, path);
45 } else {
46 strncpy(logbuf, msg, BUFSIZE - 1);
47 }
48}
49
50static int
51logger_setup(void **state)
52{
53 (void) state; /* unused */
54#if ENABLE_LOGGER_CHECKING
55 ly_set_log_clb(logger, 1);
56#endif
57 return 0;
58}
59
60void
61logbuf_clean(void)
62{
63 logbuf[0] = '\0';
64}
65
66#if ENABLE_LOGGER_CHECKING
67# define logbuf_assert(str) assert_string_equal(logbuf, str)
68#else
69# define logbuf_assert(str)
70#endif
71
72static void
73test_element(void **state)
74{
75 (void) state; /* unused */
76
77 size_t name_len, prefix_len;
Radek Krejci28e8cb52019-03-08 11:31:31 +010078 size_t buf_len, len;
Radek Krejcid91dbaf2018-09-21 15:51:39 +020079 const char *name, *prefix;
Radek Krejci28e8cb52019-03-08 11:31:31 +010080 char *buf = NULL, *out = NULL;
Radek Krejcid91dbaf2018-09-21 15:51:39 +020081 const char *str, *p;
Radek Krejci28e8cb52019-03-08 11:31:31 +010082 int dynamic;
Radek Krejcid91dbaf2018-09-21 15:51:39 +020083
84 struct lyxml_context ctx;
85 memset(&ctx, 0, sizeof ctx);
86 ctx.line = 1;
87
88 /* empty */
89 str = "";
Radek Krejci7a7fa902018-09-25 17:08:21 +020090 assert_int_equal(LY_SUCCESS, lyxml_get_element(&ctx, &str, &prefix, &prefix_len, &name, &name_len));
Radek Krejcid91dbaf2018-09-21 15:51:39 +020091 assert_null(name);
Radek Krejcib1890642018-10-03 14:05:40 +020092 assert_int_equal(LYXML_END, ctx.status);
Radek Krejcid91dbaf2018-09-21 15:51:39 +020093 assert_true(str[0] == '\0');
Radek Krejcif2c721d2019-06-03 16:37:58 +020094 ctx.status = 0;
Radek Krejcid91dbaf2018-09-21 15:51:39 +020095
Radek Krejcib1890642018-10-03 14:05:40 +020096 /* end element */
97 str = "</element>";
98 assert_int_equal(LY_EVALID, lyxml_get_element(&ctx, &str, &prefix, &prefix_len, &name, &name_len));
Radek Krejci3fbc9872019-04-16 16:50:01 +020099 logbuf_assert("Opening and closing elements tag missmatch (\"element\"). Line number 1.");
Radek Krejcib1890642018-10-03 14:05:40 +0200100
Radek Krejcid91dbaf2018-09-21 15:51:39 +0200101 /* no element */
102 logbuf_clean();
103 str = p = "no data present";
Radek Krejci7a7fa902018-09-25 17:08:21 +0200104 assert_int_equal(LY_EINVAL, lyxml_get_element(&ctx, &str, &prefix, &prefix_len, &name, &name_len));
Radek Krejcid91dbaf2018-09-21 15:51:39 +0200105 assert_null(name);
106 assert_ptr_equal(p, str); /* input data not eaten */
107 logbuf_assert("");
108
109 /* not supported DOCTYPE */
110 str = p = "<!DOCTYPE greeting SYSTEM \"hello.dtd\"><greeting/>";
Radek Krejci7a7fa902018-09-25 17:08:21 +0200111 assert_int_equal(LY_EVALID, lyxml_get_element(&ctx, &str, &prefix, &prefix_len, &name, &name_len));
Radek Krejcid91dbaf2018-09-21 15:51:39 +0200112 assert_null(name);
113 assert_ptr_equal(p, str); /* input data not eaten */
114 logbuf_assert("Document Type Declaration not supported. Line number 1.");
115
Radek Krejcic5c31bb2019-04-08 14:40:52 +0200116 /* invalid XML */
117 str = p = "<!NONSENCE/>";
118 assert_int_equal(LY_EVALID, lyxml_get_element(&ctx, &str, &prefix, &prefix_len, &name, &name_len));
119 assert_null(name);
120 assert_ptr_equal(p, str); /* input data not eaten */
121 logbuf_assert("Unknown XML section \"<!NONSENCE/>\". Line number 1.");
122
Radek Krejcid91dbaf2018-09-21 15:51:39 +0200123 /* unqualified element */
124 str = " < element/>";
Radek Krejci7a7fa902018-09-25 17:08:21 +0200125 assert_int_equal(LY_SUCCESS, lyxml_get_element(&ctx, &str, &prefix, &prefix_len, &name, &name_len));
Radek Krejcid91dbaf2018-09-21 15:51:39 +0200126 assert_null(prefix);
127 assert_false(strncmp("element", name, name_len));
128 assert_int_equal(7, name_len);
Radek Krejcifad79c92019-06-04 11:43:30 +0200129 assert_int_equal(LYXML_END, ctx.status);
Radek Krejcib1890642018-10-03 14:05:40 +0200130 assert_string_equal("", str);
Radek Krejci28e8cb52019-03-08 11:31:31 +0100131 assert_int_equal(0, ctx.elements.count);
Radek Krejcifad79c92019-06-04 11:43:30 +0200132 lyxml_context_clear(&ctx);
Radek Krejci28e8cb52019-03-08 11:31:31 +0100133
134 str = " < element attr=\'x\'/>";
135 assert_int_equal(LY_SUCCESS, lyxml_get_element(&ctx, &str, &prefix, &prefix_len, &name, &name_len));
136 assert_int_equal(LYXML_ATTRIBUTE, ctx.status);
137 assert_string_equal("attr=\'x\'/>", str);
138 assert_int_equal(1, ctx.elements.count);
139 assert_int_equal(LY_SUCCESS, lyxml_get_attribute(&ctx, &str, &prefix, &prefix_len, &name, &name_len));
140 assert_int_equal(LYXML_ATTR_CONTENT, ctx.status);
141 assert_string_equal("\'x\'/>", str);
142 assert_int_equal(1, ctx.elements.count);
143 assert_int_equal(LY_SUCCESS, lyxml_get_string(&ctx, &str, &buf, &buf_len, &out, &len, &dynamic));
Radek Krejcifad79c92019-06-04 11:43:30 +0200144 assert_int_equal(LYXML_END, ctx.status);
Radek Krejci28e8cb52019-03-08 11:31:31 +0100145 assert_string_equal("", str);
146 assert_int_equal(0, ctx.elements.count);
Radek Krejcifad79c92019-06-04 11:43:30 +0200147 lyxml_context_clear(&ctx);
Radek Krejcid91dbaf2018-09-21 15:51:39 +0200148
Radek Krejcifb7c6582018-09-21 16:12:45 +0200149 str = "<?xml version=\"1.0\"?> <!-- comment --> <![CDATA[<greeting>Hello, world!</greeting>]]> <?TEST xxx?> <element/>";
Radek Krejci7a7fa902018-09-25 17:08:21 +0200150 assert_int_equal(LY_SUCCESS, lyxml_get_element(&ctx, &str, &prefix, &prefix_len, &name, &name_len));
Radek Krejcid91dbaf2018-09-21 15:51:39 +0200151 assert_null(prefix);
152 assert_false(strncmp("element", name, name_len));
153 assert_int_equal(7, name_len);
Radek Krejcifad79c92019-06-04 11:43:30 +0200154 assert_int_equal(LYXML_END, ctx.status);
Radek Krejcib1890642018-10-03 14:05:40 +0200155 assert_string_equal("", str);
Radek Krejcifad79c92019-06-04 11:43:30 +0200156 lyxml_context_clear(&ctx);
Radek Krejcid91dbaf2018-09-21 15:51:39 +0200157
158 str = "<element xmlns=\"urn\"></element>";
Radek Krejci7a7fa902018-09-25 17:08:21 +0200159 assert_int_equal(LY_SUCCESS, lyxml_get_element(&ctx, &str, &prefix, &prefix_len, &name, &name_len));
Radek Krejcid91dbaf2018-09-21 15:51:39 +0200160 assert_null(prefix);
161 assert_false(strncmp("element", name, name_len));
162 assert_int_equal(7, name_len);
Radek Krejcib1890642018-10-03 14:05:40 +0200163 assert_int_equal(LYXML_ATTRIBUTE, ctx.status);
164 assert_string_equal("xmlns=\"urn\"></element>", str);
165 /* cleean context by getting closing tag */
166 str += 12;
167 assert_int_equal(LY_SUCCESS, lyxml_get_element(&ctx, &str, &prefix, &prefix_len, &name, &name_len));
Radek Krejcifad79c92019-06-04 11:43:30 +0200168 lyxml_context_clear(&ctx);
Radek Krejcid91dbaf2018-09-21 15:51:39 +0200169
170 /* qualified element */
171 str = " < yin:element/>";
Radek Krejci7a7fa902018-09-25 17:08:21 +0200172 assert_int_equal(LY_SUCCESS, lyxml_get_element(&ctx, &str, &prefix, &prefix_len, &name, &name_len));
Radek Krejcid91dbaf2018-09-21 15:51:39 +0200173 assert_false(strncmp("yin", prefix, prefix_len));
174 assert_false(strncmp("element", name, name_len));
175 assert_int_equal(3, prefix_len);
176 assert_int_equal(7, name_len);
Radek Krejcifad79c92019-06-04 11:43:30 +0200177 assert_int_equal(LYXML_END, ctx.status);
Radek Krejcib1890642018-10-03 14:05:40 +0200178 assert_string_equal("", str);
Radek Krejcifad79c92019-06-04 11:43:30 +0200179 lyxml_context_clear(&ctx);
Radek Krejcid91dbaf2018-09-21 15:51:39 +0200180
181 str = "<yin:element xmlns=\"urn\"></element>";
Radek Krejci7a7fa902018-09-25 17:08:21 +0200182 assert_int_equal(LY_SUCCESS, lyxml_get_element(&ctx, &str, &prefix, &prefix_len, &name, &name_len));
Radek Krejcid91dbaf2018-09-21 15:51:39 +0200183 assert_false(strncmp("yin", prefix, prefix_len));
184 assert_false(strncmp("element", name, name_len));
185 assert_int_equal(3, prefix_len);
186 assert_int_equal(7, name_len);
Radek Krejcib1890642018-10-03 14:05:40 +0200187 assert_int_equal(LYXML_ATTRIBUTE, ctx.status);
188 assert_string_equal("xmlns=\"urn\"></element>", str);
189 /* cleean context by getting closing tag */
190 str += 12;
191 assert_int_equal(LY_EVALID, lyxml_get_element(&ctx, &str, &prefix, &prefix_len, &name, &name_len));
Radek Krejci3fbc9872019-04-16 16:50:01 +0200192 logbuf_assert("Opening and closing elements tag missmatch (\"element\"). Line number 1.");
Radek Krejcia93621b2018-10-18 11:13:38 +0200193 str = "</yin:element/>";
194 assert_int_equal(LY_EVALID, lyxml_get_element(&ctx, &str, &prefix, &prefix_len, &name, &name_len));
195 logbuf_assert("Unexpected data \"/>\" in closing element tag. Line number 1.");
Radek Krejcib1890642018-10-03 14:05:40 +0200196 lyxml_context_clear(&ctx);
Radek Krejcid91dbaf2018-09-21 15:51:39 +0200197
198 /* UTF8 characters */
199 str = "<𠜎€𠜎Øn:𠜎€𠜎Øn/>";
Radek Krejci7a7fa902018-09-25 17:08:21 +0200200 assert_int_equal(LY_SUCCESS, lyxml_get_element(&ctx, &str, &prefix, &prefix_len, &name, &name_len));
Radek Krejcid91dbaf2018-09-21 15:51:39 +0200201 assert_false(strncmp("𠜎€𠜎Øn", prefix, prefix_len));
202 assert_false(strncmp("𠜎€𠜎Øn", name, name_len));
203 assert_int_equal(14, prefix_len);
204 assert_int_equal(14, name_len);
Radek Krejcifad79c92019-06-04 11:43:30 +0200205 assert_int_equal(LYXML_END, ctx.status);
Radek Krejcib1890642018-10-03 14:05:40 +0200206 assert_string_equal("", str);
Radek Krejcifad79c92019-06-04 11:43:30 +0200207 lyxml_context_clear(&ctx);
Radek Krejcid91dbaf2018-09-21 15:51:39 +0200208
209 /* invalid UTF-8 character */
210 str = "<¢:element>";
Radek Krejci7a7fa902018-09-25 17:08:21 +0200211 assert_int_equal(LY_EVALID, lyxml_get_element(&ctx, &str, &prefix, &prefix_len, &name, &name_len));
Radek Krejcid91dbaf2018-09-21 15:51:39 +0200212 logbuf_assert("Identifier \"¢:element>\" starts with invalid character. Line number 1.");
213 str = "<yin:c⁐element>";
Radek Krejci7a7fa902018-09-25 17:08:21 +0200214 assert_int_equal(LY_EVALID, lyxml_get_element(&ctx, &str, &prefix, &prefix_len, &name, &name_len));
Radek Krejcid972c252018-09-25 13:23:39 +0200215 logbuf_assert("Invalid character sequence \"⁐element>\", expected whitespace or element tag termination ('>' or '/>'. Line number 1.");
Radek Krejcifad79c92019-06-04 11:43:30 +0200216 lyxml_context_clear(&ctx);
Radek Krejci339e2de2019-05-17 14:28:24 +0200217
218 /* mixed content */
219 str = "<a>text <b>x</b></a>";
220 assert_int_equal(LY_SUCCESS, lyxml_get_element(&ctx, &str, &prefix, &prefix_len, &name, &name_len));
221 assert_string_equal("text <b>x</b></a>", str);
222 assert_int_equal(LYXML_ELEM_CONTENT, ctx.status);
223 assert_int_equal(LY_EVALID, lyxml_get_string(&ctx, &str, &buf, &buf_len, &out, &len, &dynamic));
224 logbuf_assert("Mixed XML content is not allowed (text <b>). Line number 1.");
225 lyxml_context_clear(&ctx);
226
David Sedlák54a6f132019-07-16 15:14:18 +0200227 /* tag missmatch */
228 str = "<a>text</b>";
229 assert_int_equal(LY_SUCCESS, lyxml_get_element(&ctx, &str, &prefix, &prefix_len, &name, &name_len));
230 assert_string_equal("text</b>", str);
231 assert_int_equal(LYXML_ELEM_CONTENT, ctx.status);
232 assert_int_equal(LY_EVALID, lyxml_get_string(&ctx, &str, &buf, &buf_len, &out, &len, &dynamic));
Michal Vasko14654712020-02-06 08:35:21 +0100233 logbuf_assert("Opening and closing elements tag missmatch (\"b\", expected \"a\"). Line number 1.");
David Sedlák54a6f132019-07-16 15:14:18 +0200234 lyxml_context_clear(&ctx);
235
Radek Krejcid972c252018-09-25 13:23:39 +0200236}
237
238static void
239test_attribute(void **state)
240{
241 (void) state; /* unused */
242
243 size_t name_len, prefix_len;
244 const char *name, *prefix;
245 const char *str, *p;
246
247 struct lyxml_context ctx;
248 memset(&ctx, 0, sizeof ctx);
249 ctx.line = 1;
250
251 /* empty - without element tag termination */
252 str = "";
Radek Krejcifad79c92019-06-04 11:43:30 +0200253 assert_int_equal(LY_EVALID, lyxml_get_attribute(&ctx, &str, &prefix, &prefix_len, &name, &name_len));
Radek Krejcid972c252018-09-25 13:23:39 +0200254
Radek Krejcid972c252018-09-25 13:23:39 +0200255 /* not an attribute */
256 str = p = "unknown/>";
Radek Krejci7a7fa902018-09-25 17:08:21 +0200257 assert_int_equal(LY_EVALID, lyxml_get_attribute(&ctx, &str, &prefix, &prefix_len, &name, &name_len));
Radek Krejcid972c252018-09-25 13:23:39 +0200258 assert_ptr_equal(p, str); /* input data not eaten */
259 logbuf_assert("Invalid character sequence \"/>\", expected whitespace or '='. Line number 1.");
260 str = p = "unknown />";
Radek Krejci7a7fa902018-09-25 17:08:21 +0200261 assert_int_equal(LY_EVALID, lyxml_get_attribute(&ctx, &str, &prefix, &prefix_len, &name, &name_len));
Radek Krejcid972c252018-09-25 13:23:39 +0200262 assert_ptr_equal(p, str); /* input data not eaten */
263 logbuf_assert("Invalid character sequence \"/>\", expected '='. Line number 1.");
264 str = p = "xxx=/>";
Radek Krejci7a7fa902018-09-25 17:08:21 +0200265 assert_int_equal(LY_EVALID, lyxml_get_attribute(&ctx, &str, &prefix, &prefix_len, &name, &name_len));
Radek Krejcid972c252018-09-25 13:23:39 +0200266 assert_ptr_equal(p, str); /* input data not eaten */
267 logbuf_assert("Invalid character sequence \"/>\", expected either single or double quotation mark. Line number 1.");
268 str = p = "xxx\n = yyy/>";
Radek Krejci7a7fa902018-09-25 17:08:21 +0200269 assert_int_equal(LY_EVALID, lyxml_get_attribute(&ctx, &str, &prefix, &prefix_len, &name, &name_len));
Radek Krejcid972c252018-09-25 13:23:39 +0200270 assert_ptr_equal(p, str); /* input data not eaten */
271 logbuf_assert("Invalid character sequence \"yyy/>\", expected either single or double quotation mark. Line number 2.");
272
273 /* valid attribute */
274 str = "xmlns=\"urn\">";
Radek Krejci7a7fa902018-09-25 17:08:21 +0200275 assert_int_equal(LY_SUCCESS, lyxml_get_attribute(&ctx, &str, &prefix, &prefix_len, &name, &name_len));
Radek Krejci49165732019-05-15 16:41:58 +0200276 assert_null(name);
Radek Krejcid972c252018-09-25 13:23:39 +0200277 assert_null(prefix);
Radek Krejci49165732019-05-15 16:41:58 +0200278 assert_int_equal(0, name_len);
Radek Krejcid972c252018-09-25 13:23:39 +0200279 assert_int_equal(0, prefix_len);
Radek Krejci49165732019-05-15 16:41:58 +0200280 assert_int_equal(1, ctx.ns.count);
281 assert_string_equal("", str);
282 assert_int_equal(LYXML_ELEM_CONTENT, ctx.status);
Radek Krejcid972c252018-09-25 13:23:39 +0200283
Radek Krejci49165732019-05-15 16:41:58 +0200284 str = "xmlns:nc\n = \'urn\'>";
Radek Krejci7a7fa902018-09-25 17:08:21 +0200285 assert_int_equal(LY_SUCCESS, lyxml_get_attribute(&ctx, &str, &prefix, &prefix_len, &name, &name_len));
Radek Krejci49165732019-05-15 16:41:58 +0200286 assert_null(name);
287 assert_null(prefix);
288 assert_int_equal(0, name_len);
289 assert_int_equal(0, prefix_len);
Radek Krejcid972c252018-09-25 13:23:39 +0200290 assert_int_equal(3, ctx.line);
Radek Krejci49165732019-05-15 16:41:58 +0200291 assert_int_equal(2, ctx.ns.count);
292 assert_string_equal("", str);
293 assert_int_equal(LYXML_ELEM_CONTENT, ctx.status);
Radek Krejci28e8cb52019-03-08 11:31:31 +0100294
Radek Krejci49165732019-05-15 16:41:58 +0200295 lyxml_context_clear(&ctx);
Radek Krejcid91dbaf2018-09-21 15:51:39 +0200296}
297
Radek Krejci7a7fa902018-09-25 17:08:21 +0200298static void
299test_text(void **state)
300{
301 (void) state; /* unused */
302
Radek Krejcid70d1072018-10-09 14:20:47 +0200303 size_t buf_len, len;
304 int dynamic;
Radek Krejci7a7fa902018-09-25 17:08:21 +0200305 const char *str, *p;
Radek Krejcid70d1072018-10-09 14:20:47 +0200306 char *buf = NULL, *out = NULL;
Radek Krejci339e2de2019-05-17 14:28:24 +0200307 const char *prefix, *name;
308 size_t prefix_len, name_len;
Radek Krejci7a7fa902018-09-25 17:08:21 +0200309
310 struct lyxml_context ctx;
311 memset(&ctx, 0, sizeof ctx);
312 ctx.line = 1;
313
314 /* empty attribute value */
Radek Krejcib1890642018-10-03 14:05:40 +0200315 ctx.status = LYXML_ATTR_CONTENT;
Radek Krejci7a7fa902018-09-25 17:08:21 +0200316 str = "\"\"";
Radek Krejcid70d1072018-10-09 14:20:47 +0200317 assert_int_equal(LY_SUCCESS, lyxml_get_string(&ctx, &str, &buf, &buf_len, &out, &len, &dynamic));
318 assert_null(buf);
319 assert_ptr_equal(&str[-1], out);
320 assert_int_equal(0, dynamic);
321 assert_int_equal(0, len);
Radek Krejci7a7fa902018-09-25 17:08:21 +0200322 assert_true(str[0] == '\0'); /* everything eaten */
Radek Krejcib1890642018-10-03 14:05:40 +0200323 assert_int_equal(LYXML_ATTRIBUTE, ctx.status);
324
325 ctx.status = LYXML_ATTR_CONTENT;
Radek Krejci7a7fa902018-09-25 17:08:21 +0200326 str = "\'\'";
Radek Krejcid70d1072018-10-09 14:20:47 +0200327 assert_int_equal(LY_SUCCESS, lyxml_get_string(&ctx, &str, &buf, &buf_len, &out, &len, &dynamic));
328 assert_null(buf);
329 assert_ptr_equal(&str[-1], out);
330 assert_int_equal(0, dynamic);
331 assert_int_equal(0, len);
Radek Krejci7a7fa902018-09-25 17:08:21 +0200332 assert_true(str[0] == '\0'); /* everything eaten */
Radek Krejcib1890642018-10-03 14:05:40 +0200333 assert_int_equal(LYXML_ATTRIBUTE, ctx.status);
Radek Krejci7a7fa902018-09-25 17:08:21 +0200334
Radek Krejcied6c6ad2018-09-26 09:10:18 +0200335 /* empty element content - only formating before defining child */
Radek Krejcib1890642018-10-03 14:05:40 +0200336 ctx.status = LYXML_ELEM_CONTENT;
Radek Krejci339e2de2019-05-17 14:28:24 +0200337 str = "<x>\n <y>";
338 assert_int_equal(LY_SUCCESS, lyxml_get_element(&ctx, &str, &prefix, &prefix_len, &name, &name_len));
Radek Krejcid70d1072018-10-09 14:20:47 +0200339 assert_int_equal(LY_EINVAL, lyxml_get_string(&ctx, &str, &buf, &buf_len, &out, &len, &dynamic));
340 assert_null(buf);
Radek Krejci339e2de2019-05-17 14:28:24 +0200341 assert_string_equal("<y>", str);
342 lyxml_context_clear(&ctx);
Radek Krejcied6c6ad2018-09-26 09:10:18 +0200343
Radek Krejci7a7fa902018-09-25 17:08:21 +0200344 /* empty element content is invalid - missing content terminating character < */
Radek Krejcib1890642018-10-03 14:05:40 +0200345 ctx.status = LYXML_ELEM_CONTENT;
Radek Krejci7a7fa902018-09-25 17:08:21 +0200346 str = "";
Radek Krejcid70d1072018-10-09 14:20:47 +0200347 assert_int_equal(LY_EVALID, lyxml_get_string(&ctx, &str, &buf, &buf_len, &out, &len, &dynamic));
348 assert_null(buf);
Radek Krejci0a1d0d42019-05-16 15:14:51 +0200349 logbuf_assert("Unexpected end-of-input. Line number 2.");
Radek Krejcied6c6ad2018-09-26 09:10:18 +0200350
Radek Krejcib1890642018-10-03 14:05:40 +0200351 ctx.status = LYXML_ELEM_CONTENT;
Radek Krejci117d2082018-09-26 10:05:14 +0200352 str = p = "xxx";
Radek Krejcid70d1072018-10-09 14:20:47 +0200353 assert_int_equal(LY_EVALID, lyxml_get_string(&ctx, &str, &buf, &buf_len, &out, &len, &dynamic));
354 assert_null(buf);
Radek Krejci0a1d0d42019-05-16 15:14:51 +0200355 logbuf_assert("Unexpected end-of-input. Line number 2.");
Radek Krejcied6c6ad2018-09-26 09:10:18 +0200356 assert_ptr_equal(p, str); /* input data not eaten */
Radek Krejci7a7fa902018-09-25 17:08:21 +0200357
Radek Krejci7a7fa902018-09-25 17:08:21 +0200358 /* valid strings */
Radek Krejcib1890642018-10-03 14:05:40 +0200359 ctx.status = LYXML_ELEM_CONTENT;
Radek Krejci339e2de2019-05-17 14:28:24 +0200360 str = "<a>€𠜎Øn \n&lt;&amp;&quot;&apos;&gt; &#82;&#x4f;&#x4B;</a>";
361 assert_int_equal(LY_SUCCESS, lyxml_get_element(&ctx, &str, &prefix, &prefix_len, &name, &name_len));
Radek Krejcid70d1072018-10-09 14:20:47 +0200362 assert_int_equal(LY_SUCCESS, lyxml_get_string(&ctx, &str, &buf, &buf_len, &out, &len, &dynamic));
363 assert_int_not_equal(0, dynamic);
364 assert_non_null(buf);
365 assert_ptr_equal(out, buf);
366 assert_int_equal(22, buf_len);
367 assert_int_equal(21, len);
368 assert_string_equal("€𠜎Øn \n<&\"\'> ROK", buf);
Radek Krejcif2c721d2019-06-03 16:37:58 +0200369 assert_string_equal("</a>", str);
Radek Krejcib1890642018-10-03 14:05:40 +0200370 assert_int_equal(LYXML_ELEMENT, ctx.status);
Radek Krejci339e2de2019-05-17 14:28:24 +0200371 lyxml_context_clear(&ctx);
Radek Krejci7a7fa902018-09-25 17:08:21 +0200372
Radek Krejci117d2082018-09-26 10:05:14 +0200373 /* test using n-bytes UTF8 hexadecimal code points */
Radek Krejcib1890642018-10-03 14:05:40 +0200374 ctx.status = LYXML_ATTR_CONTENT;
Radek Krejci117d2082018-09-26 10:05:14 +0200375 str = "\'&#x0024;&#x00A2;&#x20ac;&#x10348;\'";
Radek Krejcid70d1072018-10-09 14:20:47 +0200376 assert_int_equal(LY_SUCCESS, lyxml_get_string(&ctx, &str, &buf, &buf_len, &out, &len, &dynamic));
377 assert_int_not_equal(0, dynamic);
378 assert_non_null(buf);
379 assert_ptr_equal(out, buf);
Radek Krejcid5f2b5f2018-10-11 10:54:36 +0200380 assert_int_equal(22, buf_len);
Radek Krejcid70d1072018-10-09 14:20:47 +0200381 assert_int_equal(10, len);
382 assert_string_equal("$¢€𐍈", buf);
Radek Krejcib1890642018-10-03 14:05:40 +0200383 assert_int_equal(LYXML_ATTRIBUTE, ctx.status);
Radek Krejci117d2082018-09-26 10:05:14 +0200384
Radek Krejcid70d1072018-10-09 14:20:47 +0200385 free(buf);
386 buf = NULL;
387
Radek Krejci7a7fa902018-09-25 17:08:21 +0200388 /* invalid characters in string */
Radek Krejcib1890642018-10-03 14:05:40 +0200389 ctx.status = LYXML_ATTR_CONTENT;
Radek Krejci7a7fa902018-09-25 17:08:21 +0200390 str = p = "\'&#x52\'";
Radek Krejcid70d1072018-10-09 14:20:47 +0200391 assert_int_equal(LY_EVALID, lyxml_get_string(&ctx, &str, &buf, &buf_len, &out, &len, &dynamic));
Radek Krejci117d2082018-09-26 10:05:14 +0200392 logbuf_assert("Invalid character sequence \"'\", expected ;. Line number 3.");
Radek Krejcid70d1072018-10-09 14:20:47 +0200393 assert_null(buf);
Radek Krejci7a7fa902018-09-25 17:08:21 +0200394 assert_ptr_equal(p, str); /* input data not eaten */
Radek Krejcib1890642018-10-03 14:05:40 +0200395 ctx.status = LYXML_ATTR_CONTENT;
Radek Krejci7a7fa902018-09-25 17:08:21 +0200396 str = p = "\"&#82\"";
Radek Krejcid70d1072018-10-09 14:20:47 +0200397 assert_int_equal(LY_EVALID, lyxml_get_string(&ctx, &str, &buf, &buf_len, &out, &len, &dynamic));
Radek Krejci117d2082018-09-26 10:05:14 +0200398 logbuf_assert("Invalid character sequence \"\"\", expected ;. Line number 3.");
Radek Krejcid70d1072018-10-09 14:20:47 +0200399 assert_null(buf);
Radek Krejci7a7fa902018-09-25 17:08:21 +0200400 assert_ptr_equal(p, str); /* input data not eaten */
Radek Krejcib1890642018-10-03 14:05:40 +0200401 ctx.status = LYXML_ATTR_CONTENT;
Radek Krejcied6c6ad2018-09-26 09:10:18 +0200402 str = p = "\"&nonsence;\"";
Radek Krejcid70d1072018-10-09 14:20:47 +0200403 assert_int_equal(LY_EVALID, lyxml_get_string(&ctx, &str, &buf, &buf_len, &out, &len, &dynamic));
Radek Krejci117d2082018-09-26 10:05:14 +0200404 logbuf_assert("Entity reference \"&nonsence;\" not supported, only predefined references allowed. Line number 3.");
Radek Krejcid70d1072018-10-09 14:20:47 +0200405 assert_null(buf);
Radek Krejcied6c6ad2018-09-26 09:10:18 +0200406 assert_ptr_equal(p, str); /* input data not eaten */
Radek Krejcib1890642018-10-03 14:05:40 +0200407 ctx.status = LYXML_ELEM_CONTENT;
Radek Krejcied6c6ad2018-09-26 09:10:18 +0200408 str = p = "&#o122;";
Radek Krejcid70d1072018-10-09 14:20:47 +0200409 assert_int_equal(LY_EVALID, lyxml_get_string(&ctx, &str, &buf, &buf_len, &out, &len, &dynamic));
Radek Krejci117d2082018-09-26 10:05:14 +0200410 logbuf_assert("Invalid character reference \"&#o122;\". Line number 3.");
Radek Krejcid70d1072018-10-09 14:20:47 +0200411 assert_null(buf);
Radek Krejci117d2082018-09-26 10:05:14 +0200412 assert_ptr_equal(p, str); /* input data not eaten */
413
Radek Krejcib1890642018-10-03 14:05:40 +0200414 ctx.status = LYXML_ATTR_CONTENT;
Radek Krejci117d2082018-09-26 10:05:14 +0200415 str = p = "\'&#x06;\'";
Radek Krejcid70d1072018-10-09 14:20:47 +0200416 assert_int_equal(LY_EVALID, lyxml_get_string(&ctx, &str, &buf, &buf_len, &out, &len, &dynamic));
Radek Krejci117d2082018-09-26 10:05:14 +0200417 logbuf_assert("Invalid character reference \"&#x06;\'\" (0x00000006). Line number 3.");
Radek Krejcid70d1072018-10-09 14:20:47 +0200418 assert_null(buf);
Radek Krejci117d2082018-09-26 10:05:14 +0200419 assert_ptr_equal(p, str); /* input data not eaten */
Radek Krejcib1890642018-10-03 14:05:40 +0200420 ctx.status = LYXML_ATTR_CONTENT;
Radek Krejci117d2082018-09-26 10:05:14 +0200421 str = p = "\'&#xfdd0;\'";
Radek Krejcid70d1072018-10-09 14:20:47 +0200422 assert_int_equal(LY_EVALID, lyxml_get_string(&ctx, &str, &buf, &buf_len, &out, &len, &dynamic));
Radek Krejci117d2082018-09-26 10:05:14 +0200423 logbuf_assert("Invalid character reference \"&#xfdd0;\'\" (0x0000fdd0). Line number 3.");
Radek Krejcid70d1072018-10-09 14:20:47 +0200424 assert_null(buf);
Radek Krejci117d2082018-09-26 10:05:14 +0200425 assert_ptr_equal(p, str); /* input data not eaten */
Radek Krejcib1890642018-10-03 14:05:40 +0200426 ctx.status = LYXML_ATTR_CONTENT;
Radek Krejci117d2082018-09-26 10:05:14 +0200427 str = p = "\'&#xffff;\'";
Radek Krejcid70d1072018-10-09 14:20:47 +0200428 assert_int_equal(LY_EVALID, lyxml_get_string(&ctx, &str, &buf, &buf_len, &out, &len, &dynamic));
Radek Krejci117d2082018-09-26 10:05:14 +0200429 logbuf_assert("Invalid character reference \"&#xffff;\'\" (0x0000ffff). Line number 3.");
Radek Krejcid70d1072018-10-09 14:20:47 +0200430 assert_null(buf);
Radek Krejcied6c6ad2018-09-26 09:10:18 +0200431 assert_ptr_equal(p, str); /* input data not eaten */
Radek Krejci7a7fa902018-09-25 17:08:21 +0200432}
433
Radek Krejci4b74d5e2018-09-26 14:30:55 +0200434static void
435test_ns(void **state)
436{
437 (void) state; /* unused */
438
Radek Krejci4b74d5e2018-09-26 14:30:55 +0200439 const struct lyxml_ns *ns;
440
441 struct lyxml_context ctx;
442 memset(&ctx, 0, sizeof ctx);
443 ctx.line = 1;
444
Radek Krejcie0734d22019-04-05 15:54:28 +0200445 /* simulate adding open element1 into context */
446 ctx.elements.count++;
447 /* processing namespace definitions */
Radek Krejci17a78d82019-05-15 15:49:55 +0200448 assert_int_equal(LY_SUCCESS, lyxml_ns_add(&ctx, NULL, 0, strdup("urn:default")));
449 assert_int_equal(LY_SUCCESS, lyxml_ns_add(&ctx, "nc", 2, strdup("urn:nc1")));
Radek Krejcie0734d22019-04-05 15:54:28 +0200450 /* simulate adding open element2 into context */
451 ctx.elements.count++;
452 /* processing namespace definitions */
Radek Krejci17a78d82019-05-15 15:49:55 +0200453 assert_int_equal(LY_SUCCESS, lyxml_ns_add(&ctx, "nc", 2, strdup("urn:nc2")));
Radek Krejcie0734d22019-04-05 15:54:28 +0200454 assert_int_equal(3, ctx.ns.count);
455 assert_int_not_equal(0, ctx.ns.size);
Radek Krejci4b74d5e2018-09-26 14:30:55 +0200456
457 ns = lyxml_ns_get(&ctx, NULL, 0);
458 assert_non_null(ns);
459 assert_null(ns->prefix);
460 assert_string_equal("urn:default", ns->uri);
461
462 ns = lyxml_ns_get(&ctx, "nc", 2);
463 assert_non_null(ns);
464 assert_string_equal("nc", ns->prefix);
465 assert_string_equal("urn:nc2", ns->uri);
466
Radek Krejcie0734d22019-04-05 15:54:28 +0200467 /* simulate closing element2 */
468 ctx.elements.count--;
Radek Krejci17dca992019-05-17 10:53:27 +0200469 lyxml_ns_rm(&ctx);
Radek Krejcie0734d22019-04-05 15:54:28 +0200470 assert_int_equal(2, ctx.ns.count);
Radek Krejci4b74d5e2018-09-26 14:30:55 +0200471
472 ns = lyxml_ns_get(&ctx, "nc", 2);
473 assert_non_null(ns);
474 assert_string_equal("nc", ns->prefix);
475 assert_string_equal("urn:nc1", ns->uri);
476
Radek Krejcie0734d22019-04-05 15:54:28 +0200477 /* simulate closing element1 */
478 ctx.elements.count--;
Radek Krejci17dca992019-05-17 10:53:27 +0200479 lyxml_ns_rm(&ctx);
Radek Krejcie0734d22019-04-05 15:54:28 +0200480 assert_int_equal(0, ctx.ns.count);
Radek Krejci4b74d5e2018-09-26 14:30:55 +0200481
482 assert_null(lyxml_ns_get(&ctx, "nc", 2));
483 assert_null(lyxml_ns_get(&ctx, NULL, 0));
484}
485
David Sedlákb3bed7a2019-03-08 11:53:37 +0100486static void
Radek Krejcie0734d22019-04-05 15:54:28 +0200487test_ns2(void **state)
488{
489 (void) state; /* unused */
490
Radek Krejcie0734d22019-04-05 15:54:28 +0200491 struct lyxml_context ctx;
492 memset(&ctx, 0, sizeof ctx);
493 ctx.line = 1;
494
Radek Krejcie0734d22019-04-05 15:54:28 +0200495 /* simulate adding open element1 into context */
496 ctx.elements.count++;
497 /* default namespace defined in parent element1 */
Radek Krejci17a78d82019-05-15 15:49:55 +0200498 assert_int_equal(LY_SUCCESS, lyxml_ns_add(&ctx, NULL, 0, strdup("urn:default")));
Radek Krejcie0734d22019-04-05 15:54:28 +0200499 assert_int_equal(1, ctx.ns.count);
500 /* going into child element1 */
Radek Krejcie0734d22019-04-05 15:54:28 +0200501 /* simulate adding open element1 into context */
502 ctx.elements.count++;
503 /* no namespace defined, going out (first, simulate closing of so far open element) */
504 ctx.elements.count--;
Radek Krejci17dca992019-05-17 10:53:27 +0200505 lyxml_ns_rm(&ctx);
Radek Krejcie0734d22019-04-05 15:54:28 +0200506 assert_int_equal(1, ctx.ns.count);
507 /* nothing else, going out of the parent element1 (first, simulate closing of so far open element) */
508 ctx.elements.count--;
Radek Krejci17dca992019-05-17 10:53:27 +0200509 lyxml_ns_rm(&ctx);
Radek Krejcie0734d22019-04-05 15:54:28 +0200510 assert_int_equal(0, ctx.ns.count);
511}
512
Radek Krejcifad79c92019-06-04 11:43:30 +0200513static void
514test_simple_xml(void **state)
515{
516 (void)state; /* unused */
517 size_t name_len, prefix_len;
518 const char *prefix, *name;
Radek Krejcifad79c92019-06-04 11:43:30 +0200519 struct lyxml_context ctx;
520
521 char *buf = NULL, *output = NULL;
522 size_t buf_size, length;
523 int dynamic;
Radek Krejcie553e6d2019-06-07 15:33:18 +0200524 const char *test_input = "<elem1 attr1=\"value\"> <elem2 attr2=\"value\" /> </elem1>";
Radek Krejcifad79c92019-06-04 11:43:30 +0200525
526 memset(&ctx, 0, sizeof ctx);
527 ctx.line = 1;
Radek Krejcifad79c92019-06-04 11:43:30 +0200528
Radek Krejcie553e6d2019-06-07 15:33:18 +0200529 assert_int_equal(LY_SUCCESS, lyxml_get_element(&ctx, &test_input, &prefix, &prefix_len, &name, &name_len));
Radek Krejcifad79c92019-06-04 11:43:30 +0200530 assert_int_equal(ctx.status, LYXML_ATTRIBUTE);
Radek Krejcie553e6d2019-06-07 15:33:18 +0200531 assert_string_equal(test_input, "attr1=\"value\"> <elem2 attr2=\"value\" /> </elem1>");
Radek Krejcifad79c92019-06-04 11:43:30 +0200532
Radek Krejcie553e6d2019-06-07 15:33:18 +0200533 assert_int_equal(LY_SUCCESS, lyxml_get_attribute(&ctx, &test_input, &prefix, &prefix_len, &name, &name_len));
Radek Krejcifad79c92019-06-04 11:43:30 +0200534 assert_int_equal(ctx.status, LYXML_ATTR_CONTENT);
Radek Krejcie553e6d2019-06-07 15:33:18 +0200535 assert_string_equal(test_input, "\"value\"> <elem2 attr2=\"value\" /> </elem1>");
Radek Krejcifad79c92019-06-04 11:43:30 +0200536
Radek Krejcie553e6d2019-06-07 15:33:18 +0200537 assert_int_equal(LY_SUCCESS, lyxml_get_string(&ctx, &test_input, &buf, &buf_size, &output, &length, &dynamic));
Radek Krejcifad79c92019-06-04 11:43:30 +0200538 assert_int_equal(ctx.status, LYXML_ELEM_CONTENT);
Radek Krejcie553e6d2019-06-07 15:33:18 +0200539 assert_string_equal(test_input, " <elem2 attr2=\"value\" /> </elem1>");
Radek Krejcifad79c92019-06-04 11:43:30 +0200540
Radek Krejcie553e6d2019-06-07 15:33:18 +0200541 /* try to get string content of elem1 whitespace is removed and EINVAL is expected in this case as well as moving status from element
542 * content to the element */
543 assert_int_equal(LY_EINVAL, lyxml_get_string(&ctx, &test_input, &buf, &buf_size, &output, &length, &dynamic));
Radek Krejcifad79c92019-06-04 11:43:30 +0200544 assert_int_equal(ctx.status, LYXML_ELEMENT);
Radek Krejcie553e6d2019-06-07 15:33:18 +0200545 assert_string_equal(test_input, "<elem2 attr2=\"value\" /> </elem1>");
Radek Krejcifad79c92019-06-04 11:43:30 +0200546
Radek Krejcie553e6d2019-06-07 15:33:18 +0200547 assert_int_equal(LY_SUCCESS, lyxml_get_element(&ctx, &test_input, &prefix, &prefix_len, &name, &name_len));
548 assert_int_equal(ctx.status, LYXML_ATTRIBUTE);
549 assert_string_equal(test_input, "attr2=\"value\" /> </elem1>");
550
551 assert_int_equal(LY_SUCCESS, lyxml_get_attribute(&ctx, &test_input, &prefix, &prefix_len, &name, &name_len));
552 assert_int_equal(ctx.status, LYXML_ATTR_CONTENT);
553 assert_string_equal(test_input, "\"value\" /> </elem1>");
554
555 assert_int_equal(LY_SUCCESS, lyxml_get_string(&ctx, &test_input, &buf, &buf_size, &output, &length, &dynamic));
556 assert_int_equal(ctx.status, LYXML_ELEMENT);
557 assert_string_equal(test_input, " </elem1>");
558
559 assert_int_equal(LY_SUCCESS, lyxml_get_element(&ctx, &test_input, &prefix, &prefix_len, &name, &name_len));
Radek Krejcifad79c92019-06-04 11:43:30 +0200560 assert_int_equal(ctx.status, LYXML_END);
Radek Krejcie553e6d2019-06-07 15:33:18 +0200561 assert_string_equal(test_input, "");
Radek Krejcifad79c92019-06-04 11:43:30 +0200562
563 lyxml_context_clear(&ctx);
Radek Krejcifad79c92019-06-04 11:43:30 +0200564}
565
Radek Krejcid91dbaf2018-09-21 15:51:39 +0200566int main(void)
567{
568 const struct CMUnitTest tests[] = {
Radek Krejcid972c252018-09-25 13:23:39 +0200569 cmocka_unit_test_setup(test_element, logger_setup),
570 cmocka_unit_test_setup(test_attribute, logger_setup),
Radek Krejci7a7fa902018-09-25 17:08:21 +0200571 cmocka_unit_test_setup(test_text, logger_setup),
Radek Krejci4b74d5e2018-09-26 14:30:55 +0200572 cmocka_unit_test_setup(test_ns, logger_setup),
Radek Krejcie0734d22019-04-05 15:54:28 +0200573 cmocka_unit_test_setup(test_ns2, logger_setup),
Radek Krejcifad79c92019-06-04 11:43:30 +0200574 cmocka_unit_test_setup(test_simple_xml, logger_setup),
Radek Krejcid91dbaf2018-09-21 15:51:39 +0200575 };
576
577 return cmocka_run_group_tests(tests, NULL, NULL);
578}