LCOV - code coverage report
Current view: top level - tests - catch_parser.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 202 211 95.7 %
Date: 2023-07-29 22:00:24 Functions: 19 19 100.0 %
Legend: Lines: hit not hit

          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/parser.h>
      22             : 
      23             : #include    <as2js/exception.h>
      24             : #include    <as2js/json.h>
      25             : #include    <as2js/message.h>
      26             : 
      27             : 
      28             : // self
      29             : //
      30             : #include    "catch_main.h"
      31             : 
      32             : 
      33             : // C++
      34             : //
      35             : #include    <cstring>
      36             : #include    <algorithm>
      37             : #include    <iomanip>
      38             : 
      39             : 
      40             : // C
      41             : //
      42             : #include    <unistd.h>
      43             : #include    <sys/stat.h>
      44             : 
      45             : 
      46             : // last include
      47             : //
      48             : #include    <snapdev/poison.h>
      49             : 
      50             : 
      51             : 
      52             : 
      53             : namespace
      54             : {
      55             : 
      56             : 
      57             : 
      58             : 
      59             : 
      60             : //
      61             : // JSON data used to test the parser, most of the work is in this table
      62             : // these are long JSON strings! It is actually generated using the
      63             : // json_to_string tool and the parser_data/*.json source files.
      64             : //
      65             : // Note: the top entries are arrays so we can execute programs in the
      66             : //       order we define them...
      67             : //
      68             : char const g_array[] =
      69             : #include "parser_data/array.ci"
      70             : ;
      71             : char const g_basics[] =
      72             : #include "parser_data/basics.ci"
      73             : ;
      74             : char const g_class[] =
      75             : #include "parser_data/class.ci"
      76             : ;
      77             : char const g_enum[] =
      78             : #include "parser_data/enum.ci"
      79             : ;
      80             : char const g_expression[] =
      81             : #include "parser_data/expression.ci"
      82             : ;
      83             : char const g_if[] =
      84             : #include "parser_data/if.ci"
      85             : ;
      86             : char const g_for[] =
      87             : #include "parser_data/for.ci"
      88             : ;
      89             : char const g_function[] =
      90             : #include "parser_data/function.ci"
      91             : ;
      92             : char const g_pragma[] =
      93             : #include "parser_data/pragma.ci"
      94             : ;
      95             : char const g_regex[] =
      96             : #include "parser_data/regex.ci"
      97             : ;
      98             : char const g_synchronized[] =
      99             : #include "parser_data/synchronized.ci"
     100             : ;
     101             : char const g_switch[] =
     102             : #include "parser_data/switch.ci"
     103             : ;
     104             : char const g_trycatch[] =
     105             : #include "parser_data/trycatch.ci"
     106             : ;
     107             : char const g_type[] =
     108             : #include "parser_data/type.ci"
     109             : ;
     110             : char const g_variable[] =
     111             : #include "parser_data/variable.ci"
     112             : ;
     113             : char const g_while[] =
     114             : #include "parser_data/while.ci"
     115             : ;
     116             : char const g_yield[] =
     117             : #include "parser_data/yield.ci"
     118             : ;
     119             : // TODO: specialize all those parts!
     120             : char const g_data[] =
     121             : #include "parser_data/parser.ci"
     122             : ;
     123             : 
     124             : 
     125             : 
     126             : 
     127             : 
     128             : 
     129             : 
     130             : 
     131             : // This function runs all the tests defined in the
     132             : // string 'data'
     133          18 : void run_tests(char const *data, char const *filename)
     134             : {
     135          36 :     std::string input_data(data);
     136             : 
     137          18 :     if(SNAP_CATCH2_NAMESPACE::g_save_parser_tests)
     138             :     {
     139           0 :         std::ofstream json_file;
     140           0 :         json_file.open(filename);
     141           0 :         CATCH_REQUIRE(json_file.is_open());
     142           0 :         json_file << "// To properly indent this JSON you may use http://json-indent.appspot.com/"
     143           0 :                 << std::endl << data << std::endl;
     144           0 :     }
     145             : 
     146          18 :     as2js::input_stream<std::stringstream>::pointer_t in(std::make_shared<as2js::input_stream<std::stringstream>>());
     147          18 :     *in << input_data;
     148          18 :     as2js::json::pointer_t json_data(std::make_shared<as2js::json>());
     149          36 :     as2js::json::json_value::pointer_t json(json_data->parse(in));
     150             : 
     151             :     // verify that the parser() did not fail
     152             :     //
     153          18 :     CATCH_REQUIRE(json != nullptr);
     154          18 :     CATCH_REQUIRE(json->get_type() == as2js::json::json_value::type_t::JSON_TYPE_ARRAY);
     155             : 
     156          36 :     std::string const name_string("name");
     157          36 :     std::string const program_string("program");
     158          36 :     std::string const verbose_string("verbose");
     159          36 :     std::string const slow_string("slow");
     160          36 :     std::string const result_string("result");
     161          36 :     std::string const expected_messages_string("expected messages");
     162             : 
     163          18 :     as2js::json::json_value::array_t const& array(json->get_array());
     164          18 :     size_t const max_programs(array.size());
     165         185 :     for(size_t idx(0); idx < max_programs; ++idx)
     166             :     {
     167         167 :         as2js::json::json_value::pointer_t prog_obj(array[idx]);
     168         167 :         CATCH_REQUIRE(prog_obj->get_type() == as2js::json::json_value::type_t::JSON_TYPE_OBJECT);
     169         167 :         as2js::json::json_value::object_t const & prog(prog_obj->get_object());
     170             : 
     171         167 :         bool verbose(false);
     172         167 :         as2js::json::json_value::object_t::const_iterator verbose_it(prog.find(verbose_string));
     173         167 :         if(verbose_it != prog.end())
     174             :         {
     175           5 :             verbose = verbose_it->second->get_type() == as2js::json::json_value::type_t::JSON_TYPE_TRUE;
     176             :         }
     177             : 
     178         167 :         bool slow(false);
     179         167 :         as2js::json::json_value::object_t::const_iterator slow_it(prog.find(slow_string));
     180         167 :         if(slow_it != prog.end())
     181             :         {
     182          25 :             slow = slow_it->second->get_type() == as2js::json::json_value::type_t::JSON_TYPE_TRUE;
     183             :         }
     184             : 
     185             :         // got a program, try to compile it with all the possible options
     186         167 :         as2js::json::json_value::pointer_t name(prog.find(name_string)->second);
     187         167 :         std::cout << "  -- working on \"" << name->get_string() << "\" " << (slow ? "" : "...") << std::flush;
     188             : 
     189      684199 :         for(std::size_t opt(0); opt < (1ULL << SNAP_CATCH2_NAMESPACE::g_options_size); ++opt)
     190             :         {
     191      684032 :             if(slow && ((opt + 1) % 250) == 0)
     192             :             {
     193         400 :                 std::cout << "." << std::flush;
     194             :             }
     195             : //std::cerr << "\n***\n*** OPTIONS:";
     196      684032 :             as2js::options::pointer_t options(std::make_shared<as2js::options>());
     197     8892416 :             for(std::size_t o(0); o < SNAP_CATCH2_NAMESPACE::g_options_size; ++o)
     198             :             {
     199     8208384 :                 if((opt & (1 << o)) != 0)
     200             :                 {
     201     4104192 :                     options->set_option(
     202     4104192 :                               SNAP_CATCH2_NAMESPACE::g_options[o].f_option
     203     4104192 :                             , options->get_option(SNAP_CATCH2_NAMESPACE::g_options[o].f_option)
     204     4104192 :                                 | SNAP_CATCH2_NAMESPACE::g_options[o].f_value);
     205             : //std::cerr << " " << SNAP_CATCH2_NAMESPACE::g_options[o].f_name << "=" << SNAP_CATCH2_NAMESPACE::g_options[o].f_value;
     206             :                 }
     207             :             }
     208             : //std::cerr << "\n***\n";
     209             : 
     210      684032 :             as2js::json::json_value::pointer_t program_value(prog.find(program_string)->second);
     211      684032 :             std::string program_source(program_value->get_string());
     212             : //std::cerr << "prog = [" << program_source << "]\n";
     213      684032 :             as2js::input_stream<std::stringstream>::pointer_t prog_text(std::make_shared<as2js::input_stream<std::stringstream>>());
     214      684032 :             *prog_text << program_source;
     215      684032 :             as2js::parser::pointer_t parser(std::make_shared<as2js::parser>(prog_text, options));
     216             : 
     217      684032 :             SNAP_CATCH2_NAMESPACE::test_callback tc(verbose);
     218             : 
     219      684032 :             as2js::json::json_value::object_t::const_iterator expected_msg_it(prog.find(expected_messages_string));
     220      684032 :             if(expected_msg_it != prog.end())
     221             :             {
     222             :                 // the expected messages value must be an array
     223             :                 //
     224      602112 :                 as2js::message_level_t message_level(as2js::message_level_t::MESSAGE_LEVEL_INFO);
     225      602112 :                 as2js::json::json_value::array_t const & msg_array(expected_msg_it->second->get_array());
     226      602112 :                 size_t const max_msgs(msg_array.size());
     227     2662400 :                 for(size_t j(0); j < max_msgs; ++j)
     228             :                 {
     229     2060288 :                     as2js::json::json_value::pointer_t message_value(msg_array[j]);
     230     2060288 :                     as2js::json::json_value::object_t const & message(message_value->get_object());
     231             : 
     232     2060288 :                     bool ignore_message(false);
     233             : 
     234             :                     // if the "message level" is less than "info" then we need
     235             :                     // to change the level otherwise we won't get that message
     236             :                     //
     237     2060288 :                     message_level = std::min(message_level, static_cast<as2js::message_level_t>(message.find("message level")->second->get_integer().get()));
     238             : 
     239     2060288 :                     as2js::json::json_value::object_t::const_iterator const message_options_iterator(message.find("options"));
     240     2060288 :                     if(message_options_iterator != message.end())
     241             :                     {
     242             : //{
     243             : //as2js::json::json_value::object_t::const_iterator line_it(message.find("line #"));
     244             : //if(line_it != message.end())
     245             : //{
     246             : //    int64_t lines(line_it->second->get_integer().get());
     247             : //std::cerr << "_________\nLine #" << lines << "\n";
     248             : //}
     249             : //else
     250             : //std::cerr << "_________\nLine #<undefined>\n";
     251             : //}
     252     1093632 :                         std::string const message_options(message_options_iterator->second->get_string());
     253     1093632 :                         for(char const * s(message_options.c_str()), *start(s);; ++s)
     254             :                         {
     255    27224064 :                             if(*s == ',' || *s == '|' || *s == '\0')
     256             :                             {
     257     2555904 :                                 std::string const opt_name(start, s - start);
     258     7696384 :                                 for(std::size_t o(0); o < SNAP_CATCH2_NAMESPACE::g_options_size; ++o)
     259             :                                 {
     260     7696384 :                                     if(SNAP_CATCH2_NAMESPACE::g_options[o].f_name == opt_name)
     261             :                                     {
     262      614400 :                                         ignore_message = (opt & (1 << o)) != 0;
     263             : //std::cerr << "+++ pos option [" << opt_name << "] " << ignore_message << "\n";
     264      614400 :                                         goto found_option;
     265             :                                     }
     266     7081984 :                                     else if(SNAP_CATCH2_NAMESPACE::g_options[o].f_neg_name == opt_name)
     267             :                                     {
     268      663552 :                                         ignore_message = (opt & (1 << o)) == 0;
     269             : //std::cerr << "+++ neg option [" << opt_name << "] " << ignore_message << "\n";
     270      663552 :                                         goto found_option;
     271             :                                     }
     272             :                                 }
     273           0 :                                 std::cerr << "error: Option \"" << opt_name << "\" not found in our list of valid options\n";
     274           0 :                                 CATCH_REQUIRE("option name from JSON not found in SNAP_CATCH2_NAMESPACE::g_options" == nullptr);
     275             : 
     276     1277952 : found_option:
     277     1277952 :                                 if(*s == '\0')
     278             :                                 {
     279      909312 :                                     break;
     280             :                                 }
     281      368640 :                                 if(*s == '|')
     282             :                                 {
     283      294912 :                                     if(ignore_message)
     284             :                                     {
     285      147456 :                                         break;
     286             :                                     }
     287             :                                 }
     288             :                                 else
     289             :                                 {
     290       73728 :                                     if(!ignore_message)
     291             :                                     {
     292       36864 :                                         break;
     293             :                                     }
     294             :                                 }
     295             : 
     296             :                                 // skip commas and pipes
     297             :                                 do
     298             :                                 {
     299      184320 :                                     ++s;
     300             :                                 }
     301      184320 :                                 while(*s == ',' || *s == '|');
     302      184320 :                                 start = s;
     303     1277952 :                             }
     304    26130432 :                         }
     305     1093632 :                     }
     306             : 
     307     2060288 :                     if(!ignore_message)
     308             :                     {
     309     1458176 :                         SNAP_CATCH2_NAMESPACE::test_callback::expected_t expected;
     310     1458176 :                         expected.f_message_level = static_cast<as2js::message_level_t>(message.find("message level")->second->get_integer().get());
     311     1458176 :                         expected.f_error_code = SNAP_CATCH2_NAMESPACE::str_to_error_code(message.find("error code")->second->get_string());
     312     1458176 :                         expected.f_pos.set_filename("unknown-file");
     313     1458176 :                         as2js::json::json_value::object_t::const_iterator func_it(message.find("function name"));
     314     1458176 :                         if(func_it == message.end())
     315             :                         {
     316     1458176 :                             expected.f_pos.set_function("unknown-func");
     317             :                         }
     318             :                         else
     319             :                         {
     320           0 :                             expected.f_pos.set_function(func_it->second->get_string());
     321             :                         }
     322     1458176 :                         as2js::json::json_value::object_t::const_iterator line_it(message.find("line #"));
     323     1458176 :                         if(line_it != message.end())
     324             :                         {
     325     1458176 :                             std::int64_t lines(line_it->second->get_integer().get());
     326    11160576 :                             for(std::int64_t l(1); l < lines; ++l)
     327             :                             {
     328     9702400 :                                 expected.f_pos.new_line();
     329             :                             }
     330             :                         }
     331     1458176 :                         expected.f_message = message.find("message")->second->get_string();
     332             : //std::cerr << "    --- message [" << expected.f_message << "]\n";
     333     1458176 :                         tc.f_expected.push_back(expected);
     334     1458176 :                     }
     335     2060288 :                 }
     336             : 
     337             :                 // the default message level is INFO, don't change if we have
     338             :                 // a higher level here; however, if we have a lower level,
     339             :                 // change the message level in the as2js library
     340             :                 //
     341      602112 :                 if(message_level < as2js::message_level_t::MESSAGE_LEVEL_INFO)
     342             :                 {
     343        8192 :                     as2js::set_message_level(message_level);
     344             :                 }
     345             :             }
     346             : 
     347     1368064 :             as2js::node::pointer_t root(parser->parse());
     348             : 
     349             :             // the result is object which can have children
     350             :             // which are represented by an array of objects
     351             :             //
     352      684032 :             SNAP_CATCH2_NAMESPACE::verify_parser_result(result_string, prog.find(result_string)->second, root, verbose, false);
     353             : 
     354      684032 :             tc.got_called();
     355             : 
     356      684032 :             set_message_level(static_cast<as2js::message_level_t>(as2js::message_level_t::MESSAGE_LEVEL_INFO));
     357      684032 :         }
     358             : 
     359         167 :         std::cout << " OK\n";
     360         167 :     }
     361             : 
     362          18 :     std::cout << "\n";
     363          36 : }
     364             : 
     365             : 
     366             : }
     367             : // no name namespace
     368             : 
     369             : 
     370             : 
     371             : 
     372             : 
     373           1 : CATCH_TEST_CASE("parser_array", "[parser][data]")
     374             : {
     375           1 :     CATCH_START_SECTION("parser_array: verify JavaScript arrays")
     376             :     {
     377           1 :         run_tests(g_array, "test_parser_array.json");
     378             :     }
     379           1 :     CATCH_END_SECTION()
     380           1 : }
     381             : 
     382             : 
     383           1 : CATCH_TEST_CASE("parser_basics", "[parser]")
     384             : {
     385           1 :     CATCH_START_SECTION("parser_basics: verify JavaScript basic elements")
     386             :     {
     387           1 :         run_tests(g_basics, "test_parser_basics.json");
     388             :     }
     389           1 :     CATCH_END_SECTION()
     390           1 : }
     391             : 
     392             : 
     393           1 : CATCH_TEST_CASE("parser_class", "[parser][instruction]")
     394             : {
     395           1 :     CATCH_START_SECTION("parser_class: verify class extension")
     396             :     {
     397           1 :         run_tests(g_class, "test_parser_class.json");
     398             :     }
     399           1 :     CATCH_END_SECTION()
     400           1 : }
     401             : 
     402             : 
     403           1 : CATCH_TEST_CASE("parser_enum", "[parser][instruction]")
     404             : {
     405           1 :     CATCH_START_SECTION("parser_enum: verify enum extension")
     406             :     {
     407           1 :         run_tests(g_enum, "test_parser_enum.json");
     408             :     }
     409           1 :     CATCH_END_SECTION()
     410           1 : }
     411             : 
     412             : 
     413           1 : CATCH_TEST_CASE("parser_expression", "[parser][expression]")
     414             : {
     415           1 :     CATCH_START_SECTION("parser_expression: verify special expressions")
     416             :     {
     417           1 :         run_tests(g_expression, "test_parser_expression.json");
     418             :     }
     419           1 :     CATCH_END_SECTION()
     420           1 : }
     421             : 
     422             : 
     423           1 : CATCH_TEST_CASE("parser_for", "[parser][instruction]")
     424             : {
     425           1 :     CATCH_START_SECTION("parser_for: verify JavaScript for loops")
     426             :     {
     427           1 :         run_tests(g_for, "test_parser_for.json");
     428             :     }
     429           1 :     CATCH_END_SECTION()
     430           1 : }
     431             : 
     432             : 
     433           1 : CATCH_TEST_CASE("parser_function", "[parser][function]")
     434             : {
     435           1 :     CATCH_START_SECTION("parser_function: verify JavaScript functions")
     436             :     {
     437           1 :         run_tests(g_function, "test_parser_function.json");
     438             :     }
     439           1 :     CATCH_END_SECTION()
     440           1 : }
     441             : 
     442             : 
     443           1 : CATCH_TEST_CASE("parser_if", "[parser][instruction]")
     444             : {
     445           1 :     CATCH_START_SECTION("parser_if: verify JavaScript if()/else")
     446             :     {
     447           1 :         run_tests(g_if, "test_parser_if.json");
     448             :     }
     449           1 :     CATCH_END_SECTION()
     450           1 : }
     451             : 
     452             : 
     453           1 : CATCH_TEST_CASE("parser_pragma", "[parser][instruction]")
     454             : {
     455           1 :     CATCH_START_SECTION("parser_pragma: verify pragma extension")
     456             :     {
     457           1 :         run_tests(g_pragma, "test_parser_pragma.json");
     458             :     }
     459           1 :     CATCH_END_SECTION()
     460           1 : }
     461             : 
     462             : 
     463           1 : CATCH_TEST_CASE("parser_regex", "[parser][expression]")
     464             : {
     465           1 :     CATCH_START_SECTION("parser_regex: verify regular expressions")
     466             :     {
     467           1 :         run_tests(g_regex, "test_parser_regex.json");
     468             :     }
     469           1 :     CATCH_END_SECTION()
     470           1 : }
     471             : 
     472             : 
     473           1 : CATCH_TEST_CASE("parser_synchronized", "[parser][synchronized]")
     474             : {
     475           1 :     CATCH_START_SECTION("parser_synchronized: verify synchronized extension")
     476             :     {
     477           1 :         run_tests(g_synchronized, "test_parser_synchronized.json");
     478             :     }
     479           1 :     CATCH_END_SECTION()
     480           1 : }
     481             : 
     482             : 
     483           1 : CATCH_TEST_CASE("parser_switch", "[parser][instruction]")
     484             : {
     485           1 :     CATCH_START_SECTION("parser_switch: verify JavaScript switch")
     486             :     {
     487           1 :         run_tests(g_switch, "test_parser_switch.json");
     488             :     }
     489           1 :     CATCH_END_SECTION()
     490           1 : }
     491             : 
     492             : 
     493           1 : CATCH_TEST_CASE("parser_try_catch", "[parser][instruction]")
     494             : {
     495           1 :     CATCH_START_SECTION("parser_try_catch: verify JavaScript exception handling")
     496             :     {
     497           1 :         run_tests(g_trycatch, "test_parser_trycatch.json");
     498             :     }
     499           1 :     CATCH_END_SECTION()
     500           1 : }
     501             : 
     502             : 
     503           1 : CATCH_TEST_CASE("parser_type", "[parser][type]")
     504             : {
     505           1 :     CATCH_START_SECTION("parser_type: verify type extensions")
     506             :     {
     507           1 :         run_tests(g_type, "test_parser_type.json");
     508             :     }
     509           1 :     CATCH_END_SECTION()
     510           1 : }
     511             : 
     512             : 
     513           1 : CATCH_TEST_CASE("parser_variable", "[parser][variable]")
     514             : {
     515           1 :     CATCH_START_SECTION("parser_variable: verify JavaScript variable")
     516             :     {
     517           1 :         run_tests(g_variable, "test_parser_variable.json");
     518             :     }
     519           1 :     CATCH_END_SECTION()
     520           1 : }
     521             : 
     522             : 
     523           1 : CATCH_TEST_CASE("parser_while", "[parser][instruction]")
     524             : {
     525           1 :     CATCH_START_SECTION("parser_while: verify JavaScript while")
     526             :     {
     527           1 :         run_tests(g_while, "test_parser_while.json");
     528             :     }
     529           1 :     CATCH_END_SECTION()
     530           1 : }
     531             : 
     532             : 
     533           1 : CATCH_TEST_CASE("parser_yield", "[parser][instruction]")
     534             : {
     535           1 :     CATCH_START_SECTION("parser_yield: verify JavaScript yield")
     536             :     {
     537           1 :         run_tests(g_yield, "test_parser_yield.json");
     538             :     }
     539           1 :     CATCH_END_SECTION()
     540           1 : }
     541             : 
     542             : 
     543             : // TODO: remove once everything is "properly" typed/moved to separate files
     544           1 : CATCH_TEST_CASE("parser_parser", "[parser][mixed]")
     545             : {
     546           1 :     CATCH_START_SECTION("parser_parser: verify other parser functionality (still mixed)")
     547             :     {
     548           1 :         run_tests(g_data, "test_parser.json");
     549             :     }
     550           1 :     CATCH_END_SECTION()
     551           1 : }
     552             : 
     553             : 
     554             : 
     555             : 
     556             : 
     557             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.14