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 : // eventdispatcher
35 : //
36 : #include <eventdispatcher/exception.h>
37 :
38 :
39 : // last include
40 : //
41 : #include <snapdev/poison.h>
42 :
43 :
44 :
45 : namespace
46 : {
47 :
48 :
49 : // test all internal instructions
50 : //
51 : constexpr char const * const g_program1 =
52 : "call(label: function)\n"
53 : "exit()\n"
54 : "goto(label: over_here)\n"
55 : "if(less: when_smaller, equal: when_equal, greater: when_larger)\n"
56 : "label(name: label_name)\n"
57 : "verify_message(sent_server: name,"
58 : " command: BACKGROUND,"
59 : " required_parameters: { color: orange, timeout: 1 + 57 * (3600 / 3) % 7200 - 34, length: -567, height: +33.21 },"
60 : " optional_parameters: {},"
61 : " forbidden_parameters: { hurray })\n"
62 : "compare(expression: ${a} <=> ${b})\n"
63 : ;
64 :
65 :
66 : } // no name namespace
67 :
68 :
69 :
70 1 : CATCH_TEST_CASE("reporter_parser", "[parser][reporter]")
71 : {
72 1 : CATCH_START_SECTION("reporter_parser: parse program1")
73 : {
74 1 : SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("program1", g_program1));
75 1 : SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
76 1 : SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
77 1 : p->parse_program();
78 :
79 1 : CATCH_REQUIRE(s->get_statement_size() == 7);
80 1 : }
81 1 : CATCH_END_SECTION()
82 1 : }
83 :
84 :
85 20 : CATCH_TEST_CASE("reporter_parser_error", "[parser][reporter][error]")
86 : {
87 20 : CATCH_START_SECTION("reporter_parser_error: bad variable")
88 : {
89 1 : SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("bad_variable.rptr", "${bad_var"));
90 1 : SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
91 1 : SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
92 1 : CATCH_REQUIRE_THROWS_MATCHES(
93 : p->parse_program()
94 : , ed::runtime_error
95 : , Catch::Matchers::ExceptionMessage(
96 : "event_dispatcher_exception: invalid token."));
97 1 : }
98 20 : CATCH_END_SECTION()
99 :
100 20 : CATCH_START_SECTION("reporter_parser_error: identifier expected for instruction")
101 : {
102 1 : SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("not_identifier.rptr", "exit() 123()"));
103 1 : SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
104 1 : SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
105 1 : CATCH_REQUIRE_THROWS_MATCHES(
106 : p->parse_program()
107 : , ed::runtime_error
108 : , Catch::Matchers::ExceptionMessage(
109 : "event_dispatcher_exception: expected identifier."));
110 1 : }
111 20 : CATCH_END_SECTION()
112 :
113 20 : CATCH_START_SECTION("reporter_parser_error: unknown instruction")
114 : {
115 1 : SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("unknown_instruction.rptr", "unknown_instruction()"));
116 1 : SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
117 1 : SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
118 1 : CATCH_REQUIRE_THROWS_MATCHES(
119 : p->parse_program()
120 : , ed::runtime_error
121 : , Catch::Matchers::ExceptionMessage(
122 : "event_dispatcher_exception: unknown instruction."));
123 1 : }
124 20 : CATCH_END_SECTION()
125 :
126 20 : CATCH_START_SECTION("reporter_parser_error: expect '(' after instruction")
127 : {
128 1 : SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("missing_open_parenthesis_EOF.rptr", "exit"));
129 1 : SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
130 1 : SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
131 1 : CATCH_REQUIRE_THROWS_MATCHES(
132 : p->parse_program()
133 : , ed::runtime_error
134 : , Catch::Matchers::ExceptionMessage(
135 : "event_dispatcher_exception: expected '(' parenthesis instead of EOF."));
136 1 : }
137 20 : CATCH_END_SECTION()
138 :
139 20 : CATCH_START_SECTION("reporter_parser_error: expect '(' not another token")
140 : {
141 1 : SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("missing_open_parenthesis.rptr", "exit 123"));
142 1 : SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
143 1 : SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
144 1 : CATCH_REQUIRE_THROWS_MATCHES(
145 : p->parse_program()
146 : , ed::runtime_error
147 : , Catch::Matchers::ExceptionMessage(
148 : "event_dispatcher_exception: expected '(' parenthesis."));
149 1 : }
150 20 : CATCH_END_SECTION()
151 :
152 20 : CATCH_START_SECTION("reporter_parser_error: expect ')' before EOF")
153 : {
154 1 : SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("missing_close_parenthesis.rptr", "exit("));
155 1 : SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
156 1 : SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
157 1 : CATCH_REQUIRE_THROWS_MATCHES(
158 : p->parse_program()
159 : , ed::runtime_error
160 : , Catch::Matchers::ExceptionMessage(
161 : "event_dispatcher_exception: expected ')' parenthesis instead of EOF."));
162 1 : }
163 20 : CATCH_END_SECTION()
164 :
165 20 : CATCH_START_SECTION("reporter_parser_error: expect ')' to end list of parameters")
166 : {
167 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\"}"));
168 1 : SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
169 1 : SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
170 1 : CATCH_REQUIRE_THROWS_MATCHES(
171 : p->parse_program()
172 : , ed::runtime_error
173 : , Catch::Matchers::ExceptionMessage(
174 : "event_dispatcher_exception: expected ')' parenthesis to end parameter list."));
175 1 : }
176 20 : CATCH_END_SECTION()
177 :
178 20 : CATCH_START_SECTION("reporter_parser_error: parameter name not identifier")
179 : {
180 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\"}"));
181 1 : SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
182 1 : SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
183 1 : CATCH_REQUIRE_THROWS_MATCHES(
184 : p->parse_program()
185 : , ed::runtime_error
186 : , Catch::Matchers::ExceptionMessage(
187 : "event_dispatcher_exception: expected identifier to name parameter."));
188 1 : }
189 20 : CATCH_END_SECTION()
190 :
191 20 : CATCH_START_SECTION("reporter_parser_error: colon missing after parameter name EOF")
192 : {
193 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"));
194 1 : SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
195 1 : SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
196 1 : CATCH_REQUIRE_THROWS_MATCHES(
197 : p->parse_program()
198 : , ed::runtime_error
199 : , Catch::Matchers::ExceptionMessage(
200 : "event_dispatcher_exception: expected ':' after parameter name, not EOF."));
201 1 : }
202 20 : CATCH_END_SECTION()
203 :
204 20 : CATCH_START_SECTION("reporter_parser_error: colon missing after parameter name")
205 : {
206 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\")"));
207 1 : SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
208 1 : SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
209 1 : CATCH_REQUIRE_THROWS_MATCHES(
210 : p->parse_program()
211 : , ed::runtime_error
212 : , Catch::Matchers::ExceptionMessage(
213 : "event_dispatcher_exception: expected ':' after parameter name."));
214 1 : }
215 20 : CATCH_END_SECTION()
216 :
217 20 : CATCH_START_SECTION("reporter_parser_error: parameter expression missing")
218 : {
219 1 : SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("parameter_without_expression.rptr", "exit(error_message:"));
220 1 : SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
221 1 : SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
222 1 : CATCH_REQUIRE_THROWS_MATCHES(
223 : p->parse_program()
224 : , ed::runtime_error
225 : , Catch::Matchers::ExceptionMessage(
226 : "event_dispatcher_exception: expected expression."));
227 1 : }
228 20 : CATCH_END_SECTION()
229 :
230 20 : CATCH_START_SECTION("reporter_parser_error: list must end with '}', not EOF")
231 : {
232 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, "));
233 1 : SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
234 1 : SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
235 1 : CATCH_REQUIRE_THROWS_MATCHES(
236 : p->parse_program()
237 : , ed::runtime_error
238 : , Catch::Matchers::ExceptionMessage(
239 : "event_dispatcher_exception: end of file found before end of list ('}' missing)."));
240 1 : }
241 20 : CATCH_END_SECTION()
242 :
243 20 : CATCH_START_SECTION("reporter_parser_error: list must end with '}'")
244 : {
245 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 )"));
246 1 : SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
247 1 : SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
248 1 : CATCH_REQUIRE_THROWS_MATCHES(
249 : p->parse_program()
250 : , ed::runtime_error
251 : , Catch::Matchers::ExceptionMessage(
252 : "event_dispatcher_exception: a list of parameter values must end with '}'."));
253 1 : }
254 20 : CATCH_END_SECTION()
255 :
256 20 : CATCH_START_SECTION("reporter_parser_error: name of list item must be an identifier")
257 : {
258 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 )"));
259 1 : SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
260 1 : SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
261 1 : CATCH_REQUIRE_THROWS_MATCHES(
262 : p->parse_program()
263 : , ed::runtime_error
264 : , Catch::Matchers::ExceptionMessage(
265 : "event_dispatcher_exception: a list item must be named using an identifier."));
266 1 : }
267 20 : CATCH_END_SECTION()
268 :
269 20 : CATCH_START_SECTION("reporter_parser_error: unterminated list item (EOF early)")
270 : {
271 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 "));
272 1 : SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
273 1 : SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
274 1 : CATCH_REQUIRE_THROWS_MATCHES(
275 : p->parse_program()
276 : , ed::runtime_error
277 : , Catch::Matchers::ExceptionMessage(
278 : "event_dispatcher_exception: a list must end with a '}'."));
279 1 : }
280 20 : CATCH_END_SECTION()
281 :
282 20 : CATCH_START_SECTION("reporter_parser_error: list item expression missing (EOF early)")
283 : {
284 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 : "));
285 1 : SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
286 1 : SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
287 1 : CATCH_REQUIRE_THROWS_MATCHES(
288 : p->parse_program()
289 : , ed::runtime_error
290 : , Catch::Matchers::ExceptionMessage(
291 : "event_dispatcher_exception: a list item with a colon (:) must be followed by an expression."));
292 1 : }
293 20 : CATCH_END_SECTION()
294 :
295 20 : CATCH_START_SECTION("reporter_parser_error: expression open parenthesis and EOF")
296 : {
297 1 : SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::lexer>("expression_parenthesis_eof.rptr", "exit(error_message: ("));
298 1 : SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
299 1 : SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
300 1 : CATCH_REQUIRE_THROWS_MATCHES(
301 : p->parse_program()
302 : , ed::runtime_error
303 : , Catch::Matchers::ExceptionMessage(
304 : "event_dispatcher_exception: an expression between parenthesis must include at least one primary expression."));
305 1 : }
306 20 : CATCH_END_SECTION()
307 :
308 20 : CATCH_START_SECTION("reporter_parser_error: expression close parenthesis missing")
309 : {
310 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 }"));
311 1 : SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
312 1 : SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
313 1 : CATCH_REQUIRE_THROWS_MATCHES(
314 : p->parse_program()
315 : , ed::runtime_error
316 : , Catch::Matchers::ExceptionMessage(
317 : "event_dispatcher_exception: an expression between parenthesis must include the ')' at the end."));
318 1 : }
319 20 : CATCH_END_SECTION()
320 :
321 20 : CATCH_START_SECTION("reporter_parser_error: expression primary not found")
322 : {
323 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 } ))"));
324 1 : SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
325 1 : SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
326 1 : CATCH_REQUIRE_THROWS_MATCHES(
327 : p->parse_program()
328 : , ed::runtime_error
329 : , Catch::Matchers::ExceptionMessage(
330 : "event_dispatcher_exception: expected a primary token for expression."));
331 1 : }
332 20 : CATCH_END_SECTION()
333 :
334 20 : CATCH_START_SECTION("reporter_parser_error: command parameter missing in verify_message()")
335 : {
336 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 })"));
337 1 : SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
338 1 : SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
339 1 : CATCH_REQUIRE_THROWS_MATCHES(
340 : p->parse_program()
341 : , ed::runtime_error
342 : , Catch::Matchers::ExceptionMessage(
343 : "event_dispatcher_exception: parameter \"command\" is required by \"verify_message\"."));
344 1 : }
345 20 : CATCH_END_SECTION()
346 20 : }
347 :
348 :
349 : // vim: ts=4 sw=4 et
|