Line data Source code
1 : // Copyright (c) 2011-2023 Made to Order Software Corp. All Rights Reserved
2 : //
3 : // https://snapwebsites.org/project/as2js
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 : // as2js
20 : //
21 : #include <as2js/compiler.h>
22 :
23 : #include <as2js/exception.h>
24 : #include <as2js/json.h>
25 : #include <as2js/message.h>
26 : #include <as2js/parser.h>
27 :
28 :
29 : // self
30 : //
31 : #include "catch_main.h"
32 :
33 :
34 : // snapdev
35 : //
36 : #include <snapdev/string_replace_many.h>
37 :
38 :
39 : // C++
40 : //
41 : #include <algorithm>
42 : #include <climits>
43 : #include <cstring>
44 : #include <iomanip>
45 :
46 :
47 : // C
48 : //
49 : #include <unistd.h>
50 : #include <sys/stat.h>
51 :
52 :
53 : // last include
54 : //
55 : #include <snapdev/poison.h>
56 :
57 :
58 :
59 : namespace
60 : {
61 :
62 : bool g_created_files = false;
63 :
64 :
65 :
66 :
67 : class input_retriever
68 : : public as2js::input_retriever
69 : {
70 : public:
71 0 : virtual as2js::base_stream::pointer_t retrieve(std::string const & filename) override
72 : {
73 0 : if(filename == "")
74 : {
75 : }
76 :
77 0 : return as2js::base_stream::pointer_t();
78 : }
79 :
80 : };
81 :
82 :
83 : std::string g_current_working_directory;
84 :
85 :
86 1 : void init_compiler(as2js::compiler & compiler)
87 : {
88 : // The .rc file cannot be captured by the input retriever
89 : // so instead we create a file in the current directory
90 :
91 : // setup an input retriever which in most cases just returns nullptr
92 : //
93 1 : compiler.set_input_retriever(std::make_shared<input_retriever>());
94 1 : }
95 :
96 :
97 36866 : void init_rc(bool bad_script = false)
98 : {
99 : // TODO: implement the clean up for this one...
100 : //
101 36866 : g_created_files = true;
102 :
103 : // we recreate because in the clean up we may end up deleting that
104 : // folder (even though it's already created by the catch_db_init()
105 : // function which happens before this call)
106 : //
107 36866 : if(mkdir("as2js", 0700) != 0)
108 : {
109 36866 : if(errno != EEXIST)
110 : {
111 0 : CATCH_REQUIRE(!"could not create directory as2js");
112 : }
113 : // else -- we already created it, that's fine
114 : }
115 :
116 : // The .rc file cannot be captured by the input retriever
117 : // so instead we create a file in the current directory
118 : //
119 110598 : std::string const safe_cwd(snapdev::string_replace_many(
120 : g_current_working_directory
121 147464 : , { { "'", "\\'" } }));
122 36866 : char const * script_path(bad_script ? "no-scripts-here" : "scripts");
123 36866 : std::ofstream out("as2js/as2js.rc");
124 : out << "// rc test file\n"
125 : "{\n"
126 36866 : " 'scripts': '" << SNAP_CATCH2_NAMESPACE::g_source_dir() << '/' << script_path << "',\n"
127 : " 'db': '" << safe_cwd << "/test.db',\n"
128 : " 'temporary_variable_name': '@temp$'\n"
129 36866 : "}\n";
130 :
131 36866 : CATCH_REQUIRE(!!out);
132 73732 : }
133 :
134 :
135 1 : void clean_rc()
136 : {
137 1 : unlink("as2js/as2js.rc");
138 1 : }
139 :
140 :
141 :
142 : //
143 : // JSON data used to test the compiler, most of the work is in this table
144 : // these are long JSON strings! It is actually generated using the
145 : // json_to_string tool and the test_as2js_compiler_*.json source files.
146 : //
147 : // Note: the top entries are arrays so we can execute programs in the
148 : // order we define them...
149 : //
150 : char const g_compiler_class[] =
151 : #include "compiler_data/class.ci"
152 : ;
153 : char const g_compiler_expression[] =
154 : #include "compiler_data/expression.ci"
155 : ;
156 : char const g_compiler_enum[] =
157 : #include "compiler_data/enum.ci"
158 : ;
159 : //char const g_compiler_compare[] =
160 : //#include "compiler_data/compare.ci"
161 : //;
162 : //char const g_compiler_conditional[] =
163 : //#include "compiler_data/conditional.ci"
164 : //;
165 : //char const g_compiler_equality[] =
166 : //#include "compiler_data/equality.ci"
167 : //;
168 : //char const g_compiler_logical[] =
169 : //#include "compiler_data/logical.ci"
170 : //;
171 : //char const g_compiler_match[] =
172 : //#include "compiler_data/match.ci"
173 : //;
174 : //char const g_compiler_multiplicative[] =
175 : //#include "compiler_data/multiplicative.ci"
176 : //;
177 : //char const g_compiler_relational[] =
178 : //#include "compiler_data/relational.ci"
179 : //;
180 : //char const g_compiler_statements[] =
181 : //#include "compiler_data/statements.ci"
182 : //;
183 :
184 :
185 :
186 :
187 :
188 :
189 :
190 :
191 : // This function runs all the tests defined in the
192 : // string 'data'
193 3 : void run_tests(char const * input_data, char const *filename)
194 : {
195 3 : if(SNAP_CATCH2_NAMESPACE::g_save_parser_tests)
196 : {
197 0 : std::ofstream json_file;
198 0 : json_file.open(filename);
199 0 : CATCH_REQUIRE(json_file.is_open());
200 : json_file
201 : << "// To properly indent this JSON you may use https://json-indent.appspot.com/\n"
202 : << input_data
203 0 : << '\n';
204 0 : }
205 :
206 3 : as2js::input_stream<std::stringstream>::pointer_t in(std::make_shared<as2js::input_stream<std::stringstream>>());
207 3 : in->get_position().set_filename(filename);
208 3 : *in << input_data;
209 3 : as2js::json::pointer_t json_data(std::make_shared<as2js::json>());
210 6 : as2js::json::json_value::pointer_t json(json_data->parse(in));
211 :
212 : // verify that the JSON parse() did not fail (internal to test)
213 : //
214 3 : CATCH_REQUIRE(json != nullptr);
215 3 : CATCH_REQUIRE(json->get_type() == as2js::json::json_value::type_t::JSON_TYPE_ARRAY);
216 :
217 6 : std::string const name_string("name");
218 6 : std::string const program_string("program");
219 6 : std::string const verbose_string("verbose");
220 6 : std::string const slow_string("slow");
221 6 : std::string const parser_result_string("parser result");
222 6 : std::string const compiler_result_string("compiler result");
223 6 : std::string const expected_messages_string("expected messages");
224 :
225 3 : as2js::json::json_value::array_t const& array(json->get_array());
226 3 : std::size_t const max_programs(array.size());
227 12 : for(std::size_t idx(0); idx < max_programs; ++idx)
228 : {
229 9 : as2js::json::json_value::pointer_t prog_obj(array[idx]);
230 9 : CATCH_REQUIRE(prog_obj->get_type() == as2js::json::json_value::type_t::JSON_TYPE_OBJECT);
231 9 : as2js::json::json_value::object_t const & prog(prog_obj->get_object());
232 :
233 9 : bool verbose(false);
234 9 : as2js::json::json_value::object_t::const_iterator verbose_it(prog.find(verbose_string));
235 9 : if(verbose_it != prog.end())
236 : {
237 2 : verbose = verbose_it->second->get_type() == as2js::json::json_value::type_t::JSON_TYPE_TRUE;
238 : }
239 :
240 9 : bool slow(false);
241 9 : as2js::json::json_value::object_t::const_iterator slow_it(prog.find(slow_string));
242 9 : if(slow_it != prog.end())
243 : {
244 9 : slow = slow_it->second->get_type() == as2js::json::json_value::type_t::JSON_TYPE_TRUE;
245 : }
246 :
247 : // got a program, try to compile it with all the possible options
248 9 : as2js::json::json_value::pointer_t name(prog.find(name_string)->second);
249 9 : std::cout << " -- working on \"" << name->get_string() << "\" " << (slow ? "" : "...") << std::flush;
250 :
251 36873 : for(std::size_t opt(0); opt < (1ULL << SNAP_CATCH2_NAMESPACE::g_options_size); ++opt)
252 : {
253 36864 : if(slow && ((opt + 1) % 250) == 0)
254 : {
255 144 : std::cout << "." << std::flush;
256 : }
257 : #define SHOW_OPTIONS 0
258 : #if SHOW_OPTIONS
259 : std::cerr << "\n***\n*** OPTIONS: [0x" << std::uppercase << std::hex << opt << std::dec << "]";
260 : #endif
261 36864 : as2js::options::pointer_t options(std::make_shared<as2js::options>());
262 479232 : for(std::size_t o(0); o < SNAP_CATCH2_NAMESPACE::g_options_size; ++o)
263 : {
264 442368 : if((opt & (1 << o)) != 0)
265 : {
266 221184 : options->set_option(
267 221184 : SNAP_CATCH2_NAMESPACE::g_options[o].f_option
268 221184 : , options->get_option(SNAP_CATCH2_NAMESPACE::g_options[o].f_option)
269 221184 : | SNAP_CATCH2_NAMESPACE::g_options[o].f_value);
270 : #if SHOW_OPTIONS
271 : std::cerr << " " << SNAP_CATCH2_NAMESPACE::g_options[o].f_name << "=" << SNAP_CATCH2_NAMESPACE::g_options[o].f_value;
272 : #endif
273 : }
274 : }
275 : #if SHOW_OPTIONS
276 : std::cerr << "\n***\n";
277 : #endif
278 :
279 36864 : as2js::json::json_value::pointer_t program_value(prog.find(program_string)->second);
280 36864 : std::string program_source(program_value->get_string());
281 : //std::cerr << "--- prog = [" << program_source << "]\n";
282 36864 : as2js::input_stream<std::stringstream>::pointer_t prog_text(std::make_shared<as2js::input_stream<std::stringstream>>());
283 36864 : prog_text->get_position().set_filename("test/" + std::string(filename) + ": " + name->get_string());
284 36864 : *prog_text << program_source;
285 36864 : as2js::parser::pointer_t parser(std::make_shared<as2js::parser>(prog_text, options));
286 :
287 36864 : init_rc();
288 36864 : SNAP_CATCH2_NAMESPACE::test_callback parser_tc(verbose, true);
289 :
290 : // no errors exepected while parsing (if you want to test errors
291 : // in the parser, use the test_as2js_parser.cpp test instead)
292 : //
293 36864 : as2js::node::pointer_t root(parser->parse());
294 : //if(name->get_string() == "well defined enum")
295 : //std::cerr << "--- parser output is:\n" << *root << "\n\n";
296 :
297 : // verify the parser result, that way we can make sure we are
298 : // testing the tree we want to test with the compiler
299 : //
300 36864 : SNAP_CATCH2_NAMESPACE::verify_result(parser_result_string, prog.find(parser_result_string)->second, root, verbose, false);
301 :
302 36864 : SNAP_CATCH2_NAMESPACE::test_callback tc(verbose, false);
303 :
304 : // now the compiler may end up generating messages...
305 : //
306 36864 : as2js::json::json_value::object_t::const_iterator expected_msg_it(prog.find(expected_messages_string));
307 36864 : if(expected_msg_it != prog.end())
308 : {
309 :
310 : // the expected messages value must be an array
311 : //
312 0 : as2js::json::json_value::array_t const& msg_array(expected_msg_it->second->get_array());
313 0 : std::size_t const max_msgs(msg_array.size());
314 0 : for(std::size_t j(0); j < max_msgs; ++j)
315 : {
316 0 : as2js::json::json_value::pointer_t message_value(msg_array[j]);
317 0 : as2js::json::json_value::object_t const& message(message_value->get_object());
318 :
319 0 : bool ignore_message(false);
320 :
321 0 : as2js::json::json_value::object_t::const_iterator const message_options_iterator(message.find("options"));
322 0 : if(message_options_iterator != message.end())
323 : {
324 : //{
325 : //as2js::json::json_value::object_t::const_iterator line_it(message.find("line #"));
326 : //if(line_it != message.end())
327 : //{
328 : // int64_t lines(line_it->second->get_integer().get());
329 : //std::cerr << "_________\nLine #" << lines << "\n";
330 : //}
331 : //else
332 : //std::cerr << "_________\nLine #<undefined>\n";
333 : //}
334 0 : std::string const message_options(message_options_iterator->second->get_string());
335 0 : for(char const *s(message_options.c_str()), *start(s);; ++s)
336 : {
337 0 : if(*s == ',' || *s == '|' || *s == '\0')
338 : {
339 0 : std::string const opt_name(start, s - start);
340 0 : for(std::size_t o(0); o < SNAP_CATCH2_NAMESPACE::g_options_size; ++o)
341 : {
342 0 : if(SNAP_CATCH2_NAMESPACE::g_options[o].f_name == opt_name)
343 : {
344 0 : ignore_message = (opt & (1 << o)) != 0;
345 : //std::cerr << "+++ pos option [" << opt_name << "] " << ignore_message << "\n";
346 0 : goto found_option;
347 : }
348 0 : else if(SNAP_CATCH2_NAMESPACE::g_options[o].f_neg_name == opt_name)
349 : {
350 0 : ignore_message = (opt & (1 << o)) == 0;
351 : //std::cerr << "+++ neg option [" << opt_name << "] " << ignore_message << "\n";
352 0 : goto found_option;
353 : }
354 : }
355 0 : std::cerr << "error: Option \"" << opt_name << "\" not found in our list of valid options\n";
356 0 : CATCH_REQUIRE("option name from JSON not found in g_options" == nullptr);
357 :
358 0 : found_option:
359 0 : if(*s == '\0')
360 : {
361 0 : break;
362 : }
363 0 : if(*s == '|')
364 : {
365 0 : if(ignore_message)
366 : {
367 0 : break;
368 : }
369 : }
370 : else
371 : {
372 0 : if(!ignore_message)
373 : {
374 0 : break;
375 : }
376 : }
377 :
378 : // skip commas
379 : do
380 : {
381 0 : ++s;
382 : }
383 0 : while(*s == ',' || *s == '|');
384 0 : start = s;
385 0 : }
386 0 : }
387 0 : }
388 :
389 0 : if(!ignore_message)
390 : {
391 0 : SNAP_CATCH2_NAMESPACE::test_callback::expected_t expected;
392 0 : expected.f_message_level = static_cast<as2js::message_level_t>(message.find("message level")->second->get_integer().get());
393 0 : expected.f_error_code = SNAP_CATCH2_NAMESPACE::str_to_error_code(message.find("error code")->second->get_string());
394 0 : expected.f_pos.set_filename("unknown-file");
395 0 : as2js::json::json_value::object_t::const_iterator func_it(message.find("function name"));
396 0 : if(func_it == message.end())
397 : {
398 0 : expected.f_pos.set_function("unknown-func");
399 : }
400 : else
401 : {
402 0 : expected.f_pos.set_function(func_it->second->get_string());
403 : }
404 0 : as2js::json::json_value::object_t::const_iterator line_it(message.find("line #"));
405 0 : if(line_it != message.end())
406 : {
407 0 : std::int64_t lines(line_it->second->get_integer().get());
408 0 : for(std::int64_t l(1); l < lines; ++l)
409 : {
410 0 : expected.f_pos.new_line();
411 : }
412 : }
413 0 : expected.f_message = message.find("message")->second->get_string();
414 0 : tc.f_expected.push_back(expected);
415 0 : }
416 0 : }
417 : }
418 :
419 : // run the compiler
420 : //
421 110592 : as2js::compiler compiler(options);
422 36864 : compiler.compile(root);
423 :
424 : //std::cerr << " -- compiler root after compiling:\n" << *root << "\n\n";
425 :
426 : // the result is object which can have children
427 : // which are represented by an array of objects
428 : //
429 36864 : SNAP_CATCH2_NAMESPACE::verify_result(compiler_result_string, prog.find(compiler_result_string)->second, root, verbose, false);
430 :
431 36864 : tc.got_called();
432 36864 : }
433 :
434 9 : std::cout << " OK\n";
435 9 : }
436 :
437 3 : std::cout << "\n";
438 6 : }
439 :
440 :
441 : }
442 : // no name namespace
443 :
444 :
445 : namespace SNAP_CATCH2_NAMESPACE
446 : {
447 :
448 :
449 1 : int catch_compiler_init()
450 : {
451 : // get the current working directory as we need it in multiple places
452 : // that way it's cached and we do not have to duplicate this code over
453 : // and over again
454 : //
455 1 : char * cwd(get_current_dir_name());
456 1 : if(cwd == nullptr)
457 : {
458 0 : std::cerr << "error: could not get the current directory name.\n";
459 0 : return 1;
460 : }
461 1 : g_current_working_directory = cwd;
462 1 : free(cwd);
463 :
464 1 : struct stat st = {};
465 :
466 : // we do not want a test.db or it could conflict with this test
467 : //
468 1 : if(stat("test.db", &st) == 0)
469 : {
470 : std::cerr << "error: file \""
471 : << "test.db"
472 0 : << "\" already exists; please check it out to make sure you can delete it and try running the test again.\n";
473 0 : return 1;
474 : }
475 :
476 : // Now check that we have the scripts directories, we expect
477 : // the test to be run from the binary directory and this folder
478 : // is found in the source tree... so we have to prepend the
479 : // souce dir
480 : //
481 1 : std::vector<std::string> script_folders
482 : {
483 : "scripts",
484 : "scripts/extensions",
485 : "scripts/native",
486 9 : };
487 4 : for(auto const & p : script_folders)
488 : {
489 3 : std::string filename(SNAP_CATCH2_NAMESPACE::g_source_dir());
490 3 : filename += '/';
491 3 : filename += p;
492 3 : if(stat(filename.c_str(), &st) != 0)
493 : {
494 : std::cerr << "error: file \""
495 : << filename
496 0 : << "\" is missing; please make sure that system scripts are accessible from this test.\n";
497 0 : return 1;
498 : }
499 3 : }
500 :
501 1 : return 0;
502 1 : }
503 :
504 :
505 2 : void catch_compiler_cleanup()
506 : {
507 2 : if(g_created_files)
508 : {
509 : // ignore errors on these few calls
510 : //
511 2 : unlink("test.db");
512 2 : unlink("as2js/as2js.rc");
513 2 : rmdir("as2js");
514 : }
515 2 : }
516 :
517 :
518 : } // namespace SNAP_CATCH2_NAMESPACE
519 :
520 :
521 :
522 :
523 :
524 4 : CATCH_TEST_CASE("compiler_invalid_module_files", "[compiler][module][invalid]")
525 : {
526 4 : CATCH_START_SECTION("compiler_invalid_module_files: missing as2js.rc file")
527 : {
528 : // as2js.rc checked before the options (this is not a really good
529 : // test I guess... as the order is only fortuitous)
530 : //
531 1 : clean_rc();
532 1 : as2js::compiler::clean();
533 2 : CATCH_REQUIRE_THROWS_MATCHES(
534 : std::make_shared<as2js::compiler>(nullptr)
535 : , as2js::as2js_exit
536 : , Catch::Matchers::ExceptionMessage(
537 : "as2js_exception: cannot find the \"as2js.rc\" file; the system default is usually put in \"/etc/as2js/as2js.rc\"."));
538 : }
539 4 : CATCH_END_SECTION()
540 :
541 4 : CATCH_START_SECTION("compiler_invalid_module_files: with option, still missing as2js.rc file")
542 : {
543 1 : as2js::options::pointer_t options(std::make_shared<as2js::options>());
544 1 : CATCH_REQUIRE_THROWS_MATCHES(
545 : std::make_shared<as2js::compiler>(options)
546 : , as2js::as2js_exit
547 : , Catch::Matchers::ExceptionMessage(
548 : "as2js_exception: cannot find the \"as2js.rc\" file; the system default is usually put in \"/etc/as2js/as2js.rc\"."));
549 1 : }
550 4 : CATCH_END_SECTION()
551 :
552 4 : CATCH_START_SECTION("compiler_invalid_module_files: invalid path to scripts")
553 : {
554 1 : init_rc(true);
555 1 : as2js::options::pointer_t options(std::make_shared<as2js::options>());
556 1 : CATCH_REQUIRE_THROWS_MATCHES(
557 : std::make_shared<as2js::compiler>(options)
558 : , as2js::as2js_exit
559 : , Catch::Matchers::ExceptionMessage(
560 : "as2js_exception: module file \"as2js_init.ajs\" not found in any of the paths \"\"."));
561 1 : SNAP_CATCH2_NAMESPACE::catch_compiler_cleanup();
562 1 : }
563 4 : CATCH_END_SECTION()
564 :
565 4 : CATCH_START_SECTION("compiler_invalid_module_files: options pointer is required")
566 : {
567 1 : init_rc();
568 :
569 2 : CATCH_REQUIRE_THROWS_MATCHES(
570 : std::make_shared<as2js::compiler>(nullptr)
571 : , as2js::invalid_data
572 : , Catch::Matchers::ExceptionMessage(
573 : "as2js_exception: the 'options' pointer cannot be null in the lexer() constructor."));
574 : }
575 4 : CATCH_END_SECTION()
576 4 : }
577 :
578 :
579 2 : CATCH_TEST_CASE("compiler_invalid_nodes", "[compiler][invalid]")
580 : {
581 2 : CATCH_START_SECTION("compiler_invalid_nodes: empty node does nothing")
582 : {
583 1 : as2js::node::pointer_t node;
584 1 : SNAP_CATCH2_NAMESPACE::test_callback tc(false, false);
585 1 : as2js::options::pointer_t options(std::make_shared<as2js::options>());
586 :
587 2 : as2js::compiler compiler(options);
588 1 : init_compiler(compiler);
589 1 : CATCH_REQUIRE(compiler.compile(node) == 0);
590 :
591 1 : tc.got_called();
592 1 : }
593 2 : CATCH_END_SECTION()
594 :
595 2 : CATCH_START_SECTION("compiler_invalid_nodes: only ROOT and PROGRAM are valid at the top")
596 : {
597 1163 : for(int i(-1); i < static_cast<int>(as2js::node_t::NODE_max); ++i)
598 : {
599 1162 : as2js::node::pointer_t node;
600 : try
601 : {
602 1162 : node = std::make_shared<as2js::node>(as2js::node_t::NODE_UNKNOWN);
603 : }
604 0 : catch(as2js::incompatible_type const &)
605 : {
606 : // many node types cannot be created
607 : // (we have gaps in our numbers)
608 : //
609 0 : continue;
610 0 : }
611 :
612 1162 : SNAP_CATCH2_NAMESPACE::test_callback tc(false, false);
613 : {
614 1162 : SNAP_CATCH2_NAMESPACE::test_callback::expected_t expected;
615 1162 : expected.f_message_level = as2js::message_level_t::MESSAGE_LEVEL_ERROR;
616 1162 : expected.f_error_code = as2js::err_code_t::AS_ERR_INTERNAL_ERROR;
617 1162 : expected.f_pos.set_filename("unknown-file");
618 1162 : expected.f_pos.set_function("unknown-func");
619 : //expected.f_pos.new_line(); -- line 1
620 1162 : expected.f_message = "the compiler::compile() function expected a root or a program node to start with.";
621 1162 : tc.f_expected.push_back(expected);
622 1162 : }
623 :
624 1162 : as2js::options::pointer_t options(std::make_shared<as2js::options>());
625 2324 : as2js::compiler compiler(options);
626 1162 : CATCH_REQUIRE(compiler.compile(node) != 0);
627 1162 : CATCH_REQUIRE(node->get_type() == as2js::node_t::NODE_UNKNOWN);
628 1162 : CATCH_REQUIRE(node->get_children_size() == 0);
629 1162 : }
630 : }
631 2 : CATCH_END_SECTION()
632 2 : }
633 :
634 :
635 1 : CATCH_TEST_CASE("compiler_class", "[compiler][class]")
636 : {
637 1 : CATCH_START_SECTION("compiler_class: verify class functionality")
638 : {
639 1 : run_tests(g_compiler_class, "compiler/class.json");
640 : }
641 1 : CATCH_END_SECTION()
642 1 : }
643 :
644 :
645 1 : CATCH_TEST_CASE("compiler_enum", "[compiler][enum]")
646 : {
647 1 : CATCH_START_SECTION("compiler_enum: verify enumerations")
648 : {
649 1 : run_tests(g_compiler_enum, "compiler/enum.json");
650 : }
651 1 : CATCH_END_SECTION()
652 1 : }
653 :
654 :
655 1 : CATCH_TEST_CASE("compiler_expression", "[compiler][expression]")
656 : {
657 1 : CATCH_START_SECTION("compiler_expression: verify expressions")
658 : {
659 1 : run_tests(g_compiler_expression, "compiler/expression.json");
660 : }
661 1 : CATCH_END_SECTION()
662 1 : }
663 :
664 :
665 :
666 : // vim: ts=4 sw=4 et
|