LCOV - code coverage report
Current view: top level - tests - catch_pbql_parser.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 99.7 % 302 301
Test Date: 2025-06-19 11:28:46 Functions: 100.0 % 4 4
Legend: Lines: hit not hit

            Line data    Source code
       1              : // Copyright (c) 2019-2025  Made to Order Software Corp.  All Rights Reserved
       2              : //
       3              : // https://snapwebsites.org/project/prinbee
       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              : // prinbee
      20              : //
      21              : #include    <prinbee/pbql/parser.h>
      22              : 
      23              : #include    <prinbee/exception.h>
      24              : 
      25              : 
      26              : // self
      27              : //
      28              : #include    "catch_main.h"
      29              : 
      30              : 
      31              : // snaplogger
      32              : //
      33              : #include    <snaplogger/message.h>
      34              : 
      35              : 
      36              : // snapdev
      37              : //
      38              : #include    <snapdev/not_reached.h>
      39              : #include    <snapdev/string_replace_many.h>
      40              : #include    <snapdev/to_lower.h>
      41              : 
      42              : 
      43              : // C++
      44              : //
      45              : //#include    <bitset>
      46              : //#include    <fstream>
      47              : //#include    <iomanip>
      48              : 
      49              : 
      50              : // C
      51              : //
      52              : //#include    <sys/stat.h>
      53              : //#include    <sys/types.h>
      54              : 
      55              : 
      56              : // last include
      57              : //
      58              : #include    <snapdev/poison.h>
      59              : 
      60              : 
      61              : 
      62              : namespace
      63              : {
      64              : 
      65              : 
      66              : 
      67          112 : std::string escape_quotes(std::string const & s)
      68              : {
      69              :     // double quotes which is the way to escape quotes in SQL
      70              :     //
      71          448 :     return snapdev::string_replace_many(s, {{"'", "''"}});
      72          112 : }
      73              : 
      74              : 
      75          256 : char const * optional_equal()
      76              : {
      77          256 :     switch(rand() % 5)
      78              :     {
      79           49 :     case 0:
      80           49 :         return " ";
      81              : 
      82           41 :     case 1:
      83           41 :         return "=";
      84              : 
      85           53 :     case 2:
      86           53 :         return " =";
      87              : 
      88           58 :     case 3:
      89           58 :         return "= ";
      90              : 
      91           55 :     case 4:
      92           55 :         return " = ";
      93              : 
      94              :     }
      95            0 :     snapdev::NOT_REACHED();
      96              : }
      97              : 
      98              : 
      99              : 
     100              : } // no name namespace
     101              : 
     102              : 
     103              : 
     104            2 : CATCH_TEST_CASE("parser", "[parser][pbql]")
     105              : {
     106            4 :     CATCH_START_SECTION("parser: begin + select + commit/rollback")
     107              :     {
     108            5 :         for(int state(0); state < 4; ++state) // COMMIT / COMMIT + IF / ROLLBACK / ROLLBACK + IF
     109              :         {
     110           16 :             for(int work(0); work < 3; ++work)
     111              :             {
     112           96 :                 for(int type(0); type < 7; ++type)
     113              :                 {
     114              :                     // BEGIN
     115          252 :                     std::string script("BEGIN");
     116              : 
     117              :                     // WORK/TRANSACTION
     118           84 :                     if(work == 1)
     119              :                     {
     120           28 :                         script += " WORK";
     121              :                     }
     122           56 :                     else if(work == 2)
     123              :                     {
     124           28 :                         script += " TRANSACTION";
     125              :                     }
     126              : 
     127              :                     // ON
     128           84 :                     if(type >= 3)
     129              :                     {
     130           48 :                         script += " ON";
     131              :                     }
     132              : 
     133              :                     // SCHEMA/DATA
     134           84 :                     prinbee::pbql::transaction_t expected_transaction(prinbee::pbql::transaction_t::TRANSACTION_UNDEFINED);
     135           84 :                     if(type == 1 || type == 3 || type == 5)
     136              :                     {
     137           36 :                         script += " SCHEMA";
     138           36 :                         expected_transaction = prinbee::pbql::transaction_t::TRANSACTION_SCHEMA;
     139              :                     }
     140           48 :                     else if(type == 2 || type == 4 || type == 6)
     141              :                     {
     142           36 :                         script += " DATA";
     143           36 :                         expected_transaction = prinbee::pbql::transaction_t::TRANSACTION_DATA;
     144              :                     }
     145              : 
     146              :                     // no IF for a BEGIN, type 5 and 6 are not use here
     147              : 
     148           84 :                     script += ";\n";
     149              : 
     150              :                     // COMMIT or ROLLBACK
     151           84 :                     script += state < 2 ? "COMMIT" : "ROLLBACK";
     152              : 
     153              :                     // WORK/TRANSACTION (the test would be better if the COMMIT/ROLLBACK would use a different set of parameters than the BEGIN...)
     154           84 :                     if(work == 1)
     155              :                     {
     156           28 :                         script += " WORK";
     157              :                     }
     158           56 :                     else if(work == 2)
     159              :                     {
     160           28 :                         script += " TRANSACTION";
     161              :                     }
     162              : 
     163              :                     // ON
     164           84 :                     if(type >= 3)
     165              :                     {
     166           48 :                         script += " ON";
     167              :                     }
     168              : 
     169              :                     // SCHEMA/DATA
     170              :                     //prinbee::pbql::transaction_t expected_transaction(prinbee::pbql::transaction_t::TRANSACTION_UNDEFINED);
     171           84 :                     if(type == 1 || type == 3 || type == 5)
     172              :                     {
     173           36 :                         script += " SCHEMA";
     174              :                         //expected_transaction = prinbee::pbql::transaction_t::TRANSACTION_SCHEMA;
     175              :                     }
     176           48 :                     else if(type == 2 || type == 4 || type == 6)
     177              :                     {
     178           36 :                         script += " DATA";
     179              :                         //expected_transaction = prinbee::pbql::transaction_t::TRANSACTION_DATA;
     180              :                     }
     181              : 
     182              :                     // IF <condition>
     183           84 :                     if(type == 5 || type == 6)
     184              :                     {
     185           24 :                         script += " IF a > b";
     186           24 :                         if(type == 6)
     187              :                         {
     188           12 :                             script += " OTHERWISE ";
     189           12 :                             script += state >= 2 ? "COMMIT" : "ROLLBACK"; // test flip from above
     190              :                         }
     191              :                     }
     192              : 
     193           84 :                     script += ";\n";
     194              : 
     195          168 : SNAP_LOG_WARNING << "script [" << script << "]" << SNAP_LOG_SEND;
     196              : 
     197           84 :                     prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
     198           84 :                     lexer->set_input(std::make_shared<prinbee::pbql::input>(script, "begin-test.pbql"));
     199           84 :                     prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
     200           84 :                     prinbee::pbql::command::vector_t const & commands(parser->parse());
     201              : 
     202           84 :                     CATCH_REQUIRE(commands.size() == 2);
     203              : 
     204              :                     // BEGIN
     205           84 :                     CATCH_REQUIRE(commands[0]->get_command() == prinbee::pbql::command_t::COMMAND_BEGIN);
     206              :                     // SCHEMA/DATA
     207           84 :                     CATCH_REQUIRE(commands[0]->is_defined_as(prinbee::pbql::param_t::PARAM_TYPE) == prinbee::pbql::param_type_t::PARAM_TYPE_INT64);
     208           84 :                     CATCH_REQUIRE(commands[0]->get_int64(prinbee::pbql::param_t::PARAM_TYPE) == static_cast<std::int64_t>(expected_transaction));
     209              : 
     210              :                     // COMMIT / ROLLBACK
     211           84 :                     CATCH_REQUIRE(commands[1]->get_command() == (state < 2 ? prinbee::pbql::command_t::COMMAND_COMMIT : prinbee::pbql::command_t::COMMAND_ROLLBACK));
     212              :                     // SCHEMA/DATA
     213           84 :                     CATCH_REQUIRE(commands[1]->is_defined_as(prinbee::pbql::param_t::PARAM_TYPE) == prinbee::pbql::param_type_t::PARAM_TYPE_INT64);
     214           84 :                     CATCH_REQUIRE(commands[1]->get_int64(prinbee::pbql::param_t::PARAM_TYPE) == static_cast<std::int64_t>(expected_transaction));
     215           84 :                     if(type == 5 || type == 6)
     216              :                     {
     217           24 :                         CATCH_REQUIRE(commands[1]->is_defined_as(prinbee::pbql::param_t::PARAM_CONDITION) == prinbee::pbql::param_type_t::PARAM_TYPE_STRING);
     218           24 :                         CATCH_REQUIRE(commands[1]->get_string(prinbee::pbql::param_t::PARAM_CONDITION) == "a>b");
     219           24 :                     }
     220              :                     else
     221              :                     {
     222           60 :                         CATCH_REQUIRE(commands[1]->is_defined_as(prinbee::pbql::param_t::PARAM_CONDITION) == prinbee::pbql::param_type_t::PARAM_TYPE_UNKNOWN);
     223              :                     }
     224           84 :                 }
     225              :             }
     226              :         }
     227              :     }
     228            3 :     CATCH_END_SECTION()
     229              : 
     230            4 :     CATCH_START_SECTION("parser: create context")
     231              :     {
     232            1 :         int counter(1);
     233            3 :         for(int exists(0); exists < 2; ++exists)
     234              :         {
     235           10 :             for(int using_path(0); using_path < 4; ++using_path)
     236              :             {
     237           64 :                 for(int owner(0); owner < 7; ++owner)
     238              :                 {
     239          224 :                     for(int comment(0); comment < 3; ++comment)
     240              :                     {
     241              :                         // CREATE CONTEXT
     242          504 :                         std::string script("CREATE CONTEXT ");
     243              : 
     244              :                         // IF NOT EXISTS
     245          168 :                         if(exists != 0)
     246              :                         {
     247           84 :                             script += "IF NOT EXISTS ";
     248              :                         }
     249              : 
     250              :                         // <context-name>
     251          168 :                         std::string context_name(SNAP_CATCH2_NAMESPACE::random_string(1, 97, SNAP_CATCH2_NAMESPACE::character_t::CHARACTER_LABEL));
     252          168 :                         context_name += '_';
     253          168 :                         context_name += std::to_string(counter);
     254          168 :                         script += context_name;
     255              : 
     256              :                         // USING '<context-path>'
     257          168 :                         std::string context_path;
     258          420 :                         for(int segment(0); segment < using_path; ++segment)
     259              :                         {
     260          252 :                             if(!context_path.empty())
     261              :                             {
     262          126 :                                 context_path += '/';
     263              :                             }
     264          252 :                             context_path += SNAP_CATCH2_NAMESPACE::random_string(1, 100, SNAP_CATCH2_NAMESPACE::character_t::CHARACTER_LABEL);
     265              :                         }
     266          168 :                         if(!context_path.empty())
     267              :                         {
     268          126 :                             script += " USING '";
     269          126 :                             script += context_path;
     270          126 :                             script += '\'';
     271              :                         }
     272              : 
     273              :                         // WITH ( ... )
     274          168 :                         std::string ownership;
     275          168 :                         std::string group_member;
     276          168 :                         std::string description;
     277          168 :                         if(owner != 0 || comment != 0)
     278              :                         {
     279          160 :                             script += " WITH (";
     280          160 :                             bool quoted_owner(rand() & 1);
     281          160 :                             int order((rand() & 1) + 1);
     282          160 :                             char const * sep("");
     283          480 :                             for(int with(0); with < 2; ++with, order ^= 3)
     284              :                             {
     285          320 :                                 if((order & 1) != 0)
     286              :                                 {
     287          160 :                                     if(owner != 0)
     288              :                                     {
     289              :                                         // WITH ( OWNER )
     290          144 :                                         script += sep;
     291          144 :                                         script += "OWNER";
     292          144 :                                         script += optional_equal();
     293          144 :                                         if(quoted_owner)
     294              :                                         {
     295           68 :                                             script += '\'';
     296              :                                         }
     297          144 :                                         if((owner & 1) == 0)
     298              :                                         {
     299           72 :                                             ownership = SNAP_CATCH2_NAMESPACE::random_string(1, 32, SNAP_CATCH2_NAMESPACE::character_t::CHARACTER_LABEL);
     300              :                                         }
     301              :                                         else
     302              :                                         {
     303           72 :                                             ownership = std::to_string(rand() & 0x7fff);
     304              :                                         }
     305          144 :                                         script += ownership;
     306          144 :                                         if(owner < 5)
     307              :                                         {
     308           96 :                                             if((owner & 2) == 0)
     309              :                                             {
     310           48 :                                                 group_member = SNAP_CATCH2_NAMESPACE::random_string(1, 32, SNAP_CATCH2_NAMESPACE::character_t::CHARACTER_LABEL);
     311              :                                             }
     312              :                                             else
     313              :                                             {
     314           48 :                                                 group_member = std::to_string(rand() & 0x7fff);
     315              :                                             }
     316           96 :                                             script += ':';
     317           96 :                                             script += group_member;
     318              :                                         }
     319          144 :                                         if(quoted_owner)
     320              :                                         {
     321           68 :                                             script += '\'';
     322              :                                         }
     323          144 :                                         sep = rand() & 1 ? ", " : ",";
     324              :                                     }
     325              :                                 }
     326          320 :                                 if((order & 2) != 0)
     327              :                                 {
     328          160 :                                     if(comment != 0)
     329              :                                     {
     330              :                                         // WITH ( COMMENT )
     331          112 :                                         description = SNAP_CATCH2_NAMESPACE::random_string(1, 500);
     332          112 :                                         script += sep;
     333          112 :                                         script += "COMMENT";
     334          112 :                                         script += optional_equal();
     335          112 :                                         script += '\'';
     336          112 :                                         script += escape_quotes(description);
     337          112 :                                         script += '\'';
     338          112 :                                         sep = rand() & 1 ? ", " : ",";
     339              :                                     }
     340              :                                 }
     341              :                             }
     342          160 :                             script += ')';
     343              :                         }
     344          168 :                         script += ';';
     345              : 
     346              : //SNAP_LOG_WARNING << "script [" << script << "]" << SNAP_LOG_SEND;
     347              : 
     348          168 :                         prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
     349          168 :                         lexer->set_input(std::make_shared<prinbee::pbql::input>(script, "create-context-test.pbql"));
     350          168 :                         prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
     351          168 :                         prinbee::pbql::command::vector_t const & commands(parser->parse());
     352              : 
     353          168 :                         CATCH_REQUIRE(commands.size() == 1);
     354              :                         // CREATE CONTEXT
     355          168 :                         CATCH_REQUIRE(commands[0]->get_command() == prinbee::pbql::command_t::COMMAND_CREATE_CONTEXT);
     356              :                         // [IF NOT EXISTS]
     357          168 :                         CATCH_REQUIRE(commands[0]->is_defined_as(prinbee::pbql::param_t::PARAM_IF_EXISTS) == prinbee::pbql::param_type_t::PARAM_TYPE_BOOL);
     358          168 :                         CATCH_REQUIRE(commands[0]->get_bool(prinbee::pbql::param_t::PARAM_IF_EXISTS) == (exists == 0));
     359              :                         // <context-name>
     360          168 :                         CATCH_REQUIRE(commands[0]->is_defined_as(prinbee::pbql::param_t::PARAM_NAME) == prinbee::pbql::param_type_t::PARAM_TYPE_STRING);
     361          168 :                         CATCH_REQUIRE(commands[0]->get_string(prinbee::pbql::param_t::PARAM_NAME) == snapdev::to_lower(context_name));
     362              :                         // [USING <context-path>]
     363          168 :                         CATCH_REQUIRE(commands[0]->is_defined_as(prinbee::pbql::param_t::PARAM_PATH) == prinbee::pbql::param_type_t::PARAM_TYPE_STRING);
     364          168 :                         if(context_path.empty())
     365              :                         {
     366           42 :                             CATCH_REQUIRE(commands[0]->get_string(prinbee::pbql::param_t::PARAM_PATH) == snapdev::to_lower(context_name));
     367              :                         }
     368              :                         else
     369              :                         {
     370          126 :                             CATCH_REQUIRE(commands[0]->get_string(prinbee::pbql::param_t::PARAM_PATH) == snapdev::to_lower(context_path));
     371              :                         }
     372              :                         // WITH ( OWNER [']<user>[:<group>]['] )
     373          168 :                         CATCH_REQUIRE(commands[0]->is_defined_as(prinbee::pbql::param_t::PARAM_USER) == prinbee::pbql::param_type_t::PARAM_TYPE_STRING);
     374          168 :                         CATCH_REQUIRE(commands[0]->get_string(prinbee::pbql::param_t::PARAM_USER) == ownership);
     375          168 :                         CATCH_REQUIRE(commands[0]->is_defined_as(prinbee::pbql::param_t::PARAM_GROUP) == prinbee::pbql::param_type_t::PARAM_TYPE_STRING);
     376          168 :                         CATCH_REQUIRE(commands[0]->get_string(prinbee::pbql::param_t::PARAM_GROUP) == group_member);
     377              :                         // WITH ( COMMENT '<description>' )
     378          168 :                         CATCH_REQUIRE(commands[0]->is_defined_as(prinbee::pbql::param_t::PARAM_DESCRIPTION) == prinbee::pbql::param_type_t::PARAM_TYPE_STRING);
     379          168 :                         CATCH_REQUIRE(commands[0]->get_string(prinbee::pbql::param_t::PARAM_DESCRIPTION) == description);
     380              : 
     381              :                         // to track the number of attempts in the context name
     382              :                         //
     383          168 :                         ++counter;
     384          168 :                     }
     385              :                 }
     386              :             }
     387              :         }
     388              :     }
     389            3 :     CATCH_END_SECTION()
     390            2 : }
     391              : 
     392              : 
     393            3 : CATCH_TEST_CASE("parser_error", "[parser][pbql][error]")
     394              : {
     395            5 :     CATCH_START_SECTION("parser_error: missing lexer")
     396              :     {
     397            1 :         prinbee::pbql::lexer::pointer_t lexer;
     398            4 :         CATCH_REQUIRE_THROWS_MATCHES(
     399              :                   std::make_shared<prinbee::pbql::parser>(lexer)
     400              :                 , prinbee::logic_error
     401              :                 , Catch::Matchers::ExceptionMessage(
     402              :                           "logic_error: lexer missing."));
     403            1 :     }
     404            4 :     CATCH_END_SECTION()
     405              : 
     406            5 :     CATCH_START_SECTION("parser_error: create context errors")
     407              :     {
     408              :         {
     409              :             // CREATE CONTEXT <identifier>
     410            3 :             std::string script("CREATE CONTEXT 123;");
     411              : 
     412            1 :             prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
     413            1 :             lexer->set_input(std::make_shared<prinbee::pbql::input>(script, "create-context-test.pbql"));
     414            1 :             prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
     415              : 
     416            3 :             CATCH_REQUIRE_THROWS_MATCHES(
     417              :                   parser->parse()
     418              :                 , prinbee::invalid_token
     419              :                 , Catch::Matchers::ExceptionMessage(
     420              :                           "prinbee_exception: create-context-test.pbql:1:16: expected an identifier after CREATE CONTEXT."));
     421            1 :         }
     422              : 
     423              :         {
     424              :             // CREATE CONTEXT IF <NOT>
     425            3 :             std::string script("CREATE CONTEXT IF FOO;");
     426              : 
     427            1 :             prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
     428            1 :             lexer->set_input(std::make_shared<prinbee::pbql::input>(script, "create-context-test.pbql"));
     429            1 :             prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
     430              : 
     431            3 :             CATCH_REQUIRE_THROWS_MATCHES(
     432              :                   parser->parse()
     433              :                 , prinbee::invalid_token
     434              :                 , Catch::Matchers::ExceptionMessage(
     435              :                           "prinbee_exception: create-context-test.pbql:1:19: expected the NOT identifier after CREATE CONTEXT IF, not \"FOO\"."));
     436            1 :         }
     437              : 
     438              :         {
     439              :             // CREATE CONTEXT IF NOT EXIST<S>
     440            3 :             std::string script("CREATE CONTEXT IF NOT EXIST;");
     441              : 
     442            1 :             prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
     443            1 :             lexer->set_input(std::make_shared<prinbee::pbql::input>(script, "create-context-test.pbql"));
     444            1 :             prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
     445              : 
     446            3 :             CATCH_REQUIRE_THROWS_MATCHES(
     447              :                   parser->parse()
     448              :                 , prinbee::invalid_token
     449              :                 , Catch::Matchers::ExceptionMessage(
     450              :                           "prinbee_exception: create-context-test.pbql:1:23: expected the EXISTS identifier after CREATE CONTEXT IF NOT, not \"EXIST\"."));
     451            1 :         }
     452              : 
     453              :         {
     454              :             // CREATE CONTEXT IF NOT EXISTS <identifier>
     455            3 :             std::string script("CREATE CONTEXT IF NOT EXISTS 123;");
     456              : 
     457            1 :             prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
     458            1 :             lexer->set_input(std::make_shared<prinbee::pbql::input>(script, "create-context-test.pbql"));
     459            1 :             prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
     460              : 
     461            3 :             CATCH_REQUIRE_THROWS_MATCHES(
     462              :                   parser->parse()
     463              :                 , prinbee::invalid_token
     464              :                 , Catch::Matchers::ExceptionMessage(
     465              :                           "prinbee_exception: create-context-test.pbql:1:30: expected a IDENTIFIER after CREATE CONTEXT IF NOT EXISTS, not a INTEGER."));
     466            1 :         }
     467              : 
     468              :         {
     469              :             // CREATE CONTEXT my_context USING 123;
     470            3 :             std::string script("CREATE CONTEXT my_context USING 123;");
     471              : 
     472            1 :             prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
     473            1 :             lexer->set_input(std::make_shared<prinbee::pbql::input>(script, "create-context-test.pbql"));
     474            1 :             prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
     475              : 
     476            3 :             CATCH_REQUIRE_THROWS_MATCHES(
     477              :                   parser->parse()
     478              :                 , prinbee::invalid_token
     479              :                 , Catch::Matchers::ExceptionMessage(
     480              :                           "prinbee_exception: create-context-test.pbql:1:33: expected a path after the USING keyword of CREATE CONTEXT."));
     481            1 :         }
     482              : 
     483              :         {
     484              :             // CREATE CONTEXT my_context USING 'path' <USING>;
     485            3 :             std::string script("CREATE CONTEXT my_context USING 'path' USING;");
     486              : 
     487            1 :             prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
     488            1 :             lexer->set_input(std::make_shared<prinbee::pbql::input>(script, "create-context-test.pbql"));
     489            1 :             prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
     490              : 
     491            3 :             CATCH_REQUIRE_THROWS_MATCHES(
     492              :                   parser->parse()
     493              :                 , prinbee::invalid_token
     494              :                 , Catch::Matchers::ExceptionMessage(
     495              :                           "prinbee_exception: create-context-test.pbql:1:40: USING keyword found twice after CREATE CONTEXT."));
     496            1 :         }
     497              : 
     498              :         {
     499              :             // CREATE CONTEXT my_context USING '<empty>';
     500            3 :             std::string script("CREATE CONTEXT my_context USING '';");
     501              : 
     502            1 :             prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
     503            1 :             lexer->set_input(std::make_shared<prinbee::pbql::input>(script, "create-context-test.pbql"));
     504            1 :             prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
     505              : 
     506            3 :             CATCH_REQUIRE_THROWS_MATCHES(
     507              :                   parser->parse()
     508              :                 , prinbee::invalid_token
     509              :                 , Catch::Matchers::ExceptionMessage(
     510              :                           "prinbee_exception: create-context-test.pbql:1:33: expected a non-empty path after the USING keyword of CREATE CONTEXT."));
     511            1 :         }
     512              : 
     513              :         {
     514              :             // CREATE CONTEXT my_context WITH <comment>;
     515            3 :             std::string script("CREATE CONTEXT my_context WITH comment;");
     516              : 
     517            1 :             prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
     518            1 :             lexer->set_input(std::make_shared<prinbee::pbql::input>(script, "create-context-test.pbql"));
     519            1 :             prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
     520              : 
     521            3 :             CATCH_REQUIRE_THROWS_MATCHES(
     522              :                   parser->parse()
     523              :                 , prinbee::invalid_token
     524              :                 , Catch::Matchers::ExceptionMessage(
     525              :                           "prinbee_exception: create-context-test.pbql:1:32: WITH feature definitions must be defined between parenthesis, '(' missing in CREATE CONTEXT."));
     526            1 :         }
     527              : 
     528              :         {
     529              :             // CREATE CONTEXT my_context WITH ( <123>;
     530            3 :             std::string script("CREATE CONTEXT my_context WITH ( 123;");
     531              : 
     532            1 :             prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
     533            1 :             lexer->set_input(std::make_shared<prinbee::pbql::input>(script, "create-context-test.pbql"));
     534            1 :             prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
     535              : 
     536            3 :             CATCH_REQUIRE_THROWS_MATCHES(
     537              :                   parser->parse()
     538              :                 , prinbee::invalid_token
     539              :                 , Catch::Matchers::ExceptionMessage(
     540              :                           "prinbee_exception: create-context-test.pbql:1:34: WITH feature definitions must be named using an identifier in CREATE CONTEXT."));
     541            1 :         }
     542              : 
     543              :         {
     544              :             // CREATE CONTEXT my_context WITH ( OWNER name:'group';
     545            3 :             std::string script("CREATE CONTEXT my_context WITH ( OWNER name:'group';");
     546              : 
     547            1 :             prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
     548            1 :             lexer->set_input(std::make_shared<prinbee::pbql::input>(script, "create-context-test.pbql"));
     549            1 :             prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
     550              : 
     551            3 :             CATCH_REQUIRE_THROWS_MATCHES(
     552              :                   parser->parse()
     553              :                 , prinbee::invalid_token
     554              :                 , Catch::Matchers::ExceptionMessage(
     555              :                           "prinbee_exception: create-context-test.pbql:1:46: "
     556              :                           "expected a group name after ':' in CREATE CONTEXT ... WITH ( OWNER <user>:<group> ), not a STRING."));
     557            1 :         }
     558              : 
     559              :         {
     560              :             // CREATE CONTEXT my_context WITH ( OWNER name:group, OWNER;
     561            3 :             std::string script("CREATE CONTEXT my_context WITH ( OWNER name:group, OWNER;");
     562              : 
     563            1 :             prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
     564            1 :             lexer->set_input(std::make_shared<prinbee::pbql::input>(script, "create-context-test.pbql"));
     565            1 :             prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
     566              : 
     567            3 :             CATCH_REQUIRE_THROWS_MATCHES(
     568              :                   parser->parse()
     569              :                 , prinbee::invalid_token
     570              :                 , Catch::Matchers::ExceptionMessage(
     571              :                           "prinbee_exception: create-context-test.pbql:1:58: "
     572              :                           "WITH OWNER found twice after CREATE CONTEXT."));
     573            1 :         }
     574              : 
     575              :         {
     576              :             // CREATE CONTEXT my_context WITH ( OWNER = 3.5;
     577            3 :             std::string script("CREATE CONTEXT my_context WITH ( OWNER = 3.5;");
     578              : 
     579            1 :             prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
     580            1 :             lexer->set_input(std::make_shared<prinbee::pbql::input>(script, "create-context-test.pbql"));
     581            1 :             prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
     582              : 
     583            3 :             CATCH_REQUIRE_THROWS_MATCHES(
     584              :                   parser->parse()
     585              :                 , prinbee::invalid_token
     586              :                 , Catch::Matchers::ExceptionMessage(
     587              :                           "prinbee_exception: create-context-test.pbql:1:42: "
     588              :                           "expected a string or an identifier after WITH ( OWNER <owner>[:<group>] )."));
     589            1 :         }
     590              : 
     591              :         {
     592              :             // CREATE CONTEXT my_context WITH ( COMMENT TRUE;
     593            3 :             std::string script("CREATE CONTEXT my_context WITH ( COMMENT TRUE;");
     594              : 
     595            1 :             prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
     596            1 :             lexer->set_input(std::make_shared<prinbee::pbql::input>(script, "create-context-test.pbql"));
     597            1 :             prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
     598              : 
     599            3 :             CATCH_REQUIRE_THROWS_MATCHES(
     600              :                   parser->parse()
     601              :                 , prinbee::invalid_token
     602              :                 , Catch::Matchers::ExceptionMessage(
     603              :                           "prinbee_exception: create-context-test.pbql:1:42: "
     604              :                           "expected a string for <description> in CREATE CONTEXT ... WITH ( COMMENT <description> ) got a IDENTIFIER."));
     605            1 :         }
     606              : 
     607              :         {
     608              :             // CREATE CONTEXT my_context WITH ( COMMENT 'good', COMMENT;
     609            3 :             std::string script("CREATE CONTEXT my_context WITH ( COMMENT 'good', COMMENT;");
     610              : 
     611            1 :             prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
     612            1 :             lexer->set_input(std::make_shared<prinbee::pbql::input>(script, "create-context-test.pbql"));
     613            1 :             prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
     614              : 
     615            3 :             CATCH_REQUIRE_THROWS_MATCHES(
     616              :                   parser->parse()
     617              :                 , prinbee::invalid_token
     618              :                 , Catch::Matchers::ExceptionMessage(
     619              :                           "prinbee_exception: create-context-test.pbql:1:58: "
     620              :                           "WITH COMMENT found twice after CREATE CONTEXT."));
     621            1 :         }
     622              : 
     623              :         {
     624              :             // CREATE CONTEXT my_context WITH ( COMMENT 'good'?;
     625            3 :             std::string script("CREATE CONTEXT my_context WITH ( COMMENT 'good' 123;");
     626              : 
     627            1 :             prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
     628            1 :             lexer->set_input(std::make_shared<prinbee::pbql::input>(script, "create-context-test.pbql"));
     629            1 :             prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
     630              : 
     631            3 :             CATCH_REQUIRE_THROWS_MATCHES(
     632              :                   parser->parse()
     633              :                 , prinbee::invalid_token
     634              :                 , Catch::Matchers::ExceptionMessage(
     635              :                           "prinbee_exception: create-context-test.pbql:1:49: "
     636              :                           "expected a comma to separate feature definitions in CREATE CONTEXT."));
     637            1 :         }
     638              :     }
     639            4 :     CATCH_END_SECTION()
     640              : 
     641            5 :     CATCH_START_SECTION("parser_error: BEGIN/COMMIT/ROLLBACK mistakes")
     642              :     {
     643              :         {
     644              :             // BEGIN ON <123>
     645            3 :             std::string script("BEGIN ON 123;");
     646              : 
     647            1 :             prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
     648            1 :             lexer->set_input(std::make_shared<prinbee::pbql::input>(script, "transaction-test.pbql"));
     649            1 :             prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
     650              : 
     651            3 :             CATCH_REQUIRE_THROWS_MATCHES(
     652              :                   parser->parse()
     653              :                 , prinbee::invalid_token
     654              :                 , Catch::Matchers::ExceptionMessage(
     655              :                           "prinbee_exception: transaction-test.pbql:1:10: expected identifier SCHEMA or DATA after BEGIN ON."));
     656            1 :         }
     657              : 
     658              :         {
     659              :             // BEGIN ON TABLE
     660            3 :             std::string script("BEGIN ON TABLE;");
     661              : 
     662            1 :             prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
     663            1 :             lexer->set_input(std::make_shared<prinbee::pbql::input>(script, "transaction-test.pbql"));
     664            1 :             prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
     665              : 
     666            3 :             CATCH_REQUIRE_THROWS_MATCHES(
     667              :                   parser->parse()
     668              :                 , prinbee::invalid_token
     669              :                 , Catch::Matchers::ExceptionMessage(
     670              :                           "prinbee_exception: transaction-test.pbql:1:10: expected identifier SCHEMA or DATA after BEGIN ON."));
     671            1 :         }
     672              : 
     673              :         {
     674              :             // BEGIN ON SCHEMA IF
     675            3 :             std::string script("BEGIN ON SCHEMA IF;");
     676              : 
     677            1 :             prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
     678            1 :             lexer->set_input(std::make_shared<prinbee::pbql::input>(script, "transaction-test.pbql"));
     679            1 :             prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
     680              : 
     681            3 :             CATCH_REQUIRE_THROWS_MATCHES(
     682              :                   parser->parse()
     683              :                 , prinbee::invalid_token
     684              :                 , Catch::Matchers::ExceptionMessage(
     685              :                           "prinbee_exception: transaction-test.pbql:1:17: expected ';' at the end of 'BEGIN' command; not IDENTIFIER IF."));
     686            1 :         }
     687              : 
     688              :         {
     689              :             // COMMIT WORK ON SCHEMA WHEN
     690            3 :             std::string script("COMMIT WORK ON SCHEMA WHEN;");
     691              : 
     692            1 :             prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
     693            1 :             lexer->set_input(std::make_shared<prinbee::pbql::input>(script, "transaction-test.pbql"));
     694            1 :             prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
     695              : 
     696            3 :             CATCH_REQUIRE_THROWS_MATCHES(
     697              :                   parser->parse()
     698              :                 , prinbee::invalid_token
     699              :                 , Catch::Matchers::ExceptionMessage(
     700              :                           "prinbee_exception: transaction-test.pbql:1:23: expected IF clause or ';' at the end of a COMMIT or ROLLBACK."));
     701            1 :         }
     702              : 
     703              :         {
     704              :             // COMMIT TRANSACTION ON SCHEMA IF a <> b THEN
     705            3 :             std::string script("COMMIT TRANSACTION ON SCHEMA IF a <> b THEN;");
     706              : 
     707            1 :             prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
     708            1 :             lexer->set_input(std::make_shared<prinbee::pbql::input>(script, "transaction-test.pbql"));
     709            1 :             prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
     710              : 
     711            3 :             CATCH_REQUIRE_THROWS_MATCHES(
     712              :                   parser->parse()
     713              :                 , prinbee::invalid_token
     714              :                 , Catch::Matchers::ExceptionMessage(
     715              :                           "prinbee_exception: transaction-test.pbql:1:40: expected OTHERWISE after the IF expression of COMMIT or ROLLBACK."));
     716            1 :         }
     717              : 
     718              :         {
     719              :             // COMMIT TRANSACTION ON SCHEMA IF a <> b THEN
     720            3 :             std::string script("COMMIT TRANSACTION ON SCHEMA IF a <> b OTHERWISE 123;");
     721              : 
     722            1 :             prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
     723            1 :             lexer->set_input(std::make_shared<prinbee::pbql::input>(script, "transaction-test.pbql"));
     724            1 :             prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
     725              : 
     726            3 :             CATCH_REQUIRE_THROWS_MATCHES(
     727              :                   parser->parse()
     728              :                 , prinbee::invalid_token
     729              :                 , Catch::Matchers::ExceptionMessage(
     730              :                           "prinbee_exception: transaction-test.pbql:1:50: expected ROLLBACK after OTHERWISE for command COMMIT."));
     731            1 :         }
     732              : 
     733              :         {
     734              :             // COMMIT TRANSACTION ON SCHEMA IF a <> b THEN
     735            3 :             std::string script("ROLLBACK TRANSACTION ON DATA IF a = b OTHERWISE 123;");
     736              : 
     737            1 :             prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
     738            1 :             lexer->set_input(std::make_shared<prinbee::pbql::input>(script, "transaction-test.pbql"));
     739            1 :             prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
     740              : 
     741            3 :             CATCH_REQUIRE_THROWS_MATCHES(
     742              :                   parser->parse()
     743              :                 , prinbee::invalid_token
     744              :                 , Catch::Matchers::ExceptionMessage(
     745              :                           "prinbee_exception: transaction-test.pbql:1:49: expected COMMIT after OTHERWISE for command ROLLBACK."));
     746            1 :         }
     747              :     }
     748            4 :     CATCH_END_SECTION()
     749            3 : }
     750              : 
     751              : 
     752              : 
     753              : // vim: ts=4 sw=4 et
        

Generated by: LCOV version 2.0-1

Snap C++ | List of projects | List of versions