Line data Source code
1 : // Copyright (c) 2012-2024 Made to Order Software Corp. All Rights Reserved
2 : //
3 : // https://snapwebsites.org/project/eventdispatcher
4 : // contact@m2osw.com
5 : //
6 : // This program is free software: you can redistribute it and/or modify
7 : // it under the terms of the GNU General Public License as published by
8 : // the Free Software Foundation, either version 3 of the License, or
9 : // (at your option) any later version.
10 : //
11 : // This program is distributed in the hope that it will be useful,
12 : // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : // GNU General Public License for more details.
15 : //
16 : // You should have received a copy of the GNU General Public License
17 : // along with this program. If not, see <https://www.gnu.org/licenses/>.
18 :
19 : // this diagnostic has to be turned off "globally" so the catch2 does not
20 : // generate the warning on the floating point == operator
21 : //
22 : //#pragma GCC diagnostic ignored "-Wfloat-equal"
23 :
24 : // self
25 : //
26 : #include "catch_main.h"
27 :
28 :
29 : // reporter
30 : //
31 : #include <eventdispatcher/reporter/parser.h>
32 :
33 :
34 : // last include
35 : //
36 : #include <snapdev/poison.h>
37 :
38 :
39 :
40 : namespace
41 : {
42 :
43 :
44 : // test all internal instructions
45 : //
46 : constexpr char const * const g_program1 =
47 : "call(label: function)\n"
48 : "exit()\n"
49 : "goto(label: over_here)\n"
50 : "if(less: when_smaller, equal: when_equal, greater: when_larger)\n"
51 : "label(name: label_name)\n"
52 : "verify_message(sent_server: name,"
53 : " command: BACKGROUND,"
54 : " required_parameters: { color: orange, timeout: 1 + 57 * (3600 / 3) % 7200 - 34, length: -567, height: +33.21 },"
55 : " optional_parameters: {},"
56 : " forbidden_parameters: { hurray })\n"
57 : ;
58 :
59 :
60 : } // no name namespace
61 :
62 :
63 :
64 1 : CATCH_TEST_CASE("reporter_parser", "[parser][reporter]")
65 : {
66 1 : CATCH_START_SECTION("parse program1")
67 : {
68 1 : SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("program1", g_program1));
69 1 : SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
70 1 : SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
71 1 : p->parse_program();
72 :
73 1 : CATCH_REQUIRE(s->get_statement_size() == 6);
74 1 : }
75 1 : CATCH_END_SECTION()
76 1 : }
77 :
78 :
79 20 : CATCH_TEST_CASE("reporter_parser_error", "[parser][reporter][error]")
80 : {
81 20 : CATCH_START_SECTION("bad variable")
82 : {
83 1 : SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("bad_variable.rptr", "${bad_var"));
84 1 : SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
85 1 : SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
86 1 : CATCH_REQUIRE_THROWS_MATCHES(
87 : p->parse_program()
88 : , std::runtime_error
89 : , Catch::Matchers::ExceptionMessage(
90 : "invalid token."));
91 1 : }
92 20 : CATCH_END_SECTION()
93 :
94 20 : CATCH_START_SECTION("identifier expected for instruction")
95 : {
96 1 : SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("not_identifier.rptr", "exit() 123()"));
97 1 : SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
98 1 : SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
99 1 : CATCH_REQUIRE_THROWS_MATCHES(
100 : p->parse_program()
101 : , std::runtime_error
102 : , Catch::Matchers::ExceptionMessage(
103 : "expected identifier."));
104 1 : }
105 20 : CATCH_END_SECTION()
106 :
107 20 : CATCH_START_SECTION("unknown instruction")
108 : {
109 1 : SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("unknown_instruction.rptr", "unknown_instruction()"));
110 1 : SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
111 1 : SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
112 1 : CATCH_REQUIRE_THROWS_MATCHES(
113 : p->parse_program()
114 : , std::runtime_error
115 : , Catch::Matchers::ExceptionMessage(
116 : "unknown instruction."));
117 1 : }
118 20 : CATCH_END_SECTION()
119 :
120 20 : CATCH_START_SECTION("expect '(' after instruction")
121 : {
122 1 : SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("missing_open_parenthesis_EOF.rptr", "exit"));
123 1 : SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
124 1 : SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
125 1 : CATCH_REQUIRE_THROWS_MATCHES(
126 : p->parse_program()
127 : , std::runtime_error
128 : , Catch::Matchers::ExceptionMessage(
129 : "expected '(' parenthesis instead of EOF."));
130 1 : }
131 20 : CATCH_END_SECTION()
132 :
133 20 : CATCH_START_SECTION("expect '(' not another token")
134 : {
135 1 : SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("missing_open_parenthesis.rptr", "exit 123"));
136 1 : SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
137 1 : SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
138 1 : CATCH_REQUIRE_THROWS_MATCHES(
139 : p->parse_program()
140 : , std::runtime_error
141 : , Catch::Matchers::ExceptionMessage(
142 : "expected '(' parenthesis."));
143 1 : }
144 20 : CATCH_END_SECTION()
145 :
146 20 : CATCH_START_SECTION("expect ')' before EOF")
147 : {
148 1 : SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("missing_close_parenthesis.rptr", "exit("));
149 1 : SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
150 1 : SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
151 1 : CATCH_REQUIRE_THROWS_MATCHES(
152 : p->parse_program()
153 : , std::runtime_error
154 : , Catch::Matchers::ExceptionMessage(
155 : "expected ')' parenthesis instead of EOF."));
156 1 : }
157 20 : CATCH_END_SECTION()
158 :
159 20 : CATCH_START_SECTION("expect ')' to end list of parameters")
160 : {
161 1 : SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("missing_close_parenthesis.rptr", "exit(error_message: \"msg\"}"));
162 1 : SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
163 1 : SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
164 1 : CATCH_REQUIRE_THROWS_MATCHES(
165 : p->parse_program()
166 : , std::runtime_error
167 : , Catch::Matchers::ExceptionMessage(
168 : "expected ')' parenthesis to end parameter list."));
169 1 : }
170 20 : CATCH_END_SECTION()
171 :
172 20 : CATCH_START_SECTION("parameter name not identifier")
173 : {
174 1 : SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("parameter_name_not_identifier.rptr", "exit(123: \"msg\"}"));
175 1 : SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
176 1 : SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
177 1 : CATCH_REQUIRE_THROWS_MATCHES(
178 : p->parse_program()
179 : , std::runtime_error
180 : , Catch::Matchers::ExceptionMessage(
181 : "expected identifier to name parameter."));
182 1 : }
183 20 : CATCH_END_SECTION()
184 :
185 20 : CATCH_START_SECTION("colon missing after parameter name EOF")
186 : {
187 1 : SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("parameter_name_no_colon.rptr", "exit(error_message"));
188 1 : SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
189 1 : SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
190 1 : CATCH_REQUIRE_THROWS_MATCHES(
191 : p->parse_program()
192 : , std::runtime_error
193 : , Catch::Matchers::ExceptionMessage(
194 : "expected ':' after parameter name, not EOF."));
195 1 : }
196 20 : CATCH_END_SECTION()
197 :
198 20 : CATCH_START_SECTION("colon missing after parameter name")
199 : {
200 1 : SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("parameter_name_no_colon.rptr", "exit(error_message \"msg\")"));
201 1 : SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
202 1 : SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
203 1 : CATCH_REQUIRE_THROWS_MATCHES(
204 : p->parse_program()
205 : , std::runtime_error
206 : , Catch::Matchers::ExceptionMessage(
207 : "expected ':' after parameter name."));
208 1 : }
209 20 : CATCH_END_SECTION()
210 :
211 20 : CATCH_START_SECTION("parameter expression missing")
212 : {
213 1 : SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("parameter_without_expression.rptr", "exit(error_message:"));
214 1 : SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
215 1 : SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
216 1 : CATCH_REQUIRE_THROWS_MATCHES(
217 : p->parse_program()
218 : , std::runtime_error
219 : , Catch::Matchers::ExceptionMessage(
220 : "expected expression."));
221 1 : }
222 20 : CATCH_END_SECTION()
223 :
224 20 : CATCH_START_SECTION("list must end with '}', not EOF")
225 : {
226 1 : SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("list_end_with_curly_bracket.rptr", "verify_message(required_parameters: { version: 123, "));
227 1 : SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
228 1 : SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
229 1 : CATCH_REQUIRE_THROWS_MATCHES(
230 : p->parse_program()
231 : , std::runtime_error
232 : , Catch::Matchers::ExceptionMessage(
233 : "end of file found before end of list ('}' missing)."));
234 1 : }
235 20 : CATCH_END_SECTION()
236 :
237 20 : CATCH_START_SECTION("list must end with '}'")
238 : {
239 1 : SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("list_end_with_curly_bracket.rptr", "verify_message(required_parameters: { version: 123 )"));
240 1 : SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
241 1 : SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
242 1 : CATCH_REQUIRE_THROWS_MATCHES(
243 : p->parse_program()
244 : , std::runtime_error
245 : , Catch::Matchers::ExceptionMessage(
246 : "a list of parameter values must end with '}'."));
247 1 : }
248 20 : CATCH_END_SECTION()
249 :
250 20 : CATCH_START_SECTION("name of list item must be an identifier")
251 : {
252 1 : SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("list_item_identifier.rptr", "verify_message(required_parameters: { 123: version )"));
253 1 : SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
254 1 : SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
255 1 : CATCH_REQUIRE_THROWS_MATCHES(
256 : p->parse_program()
257 : , std::runtime_error
258 : , Catch::Matchers::ExceptionMessage(
259 : "a list item must be named using an identifier."));
260 1 : }
261 20 : CATCH_END_SECTION()
262 :
263 20 : CATCH_START_SECTION("unterminated list item (EOF early)")
264 : {
265 1 : SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("list_item_identifier.rptr", "verify_message(required_parameters: { version "));
266 1 : SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
267 1 : SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
268 1 : CATCH_REQUIRE_THROWS_MATCHES(
269 : p->parse_program()
270 : , std::runtime_error
271 : , Catch::Matchers::ExceptionMessage(
272 : "a list must end with a '}'."));
273 1 : }
274 20 : CATCH_END_SECTION()
275 :
276 20 : CATCH_START_SECTION("list item expression missing (EOF early)")
277 : {
278 1 : SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("list_item_identifier.rptr", "verify_message(required_parameters: { version : "));
279 1 : SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
280 1 : SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
281 1 : CATCH_REQUIRE_THROWS_MATCHES(
282 : p->parse_program()
283 : , std::runtime_error
284 : , Catch::Matchers::ExceptionMessage(
285 : "a list item with a colon (:) must be followed by an expression."));
286 1 : }
287 20 : CATCH_END_SECTION()
288 :
289 20 : CATCH_START_SECTION("expression open parenthesis and EOF")
290 : {
291 1 : SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("expression_parenthesis_eof.rptr", "exit(error_message: ("));
292 1 : SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
293 1 : SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
294 1 : CATCH_REQUIRE_THROWS_MATCHES(
295 : p->parse_program()
296 : , std::runtime_error
297 : , Catch::Matchers::ExceptionMessage(
298 : "an expression between parenthesis must include at least one primary expression."));
299 1 : }
300 20 : CATCH_END_SECTION()
301 :
302 20 : CATCH_START_SECTION("expression close parenthesis missing")
303 : {
304 1 : SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("expression_parenthesis_missing.rptr", "verify_message(required_parameters: { color: ( 234 + 770 }"));
305 1 : SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
306 1 : SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
307 1 : CATCH_REQUIRE_THROWS_MATCHES(
308 : p->parse_program()
309 : , std::runtime_error
310 : , Catch::Matchers::ExceptionMessage(
311 : "an expression between parenthesis must include the ')' at the end."));
312 1 : }
313 20 : CATCH_END_SECTION()
314 :
315 20 : CATCH_START_SECTION("expression primary not found")
316 : {
317 1 : SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("expression_primary_missing.rptr", "verify_message(required_parameters: { color: ( { oops - si } ))"));
318 1 : SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
319 1 : SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
320 1 : CATCH_REQUIRE_THROWS_MATCHES(
321 : p->parse_program()
322 : , std::runtime_error
323 : , Catch::Matchers::ExceptionMessage(
324 : "expected a primary token for expression."));
325 1 : }
326 20 : CATCH_END_SECTION()
327 :
328 20 : CATCH_START_SECTION("command parameter missing in verify_message()")
329 : {
330 1 : SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("missing_parameter.rptr", "verify_message(required_parameters: { color: red })"));
331 1 : SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
332 1 : SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
333 1 : CATCH_REQUIRE_THROWS_MATCHES(
334 : p->parse_program()
335 : , std::runtime_error
336 : , Catch::Matchers::ExceptionMessage(
337 : "parameter \"command\" is required by \"verify_message\"."));
338 1 : }
339 20 : CATCH_END_SECTION()
340 20 : }
341 :
342 :
343 : // vim: ts=4 sw=4 et
|