blob: 87b847c935d864e9b7ec42c6003c72e908331cb0 [file] [log] [blame]
Radek Krejci80dd33e2018-09-26 15:57:18 +02001/*
2 * @file test_parser_yang.c
3 * @author: Radek Krejci <rkrejci@cesnet.cz>
4 * @brief unit tests for functions from parser_yang.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
15#define _BSD_SOURCE
16#define _DEFAULT_SOURCE
17#include <stdarg.h>
18#include <stddef.h>
19#include <setjmp.h>
20#include <cmocka.h>
21
22#include <stdio.h>
23#include <string.h>
24
25#include "libyang.h"
26#include "../../src/parser_yang.c"
27
28#define BUFSIZE 1024
29char logbuf[BUFSIZE] = {0};
30
31/* set to 0 to printing error messages to stderr instead of checking them in code */
32#define ENABLE_LOGGER_CHECKING 1
33
Radek Krejcid5f2b5f2018-10-11 10:54:36 +020034#if ENABLE_LOGGER_CHECKING
Radek Krejci80dd33e2018-09-26 15:57:18 +020035static void
36logger(LY_LOG_LEVEL level, const char *msg, const char *path)
37{
38 (void) level; /* unused */
39
40 if (path) {
41 snprintf(logbuf, BUFSIZE - 1, "%s %s", msg, path);
42 } else {
43 strncpy(logbuf, msg, BUFSIZE - 1);
44 }
45}
Radek Krejcid5f2b5f2018-10-11 10:54:36 +020046#endif
Radek Krejci80dd33e2018-09-26 15:57:18 +020047
48static int
49logger_setup(void **state)
50{
51 (void) state; /* unused */
52#if ENABLE_LOGGER_CHECKING
53 ly_set_log_clb(logger, 1);
54#endif
55 return 0;
56}
57
58void
59logbuf_clean(void)
60{
61 logbuf[0] = '\0';
62}
63
64#if ENABLE_LOGGER_CHECKING
65# define logbuf_assert(str) assert_string_equal(logbuf, str)
66#else
67# define logbuf_assert(str)
68#endif
69
Radek Krejci44ceedc2018-10-02 15:54:31 +020070static void
71test_helpers(void **state)
72{
73 (void) state; /* unused */
74
75 const char *str;
Radek Krejci404251e2018-10-09 12:06:44 +020076 char *buf, *p;
Radek Krejci44ceedc2018-10-02 15:54:31 +020077 size_t len, size;
78 int prefix;
79 struct ly_parser_ctx ctx;
80 ctx.ctx = NULL;
81 ctx.line = 1;
82
83 /* storing into buffer */
84 str = "abcd";
85 buf = NULL;
86 size = len = 0;
87 assert_int_equal(LY_SUCCESS, buf_add_char(NULL, &str, 2, &buf, &size, &len));
88 assert_int_not_equal(0, size);
89 assert_int_equal(2, len);
90 assert_string_equal("cd", str);
91 assert_false(strncmp("ab", buf, 2));
92 free(buf);
Radek Krejci404251e2018-10-09 12:06:44 +020093 buf = NULL;
94
95 /* invalid first characters */
96 len = 0;
97 str = "2invalid";
98 assert_int_equal(LY_EVALID, buf_store_char(&ctx, &str, Y_IDENTIF_ARG, &p, &len, &buf, &size, 1));
99 str = ".invalid";
100 assert_int_equal(LY_EVALID, buf_store_char(&ctx, &str, Y_IDENTIF_ARG, &p, &len, &buf, &size, 1));
101 str = "-invalid";
102 assert_int_equal(LY_EVALID, buf_store_char(&ctx, &str, Y_IDENTIF_ARG, &p, &len, &buf, &size, 1));
103 /* invalid following characters */
104 len = 3; /* number of characters read before the str content */
105 str = "!";
106 assert_int_equal(LY_EVALID, buf_store_char(&ctx, &str, Y_IDENTIF_ARG, &p, &len, &buf, &size, 1));
107 str = ":";
108 assert_int_equal(LY_EVALID, buf_store_char(&ctx, &str, Y_IDENTIF_ARG, &p, &len, &buf, &size, 1));
109 /* valid colon for prefixed identifiers */
110 len = size = 0;
111 p = NULL;
112 str = "x:id";
113 assert_int_equal(LY_SUCCESS, buf_store_char(&ctx, &str, Y_PREF_IDENTIF_ARG, &p, &len, &buf, &size, 0));
114 assert_int_equal(1, len);
115 assert_null(buf);
116 assert_string_equal(":id", str);
117 assert_int_equal('x', p[len - 1]);
118 assert_int_equal(LY_SUCCESS, buf_store_char(&ctx, &str, Y_PREF_IDENTIF_ARG, &p, &len, &buf, &size, 1));
119 assert_int_equal(2, len);
120 assert_string_equal("id", str);
121 assert_int_equal(':', p[len - 1]);
122 free(buf);
Radek Krejci44ceedc2018-10-02 15:54:31 +0200123
124 /* checking identifiers */
125 assert_int_equal(LY_EVALID, check_identifierchar(&ctx, ':', 0, NULL));
126 logbuf_assert("Invalid identifier character ':'. Line number 1.");
127 assert_int_equal(LY_EVALID, check_identifierchar(&ctx, '#', 1, NULL));
128 logbuf_assert("Invalid identifier first character '#'. Line number 1.");
129
130 assert_int_equal(LY_SUCCESS, check_identifierchar(&ctx, 'a', 1, &prefix));
131 assert_int_equal(0, prefix);
132 assert_int_equal(LY_SUCCESS, check_identifierchar(&ctx, ':', 0, &prefix));
133 assert_int_equal(1, prefix);
134 assert_int_equal(LY_SUCCESS, check_identifierchar(&ctx, 'b', 0, &prefix));
135 assert_int_equal(2, prefix);
136}
Radek Krejci80dd33e2018-09-26 15:57:18 +0200137
138static void
139test_comments(void **state)
140{
141 (void) state; /* unused */
142
Radek Krejci44ceedc2018-10-02 15:54:31 +0200143 struct ly_parser_ctx ctx;
Radek Krejci80dd33e2018-09-26 15:57:18 +0200144 const char *str, *p;
Radek Krejciefd22f62018-09-27 11:47:58 +0200145 char *word, *buf;
146 size_t len;
Radek Krejci80dd33e2018-09-26 15:57:18 +0200147
Radek Krejci44ceedc2018-10-02 15:54:31 +0200148 ctx.ctx = NULL;
149 ctx.line = 1;
150
Radek Krejciefd22f62018-09-27 11:47:58 +0200151 str = " // this is a text of / one * line */ comment\nargument";
Radek Krejcifc62d7e2018-10-11 12:56:42 +0200152 assert_int_equal(LY_SUCCESS, get_argument(&ctx, &str, Y_STR_ARG, &word, &buf, &len));
Radek Krejciefd22f62018-09-27 11:47:58 +0200153 assert_string_equal("argument", word);
154 assert_null(buf);
155 assert_int_equal(8, len);
Radek Krejci80dd33e2018-09-26 15:57:18 +0200156
Radek Krejciefd22f62018-09-27 11:47:58 +0200157 str = "/* this is a \n * text // of / block * comment */\"arg\" + \"ume\" \n + \n \"nt\"";
Radek Krejcifc62d7e2018-10-11 12:56:42 +0200158 assert_int_equal(LY_SUCCESS, get_argument(&ctx, &str, Y_STR_ARG, &word, &buf, &len));
Radek Krejciefd22f62018-09-27 11:47:58 +0200159 assert_string_equal("argument", word);
160 assert_ptr_equal(buf, word);
161 assert_int_equal(8, len);
162 free(word);
Radek Krejci80dd33e2018-09-26 15:57:18 +0200163
164 str = p = " this is one line comment on last line";
Radek Krejci44ceedc2018-10-02 15:54:31 +0200165 assert_int_equal(LY_SUCCESS, skip_comment(&ctx, &str, 1));
Radek Krejci80dd33e2018-09-26 15:57:18 +0200166 assert_true(str[0] == '\0');
167
168 str = p = " this is a not terminated comment x";
Radek Krejci44ceedc2018-10-02 15:54:31 +0200169 assert_int_equal(LY_EVALID, skip_comment(&ctx, &str, 2));
170 logbuf_assert("Unexpected end-of-file, non-terminated comment. Line number 5.");
Radek Krejci80dd33e2018-09-26 15:57:18 +0200171 assert_true(str[0] == '\0');
172}
173
Radek Krejciefd22f62018-09-27 11:47:58 +0200174static void
175test_arg(void **state)
176{
177 (void) state; /* unused */
178
Radek Krejci44ceedc2018-10-02 15:54:31 +0200179 struct ly_parser_ctx ctx;
Radek Krejciefd22f62018-09-27 11:47:58 +0200180 const char *str;
181 char *word, *buf;
182 size_t len;
183
Radek Krejci44ceedc2018-10-02 15:54:31 +0200184 ctx.ctx = NULL;
185 ctx.line = 1;
186
Radek Krejciefd22f62018-09-27 11:47:58 +0200187 /* missing argument */
188 str = ";";
Radek Krejcifc62d7e2018-10-11 12:56:42 +0200189 assert_int_equal(LY_SUCCESS, get_argument(&ctx, &str, Y_MAYBE_STR_ARG, &word, &buf, &len));
Radek Krejciefd22f62018-09-27 11:47:58 +0200190 assert_null(word);
191
Radek Krejcid5f2b5f2018-10-11 10:54:36 +0200192 str = "{";
Radek Krejcifc62d7e2018-10-11 12:56:42 +0200193 assert_int_equal(LY_EVALID, get_argument(&ctx, &str, Y_STR_ARG, &word, &buf, &len));
Radek Krejcid5f2b5f2018-10-11 10:54:36 +0200194 logbuf_assert("Invalid character sequence \"{\", expected an argument. Line number 1.");
195
Radek Krejcifc62d7e2018-10-11 12:56:42 +0200196 /* invalid escape sequence */
197 str = "\"\\s\"";
198 assert_int_equal(LY_EVALID, get_argument(&ctx, &str, Y_STR_ARG, &word, &buf, &len));
Radek Krejcid5f2b5f2018-10-11 10:54:36 +0200199 logbuf_assert("Double-quoted string unknown special character \'\\s\'. Line number 1.");
200 str = "\'\\s\'"; /* valid, since it is not an escape sequence in single quoted string */
Radek Krejcifc62d7e2018-10-11 12:56:42 +0200201 assert_int_equal(LY_SUCCESS, get_argument(&ctx, &str, Y_STR_ARG, &word, &buf, &len));
Radek Krejcid5f2b5f2018-10-11 10:54:36 +0200202 assert_int_equal(2, len);
203 assert_string_equal("\\s\'", word);
204 assert_int_equal('\0', str[0]); /* input has been eaten */
205
Radek Krejcifc62d7e2018-10-11 12:56:42 +0200206 /* invalid character after the argument */
207 str = "hello\"";
208 assert_int_equal(LY_EVALID, get_argument(&ctx, &str, Y_STR_ARG, &word, &buf, &len));
209 logbuf_assert("Invalid character sequence \"\"\", expected unquoted string character, optsep, semicolon or opening brace. Line number 1.");
210 str = "hello}";
211 assert_int_equal(LY_EVALID, get_argument(&ctx, &str, Y_STR_ARG, &word, &buf, &len));
212 logbuf_assert("Invalid character sequence \"}\", expected unquoted string character, optsep, semicolon or opening brace. Line number 1.");
213
214 str = "hello/x\t"; /* slash is not an invalid character */
215 assert_int_equal(LY_SUCCESS, get_argument(&ctx, &str, Y_STR_ARG, &word, &buf, &len));
216 assert_int_equal(7, len);
217 assert_string_equal("hello/x\t", word);
218
Radek Krejcid5f2b5f2018-10-11 10:54:36 +0200219 assert_null(buf);
Radek Krejciefd22f62018-09-27 11:47:58 +0200220
221 /* different quoting */
Radek Krejcifc62d7e2018-10-11 12:56:42 +0200222 str = "hello ";
223 assert_int_equal(LY_SUCCESS, get_argument(&ctx, &str, Y_STR_ARG, &word, &buf, &len));
Radek Krejciefd22f62018-09-27 11:47:58 +0200224 assert_null(buf);
Radek Krejcid5f2b5f2018-10-11 10:54:36 +0200225 assert_int_equal(5, len);
Radek Krejcifc62d7e2018-10-11 12:56:42 +0200226 assert_string_equal("hello ", word);
Radek Krejciefd22f62018-09-27 11:47:58 +0200227
Radek Krejcifc62d7e2018-10-11 12:56:42 +0200228 str = "hello/*comment*/\n";
229 assert_int_equal(LY_SUCCESS, get_argument(&ctx, &str, Y_STR_ARG, &word, &buf, &len));
Radek Krejciefd22f62018-09-27 11:47:58 +0200230 assert_null(buf);
231 assert_int_equal(5, len);
Radek Krejcid5f2b5f2018-10-11 10:54:36 +0200232 assert_false(strncmp("hello", word, len));
233
234
Radek Krejcifc62d7e2018-10-11 12:56:42 +0200235 str = "\"hello\\n\\t\\\"\\\\\";";
236 assert_int_equal(LY_SUCCESS, get_argument(&ctx, &str, Y_STR_ARG, &word, &buf, &len));
Radek Krejcid5f2b5f2018-10-11 10:54:36 +0200237 assert_null(buf);
238 assert_int_equal(9, len);
Radek Krejcifc62d7e2018-10-11 12:56:42 +0200239 assert_string_equal("hello\\n\\t\\\"\\\\\";", word);
Radek Krejcid5f2b5f2018-10-11 10:54:36 +0200240
241 ctx.indent = 14;
242 str = "\"hello \t\n\t\t world!\"";
243 /* - space and tabs before newline are stripped out
244 * - space and tabs after newline (indentation) are stripped out
245 */
Radek Krejcifc62d7e2018-10-11 12:56:42 +0200246 assert_int_equal(LY_SUCCESS, get_argument(&ctx, &str, Y_STR_ARG, &word, &buf, &len));
Radek Krejcid5f2b5f2018-10-11 10:54:36 +0200247 assert_non_null(buf);
248 assert_ptr_equal(word, buf);
249 assert_int_equal(14, len);
250 assert_string_equal("hello\n world!", word);
251 free(buf);
252
253 ctx.indent = 14;
254 str = "\"hello\n \tworld!\"";
Radek Krejcifc62d7e2018-10-11 12:56:42 +0200255 assert_int_equal(LY_SUCCESS, get_argument(&ctx, &str, Y_STR_ARG, &word, &buf, &len));
Radek Krejcid5f2b5f2018-10-11 10:54:36 +0200256 assert_non_null(buf);
257 assert_ptr_equal(word, buf);
258 assert_int_equal(12, len);
259 assert_string_equal("hello\nworld!", word);
260 free(buf);
Radek Krejciefd22f62018-09-27 11:47:58 +0200261
262 str = "\'hello\'";
Radek Krejcifc62d7e2018-10-11 12:56:42 +0200263 assert_int_equal(LY_SUCCESS, get_argument(&ctx, &str, Y_STR_ARG, &word, &buf, &len));
Radek Krejciefd22f62018-09-27 11:47:58 +0200264 assert_null(buf);
265 assert_int_equal(5, len);
266 assert_false(strncmp("hello", word, 5));
267
268 str = "\"hel\" +\t\n\"lo\"";
Radek Krejcifc62d7e2018-10-11 12:56:42 +0200269 assert_int_equal(LY_SUCCESS, get_argument(&ctx, &str, Y_STR_ARG, &word, &buf, &len));
Radek Krejciefd22f62018-09-27 11:47:58 +0200270 assert_ptr_equal(word, buf);
271 assert_int_equal(5, len);
272 assert_string_equal("hello", word);
273 free(buf);
Radek Krejcifc62d7e2018-10-11 12:56:42 +0200274 str = "\"hel\" +\t\nlo"; /* unquoted the second part */
275 assert_int_equal(LY_EVALID, get_argument(&ctx, &str, Y_STR_ARG, &word, &buf, &len));
276 logbuf_assert("Both string parts divided by '+' must be quoted. Line number 5.");
Radek Krejciefd22f62018-09-27 11:47:58 +0200277
278 str = "\'he\'\t\n+ \"llo\"";
Radek Krejcifc62d7e2018-10-11 12:56:42 +0200279 assert_int_equal(LY_SUCCESS, get_argument(&ctx, &str, Y_STR_ARG, &word, &buf, &len));
Radek Krejciefd22f62018-09-27 11:47:58 +0200280 assert_ptr_equal(word, buf);
281 assert_int_equal(5, len);
282 assert_string_equal("hello", word);
283 free(buf);
284
Radek Krejcifc62d7e2018-10-11 12:56:42 +0200285 str = " \t\n\"he\"+\'llo\'";
286 assert_int_equal(LY_SUCCESS, get_argument(&ctx, &str, Y_STR_ARG, &word, &buf, &len));
Radek Krejciefd22f62018-09-27 11:47:58 +0200287 assert_ptr_equal(word, buf);
288 assert_int_equal(5, len);
289 assert_string_equal("hello", word);
290 free(buf);
291
Radek Krejci44ceedc2018-10-02 15:54:31 +0200292 /* missing argument */
293 str = ";";
Radek Krejcifc62d7e2018-10-11 12:56:42 +0200294 assert_int_equal(LY_EVALID, get_argument(&ctx, &str, Y_STR_ARG, &word, &buf, &len));
295 logbuf_assert("Invalid character sequence \";\", expected an argument. Line number 7.");
Radek Krejci44ceedc2018-10-02 15:54:31 +0200296
Radek Krejciefd22f62018-09-27 11:47:58 +0200297}
298
Radek Krejci80dd33e2018-09-26 15:57:18 +0200299int main(void)
300{
301 const struct CMUnitTest tests[] = {
Radek Krejci44ceedc2018-10-02 15:54:31 +0200302 cmocka_unit_test_setup(test_helpers, logger_setup),
Radek Krejci80dd33e2018-09-26 15:57:18 +0200303 cmocka_unit_test_setup(test_comments, logger_setup),
Radek Krejciefd22f62018-09-27 11:47:58 +0200304 cmocka_unit_test_setup(test_arg, logger_setup),
Radek Krejci80dd33e2018-09-26 15:57:18 +0200305 };
306
307 return cmocka_run_group_tests(tests, NULL, NULL);
308}