LCOV - code coverage report
Current view: top level - tests - catch_database.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 576 584 98.6 %
Date: 2023-07-29 22:00:24 Functions: 10 11 90.9 %
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/file/database.h>
      22             : 
      23             : #include    <as2js/exception.h>
      24             : #include    <as2js/message.h>
      25             : 
      26             : 
      27             : // self
      28             : //
      29             : #include    "catch_main.h"
      30             : 
      31             : 
      32             : // libutf8
      33             : //
      34             : #include    <libutf8/libutf8.h>
      35             : 
      36             : 
      37             : // C++
      38             : //
      39             : #include    <cstring>
      40             : #include    <algorithm>
      41             : #include    <iomanip>
      42             : 
      43             : 
      44             : // C
      45             : //
      46             : #include    <unistd.h>
      47             : #include    <sys/stat.h>
      48             : 
      49             : 
      50             : // last include
      51             : //
      52             : #include    <snapdev/poison.h>
      53             : 
      54             : 
      55             : 
      56             : namespace
      57             : {
      58             : 
      59             : 
      60        4808 : int32_t generate_string(std::string & str)
      61             : {
      62             :     char32_t c;
      63        4808 :     int32_t used(0);
      64        4808 :     int ctrl(rand() % 7);
      65        4808 :     int const max_chars(rand() % 25 + 20);
      66      158745 :     for(int j(0); j < max_chars; ++j)
      67             :     {
      68             :         do
      69             :         {
      70      240917 :             c = rand() & 0x1FFFFF;
      71      240917 :             if(ctrl == 0)
      72             :             {
      73       59239 :                 ctrl = rand() % 7;
      74       59239 :                 if((ctrl & 3) == 1)
      75             :                 {
      76       16795 :                     c = c & 1 ? '"' : '\'';
      77             :                 }
      78             :                 else
      79             :                 {
      80       42444 :                     c &= 0x1F;
      81             :                 }
      82             :             }
      83             :             else
      84             :             {
      85      181678 :                 --ctrl;
      86             :             }
      87             :         }
      88             :         while(c >= 0x110000
      89      155494 :            || (c >= 0xD800 && c <= 0xDFFF)
      90      155305 :            || ((c & 0xFFFE) == 0xFFFE)
      91      396221 :            || c == '\0');
      92      153937 :         str += libutf8::to_u8string(c);
      93      153937 :         switch(c)
      94             :         {
      95        1290 :         case '\b':
      96        1290 :             used |= 0x01;
      97        1290 :             break;
      98             : 
      99        1305 :         case '\f':
     100        1305 :             used |= 0x02;
     101        1305 :             break;
     102             : 
     103        1342 :         case '\n':
     104        1342 :             used |= 0x04;
     105        1342 :             break;
     106             : 
     107        1388 :         case '\r':
     108        1388 :             used |= 0x08;
     109        1388 :             break;
     110             : 
     111        1343 :         case '\t':
     112        1343 :             used |= 0x10;
     113        1343 :             break;
     114             : 
     115        8359 :         case '"':
     116        8359 :             used |= 0x20;
     117        8359 :             break;
     118             : 
     119        8436 :         case '\'':
     120        8436 :             used |= 0x40;
     121        8436 :             break;
     122             : 
     123      130474 :         default:
     124      130474 :             if(c < 0x0020)
     125             :             {
     126             :                 // other controls must be escaped using Unicode
     127       34411 :                 used |= 0x80;
     128             :             }
     129      130474 :             break;
     130             : 
     131             :         }
     132             :     }
     133             : 
     134        4808 :     return used;
     135             : }
     136             : 
     137             : 
     138             : class test_callback : public as2js::message_callback
     139             : {
     140             : public:
     141           4 :     test_callback()
     142           4 :     {
     143           4 :         as2js::set_message_callback(this);
     144           4 :         g_warning_count = as2js::warning_count();
     145           4 :         g_error_count = as2js::error_count();
     146           4 :     }
     147             : 
     148           4 :     ~test_callback()
     149           4 :     {
     150             :         // make sure the pointer gets reset!
     151           4 :         as2js::set_message_callback(nullptr);
     152           4 :     }
     153             : 
     154             :     // implementation of the output
     155           8 :     virtual void output(as2js::message_level_t message_level, as2js::err_code_t error_code, as2js::position const& pos, std::string const& message)
     156             :     {
     157           8 :         CATCH_REQUIRE(!f_expected.empty());
     158             : 
     159             : //std::cerr << "filename = " << pos.get_filename() << " / " << f_expected[0].f_pos.get_filename() << "\n";
     160             : //std::cerr << "msg = " << message << " / " << f_expected[0].f_message << "\n";
     161             : //std::cerr << "page = " << pos.get_page() << " / " << f_expected[0].f_pos.get_page() << "\n";
     162             : //std::cerr << "line = " << pos.get_line() << " / " << f_expected[0].f_pos.get_line() << "\n";
     163             : //std::cerr << "error_code = " << static_cast<int>(error_code) << " / " << static_cast<int>(f_expected[0].f_error_code) << "\n";
     164             : 
     165           8 :         CATCH_REQUIRE(f_expected[0].f_call);
     166           8 :         CATCH_REQUIRE(message_level == f_expected[0].f_message_level);
     167           8 :         CATCH_REQUIRE(error_code == f_expected[0].f_error_code);
     168           8 :         CATCH_REQUIRE(pos.get_filename() == f_expected[0].f_pos.get_filename());
     169           8 :         CATCH_REQUIRE(pos.get_function() == f_expected[0].f_pos.get_function());
     170           8 :         CATCH_REQUIRE(pos.get_page() == f_expected[0].f_pos.get_page());
     171           8 :         CATCH_REQUIRE(pos.get_page_line() == f_expected[0].f_pos.get_page_line());
     172           8 :         CATCH_REQUIRE(pos.get_paragraph() == f_expected[0].f_pos.get_paragraph());
     173           8 :         CATCH_REQUIRE(pos.get_line() == f_expected[0].f_pos.get_line());
     174           8 :         CATCH_REQUIRE(message == f_expected[0].f_message);
     175             : 
     176           8 :         if(message_level == as2js::message_level_t::MESSAGE_LEVEL_WARNING)
     177             :         {
     178           0 :             ++g_warning_count;
     179           0 :             CATCH_REQUIRE(g_warning_count == as2js::warning_count());
     180             :         }
     181             : 
     182           8 :         if(message_level == as2js::message_level_t::MESSAGE_LEVEL_FATAL
     183           8 :         || message_level == as2js::message_level_t::MESSAGE_LEVEL_ERROR)
     184             :         {
     185           8 :             ++g_error_count;
     186             : //std::cerr << "error: " << g_error_count << " / " << as2js::error_count() << "\n";
     187           8 :             CATCH_REQUIRE(g_error_count == as2js::error_count());
     188             :         }
     189             : 
     190           8 :         f_expected.erase(f_expected.begin());
     191           8 :     }
     192             : 
     193           4 :     void got_called()
     194             :     {
     195           4 :         if(!f_expected.empty())
     196             :         {
     197           0 :             std::cerr << "\n*** STILL " << f_expected.size() << " EXPECTED ***\n";
     198           0 :             std::cerr << "filename = " << f_expected[0].f_pos.get_filename() << "\n";
     199           0 :             std::cerr << "msg = " << f_expected[0].f_message << "\n";
     200           0 :             std::cerr << "page = " << f_expected[0].f_pos.get_page() << "\n";
     201           0 :             std::cerr << "error_code = " << static_cast<int>(f_expected[0].f_error_code) << "\n";
     202             :         }
     203           4 :         CATCH_REQUIRE(f_expected.empty());
     204           4 :     }
     205             : 
     206             :     struct expected_t
     207             :     {
     208             :         bool                        f_call = true;
     209             :         as2js::message_level_t      f_message_level = as2js::message_level_t::MESSAGE_LEVEL_OFF;
     210             :         as2js::err_code_t           f_error_code = as2js::err_code_t::AS_ERR_NONE;
     211             :         as2js::position             f_pos = as2js::position();
     212             :         std::string                 f_message= std::string(); // UTF-8 string
     213             :     };
     214             : 
     215             :     std::vector<expected_t>     f_expected = std::vector<expected_t>();
     216             : 
     217             :     static int32_t              g_warning_count;
     218             :     static int32_t              g_error_count;
     219             : };
     220             : 
     221             : int32_t   test_callback::g_warning_count = 0;
     222             : int32_t   test_callback::g_error_count = 0;
     223             : 
     224             : 
     225             : }
     226             : // no name namespace
     227             : 
     228             : 
     229             : 
     230             : 
     231             : namespace SNAP_CATCH2_NAMESPACE
     232             : {
     233             : 
     234             : 
     235             : 
     236           1 : int catch_db_init()
     237             : {
     238             :     // we do not want a test.db or it would conflict with this test
     239             :     //
     240           1 :     if(access("test.db", F_OK) == 0)
     241             :     {
     242           0 :         return 1;
     243             :     }
     244             : 
     245           1 :     return 0;
     246             : }
     247             : 
     248             : 
     249             : 
     250             : } // namespace SNAP_CATCH2_NAMESPACE
     251             : 
     252             : 
     253           1 : CATCH_TEST_CASE("db_match", "[database][match]")
     254             : {
     255           1 :     CATCH_START_SECTION("db_match: match strings")
     256             :     {
     257         101 :         for(size_t idx(0); idx < 100; ++idx)
     258             :         {
     259         100 :             std::string start;
     260         100 :             generate_string(start);
     261         100 :             std::string middle;
     262         100 :             generate_string(middle);
     263         100 :             std::string end;
     264         100 :             generate_string(end);
     265             : 
     266         100 :             std::string name;
     267         100 :             name = start + middle + end;
     268         100 :             CATCH_REQUIRE(as2js::database::match_pattern(name, "*"));
     269             : 
     270         100 :             std::string p1(start);
     271         100 :             p1 += '*';
     272         100 :             CATCH_REQUIRE(as2js::database::match_pattern(name, p1));
     273             : 
     274         100 :             std::string p2(start);
     275         100 :             p2 += '*';
     276         100 :             p2 += middle;
     277         100 :             p2 += '*';
     278         100 :             CATCH_REQUIRE(as2js::database::match_pattern(name, p2));
     279             : 
     280         100 :             std::string p3(start);
     281         100 :             p3 += '*';
     282         100 :             p3 += end;
     283         100 :             CATCH_REQUIRE(as2js::database::match_pattern(name, p3));
     284             : 
     285         100 :             std::string p4;
     286         100 :             p4 += '*';
     287         100 :             p4 += middle;
     288         100 :             p4 += '*';
     289         100 :             CATCH_REQUIRE(as2js::database::match_pattern(name, p4));
     290             : 
     291         100 :             std::string p5;
     292         100 :             p5 += '*';
     293         100 :             p5 += middle;
     294         100 :             p5 += '*';
     295         100 :             p5 += end;
     296         100 :             CATCH_REQUIRE(as2js::database::match_pattern(name, p5));
     297             : 
     298         100 :             std::string p6(start);
     299         100 :             p6 += '*';
     300         100 :             p6 += middle;
     301         100 :             p6 += '*';
     302         100 :             p6 += end;
     303         100 :             CATCH_REQUIRE(as2js::database::match_pattern(name, p6));
     304             : 
     305         100 :             std::string p7;
     306         100 :             p7 += '*';
     307         100 :             p7 += end;
     308         100 :             CATCH_REQUIRE(as2js::database::match_pattern(name, p7));
     309         100 :         }
     310             :     }
     311           1 :     CATCH_END_SECTION()
     312           1 : }
     313             : 
     314             : 
     315           3 : CATCH_TEST_CASE("db_element", "[database][element]")
     316             : {
     317           3 :     CATCH_START_SECTION("db_element: type/filename")
     318             :     {
     319           1 :         std::int32_t used_type(0);
     320           1 :         std::int32_t used_filename(0);
     321         101 :         for(std::size_t idx(0); idx < 100 || used_type != 0xFF || used_filename != 0xFF; ++idx)
     322             :         {
     323         100 :             as2js::position pos;
     324             : 
     325         100 :             std::string raw_type;
     326         100 :             used_type |= generate_string(raw_type);
     327         100 :             as2js::json::json_value::pointer_t type(new as2js::json::json_value(pos, raw_type));
     328             : 
     329         100 :             std::string raw_filename;
     330         100 :             used_filename |= generate_string(raw_filename);
     331         100 :             as2js::json::json_value::pointer_t filename(new as2js::json::json_value(pos, raw_filename));
     332             : 
     333             :             // generate a line number
     334         100 :             std::int32_t raw_line((rand() & 0xFFFFFF) + 1);
     335         100 :             as2js::integer line_integer(raw_line);
     336         100 :             as2js::json::json_value::pointer_t line(new as2js::json::json_value(pos, line_integer));
     337             : 
     338         100 :             as2js::json::json_value::object_t obj;
     339         100 :             obj["filename"] = filename;
     340         100 :             obj["type"] = type;
     341         100 :             obj["line"] = line;
     342         100 :             as2js::json::json_value::pointer_t element(new as2js::json::json_value(pos, obj));
     343             : 
     344         400 :             as2js::database::element::pointer_t db_element(new as2js::database::element("this.is.an.element.name", element));
     345             : 
     346         100 :             CATCH_REQUIRE(db_element->get_element_name() == "this.is.an.element.name");
     347         100 :             CATCH_REQUIRE(db_element->get_type() == raw_type);
     348         100 :             CATCH_REQUIRE(db_element->get_filename() == raw_filename);
     349         100 :             CATCH_REQUIRE(db_element->get_line() == raw_line);
     350             : 
     351         100 :             generate_string(raw_type);
     352         100 :             db_element->set_type(raw_type);
     353         100 :             CATCH_REQUIRE(db_element->get_type() == raw_type);
     354             : 
     355         100 :             generate_string(raw_filename);
     356         100 :             db_element->set_filename(raw_filename);
     357         100 :             CATCH_REQUIRE(db_element->get_filename() == raw_filename);
     358             : 
     359         100 :             raw_line = (rand() & 0xFFFFFF) + 1;
     360         100 :             db_element->set_line(raw_line);
     361         100 :             CATCH_REQUIRE(db_element->get_line() == raw_line);
     362         100 :         }
     363             :     }
     364           3 :     CATCH_END_SECTION()
     365             : 
     366           3 :     CATCH_START_SECTION("db_element: errorneous data")
     367             :     {
     368             :         // now check for erroneous data
     369             :         //
     370           1 :         as2js::position pos;
     371             : 
     372           1 :         std::string not_obj;
     373           1 :         generate_string(not_obj);
     374           1 :         as2js::json::json_value::pointer_t bad_element(new as2js::json::json_value(pos, not_obj));
     375             : 
     376           8 :         CATCH_REQUIRE_THROWS_MATCHES(
     377             :               new as2js::database::element("expect.a.throw", bad_element)
     378             :             , as2js::internal_error
     379             :             , Catch::Matchers::ExceptionMessage(
     380             :                       "internal_error: an element cannot be created with a json value which has a type other than object."));
     381           1 :     }
     382           3 :     CATCH_END_SECTION()
     383             : 
     384           3 :     CATCH_START_SECTION("db_element: position")
     385             :     {
     386           1 :         as2js::position pos;
     387             : 
     388           1 :         int32_t bad_raw_type((rand() & 0xFFFFFF) + 1);
     389           1 :         as2js::integer bad_type_integer(bad_raw_type);
     390           1 :         as2js::json::json_value::pointer_t bad_type(new as2js::json::json_value(pos, bad_type_integer));
     391             : 
     392           1 :         double bad_raw_filename(static_cast<double>((rand() << 16) ^ rand()) / static_cast<double>((rand() << 16) ^ rand()));
     393           1 :         as2js::floating_point bad_filename_floating_point(bad_raw_filename);
     394           1 :         as2js::json::json_value::pointer_t bad_filename(new as2js::json::json_value(pos, bad_filename_floating_point));
     395             : 
     396             :         // generate a line number
     397           1 :         std::string bad_raw_line;
     398           1 :         generate_string(bad_raw_line);
     399           1 :         as2js::json::json_value::pointer_t bad_line(new as2js::json::json_value(pos, bad_raw_line));
     400             : 
     401           1 :         as2js::json::json_value::object_t bad_obj;
     402           1 :         bad_obj["filename"] = bad_filename;
     403           1 :         bad_obj["type"] = bad_type;
     404           1 :         bad_obj["line"] = bad_line;
     405           1 :         as2js::json::json_value::pointer_t element(new as2js::json::json_value(pos, bad_obj));
     406             : 
     407             :         // WARNING: errors should be generated in the order the elements
     408             :         //          appear in the map
     409           1 :         test_callback tc;
     410             : 
     411           1 :         test_callback::expected_t expected1;
     412           1 :         expected1.f_message_level = as2js::message_level_t::MESSAGE_LEVEL_ERROR;
     413           1 :         expected1.f_error_code = as2js::err_code_t::AS_ERR_UNEXPECTED_DATABASE;
     414           1 :         expected1.f_pos.set_filename("unknown-file");
     415           1 :         expected1.f_pos.set_function("unknown-func");
     416           1 :         expected1.f_message = "The filename of an element in the database has to be a string.";
     417           1 :         tc.f_expected.push_back(expected1);
     418             : 
     419           1 :         test_callback::expected_t expected2;
     420           1 :         expected2.f_message_level = as2js::message_level_t::MESSAGE_LEVEL_ERROR;
     421           1 :         expected2.f_error_code = as2js::err_code_t::AS_ERR_UNEXPECTED_DATABASE;
     422           1 :         expected2.f_pos.set_filename("unknown-file");
     423           1 :         expected2.f_pos.set_function("unknown-func");
     424           1 :         expected2.f_message = "The line of an element in the database has to be an integer.";
     425           1 :         tc.f_expected.push_back(expected2);
     426             : 
     427           1 :         test_callback::expected_t expected3;
     428           1 :         expected3.f_message_level = as2js::message_level_t::MESSAGE_LEVEL_ERROR;
     429           1 :         expected3.f_error_code = as2js::err_code_t::AS_ERR_UNEXPECTED_DATABASE;
     430           1 :         expected3.f_pos.set_filename("unknown-file");
     431           1 :         expected3.f_pos.set_function("unknown-func");
     432           1 :         expected3.f_message = "The type of an element in the database has to be a string.";
     433           1 :         tc.f_expected.push_back(expected3);
     434             : 
     435           4 :         as2js::database::element::pointer_t db_element(new as2js::database::element("this.is.a.bad.element.name", element));
     436           1 :         tc.got_called();
     437             : 
     438           1 :         CATCH_REQUIRE(db_element->get_element_name() == "this.is.a.bad.element.name");
     439           1 :         CATCH_REQUIRE(db_element->get_type() == "");
     440           1 :         CATCH_REQUIRE(db_element->get_filename() == "");
     441           1 :         CATCH_REQUIRE(db_element->get_line() == 1);
     442           1 :     }
     443           3 :     CATCH_END_SECTION()
     444           3 : }
     445             : 
     446             : 
     447           3 : CATCH_TEST_CASE("db_package", "[database][package]")
     448             : {
     449           3 :     CATCH_START_SECTION("db_package: add & find packages")
     450             :     {
     451         101 :         for(size_t idx(0); idx < 100; ++idx)
     452             :         {
     453         100 :             as2js::position pos;
     454             : 
     455             :             // one package of 10 elements
     456         100 :             as2js::json::json_value::object_t package_obj;
     457             : 
     458             :             struct data_t
     459             :             {
     460             :                 std::string     f_element_name = std::string();
     461             :                 std::string     f_type = std::string();
     462             :                 std::string     f_filename = std::string();
     463             :                 std::int32_t    f_line = 0;
     464             :             };
     465         100 :             std::vector<data_t> elements;
     466             : 
     467        1100 :             for(std::size_t j(0); j < 10; ++j)
     468             :             {
     469        1000 :                 data_t data;
     470             : 
     471        1000 :                 generate_string(data.f_type);
     472        1000 :                 as2js::json::json_value::pointer_t type(new as2js::json::json_value(pos, data.f_type));
     473             : 
     474        1000 :                 generate_string(data.f_filename);
     475        1000 :                 as2js::json::json_value::pointer_t filename(new as2js::json::json_value(pos, data.f_filename));
     476             : 
     477             :                 // generate a line number
     478        1000 :                 data.f_line = (rand() & 0xFFFFFF) + 1;
     479        1000 :                 as2js::integer line_integer(data.f_line);
     480        1000 :                 as2js::json::json_value::pointer_t line(new as2js::json::json_value(pos, line_integer));
     481             : 
     482        1000 :                 as2js::json::json_value::object_t obj;
     483        1000 :                 obj["type"] = type;
     484        1000 :                 obj["filename"] = filename;
     485        1000 :                 obj["line"] = line;
     486        1000 :                 as2js::json::json_value::pointer_t element(new as2js::json::json_value(pos, obj));
     487             : 
     488        1000 :                 generate_string(data.f_element_name);
     489        1000 :                 package_obj[data.f_element_name] = element;
     490             : 
     491        1000 :                 elements.push_back(data);
     492             : 
     493             :                 // as we're here, make sure we can create such a db element
     494        2000 :                 as2js::database::element::pointer_t db_element(new as2js::database::element(data.f_element_name, element));
     495             : 
     496        1000 :                 CATCH_REQUIRE(db_element->get_element_name() == data.f_element_name);
     497        1000 :                 CATCH_REQUIRE(db_element->get_type() == data.f_type);
     498        1000 :                 CATCH_REQUIRE(db_element->get_filename() == data.f_filename);
     499        1000 :                 CATCH_REQUIRE(db_element->get_line() == data.f_line);
     500        1000 :             }
     501             : 
     502         100 :             as2js::json::json_value::pointer_t package(new as2js::json::json_value(pos, package_obj));
     503         100 :             std::string package_name;
     504         100 :             generate_string(package_name);
     505         200 :             as2js::database::package::pointer_t db_package(new as2js::database::package(package_name, package));
     506             : 
     507         100 :             CATCH_REQUIRE(db_package->get_package_name() == package_name);
     508             : 
     509        1100 :             for(size_t j(0); j < 10; ++j)
     510             :             {
     511        1000 :                 as2js::database::element::pointer_t e(db_package->get_element(elements[j].f_element_name));
     512             : 
     513        1000 :                 CATCH_REQUIRE(e->get_element_name() == elements[j].f_element_name);
     514        1000 :                 CATCH_REQUIRE(e->get_type()         == elements[j].f_type);
     515        1000 :                 CATCH_REQUIRE(e->get_filename()     == elements[j].f_filename);
     516        1000 :                 CATCH_REQUIRE(e->get_line()         == elements[j].f_line);
     517             : 
     518             :                 // the add_element() does nothing if we add an element with the
     519             :                 // same name
     520        1000 :                 as2js::database::element::pointer_t n(db_package->add_element(elements[j].f_element_name));
     521        1000 :                 CATCH_REQUIRE(n == e);
     522        1000 :             }
     523             : 
     524             :             // attempts a find as well
     525        1100 :             for(size_t j(0); j < 10; ++j)
     526             :             {
     527             :                 {
     528             :                     // pattern "starts with"
     529        1000 :                     int len(rand() % 5 + 1);
     530        1000 :                     std::string pattern(elements[j].f_element_name.substr(0, len));
     531        1000 :                     int const max_asterisk(rand() % 3 + 1);
     532        2946 :                     for(int a(0); a < max_asterisk; ++a)
     533             :                     {
     534        1946 :                         pattern += '*';
     535             :                     }
     536        1000 :                     as2js::database::element::vector_t list(db_package->find_elements(pattern));
     537             : 
     538             :                     // check that the name of the elements found this way are valid
     539             :                     // matches
     540        1000 :                     size_t const max_elements(list.size());
     541        1000 :                     CATCH_REQUIRE(max_elements >= 1);
     542        2190 :                     for(size_t k(0); k < max_elements; ++k)
     543             :                     {
     544        1190 :                         std::string name(list[k]->get_element_name());
     545        1190 :                         std::string match(name.substr(0, len));
     546        3515 :                         for(int a(0); a < max_asterisk; ++a)
     547             :                         {
     548        2325 :                             match += '*';
     549             :                         }
     550        1190 :                         CATCH_REQUIRE(pattern == match);
     551        1190 :                     }
     552             : 
     553             :                     // now verify that we found them all
     554       11000 :                     for(std::size_t q(0); q < 10; ++q)
     555             :                     {
     556       10000 :                         std::string name(elements[q].f_element_name);
     557       10000 :                         std::string start_with(name.substr(0, len));
     558       10000 :                         start_with += '*';
     559       10000 :                         if(start_with == pattern.substr(0, len + 1))
     560             :                         {
     561             :                             // find that entry in the list
     562        1190 :                             bool good(false);
     563        1508 :                             for(std::size_t k(0); k < max_elements; ++k)
     564             :                             {
     565        1508 :                                 if(list[k]->get_element_name() == name)
     566             :                                 {
     567        1190 :                                     good = true;
     568        1190 :                                     break;
     569             :                                 }
     570             :                             }
     571        1190 :                             CATCH_REQUIRE(good);
     572             :                         }
     573       10000 :                     }
     574        1000 :                 }
     575             : 
     576             :                 {
     577             :                     // pattern "ends with"
     578        1000 :                     int len(rand() % 5 + 1);
     579        1000 :                     std::string pattern;
     580        1000 :                     pattern += '*';
     581        1000 :                     pattern += elements[j].f_element_name.substr(elements[j].f_element_name.length() - len, len);
     582        1000 :                     as2js::database::element::vector_t list(db_package->find_elements(pattern));
     583             : 
     584             :                     // check that the name of the elements found this way are valid
     585             :                     // matches
     586        1000 :                     std::size_t const max_elements(list.size());
     587        1000 :                     CATCH_REQUIRE(max_elements >= 1);
     588        2039 :                     for(std::size_t k(0); k < max_elements; ++k)
     589             :                     {
     590        1039 :                         std::string name(list[k]->get_element_name());
     591        1039 :                         std::string match;
     592        1039 :                         match += '*';
     593        1039 :                         match += name.substr(name.length() - len, len);
     594        1039 :                         CATCH_REQUIRE(pattern == match);
     595        1039 :                     }
     596             : 
     597             :                     // now verify that we found them all
     598       11000 :                     for(std::size_t q(0); q < 10; ++q)
     599             :                     {
     600       10000 :                         std::string name(elements[q].f_element_name);
     601       10000 :                         std::string end_with;
     602       10000 :                         end_with += '*';
     603       10000 :                         end_with += name.substr(name.length() - len, len);
     604       10000 :                         if(end_with == pattern)
     605             :                         {
     606             :                             // find that entry in the list
     607        1039 :                             bool good(false);
     608        1086 :                             for(std::size_t k(0); k < max_elements; ++k)
     609             :                             {
     610        1086 :                                 if(list[k]->get_element_name() == name)
     611             :                                 {
     612        1039 :                                     good = true;
     613        1039 :                                     break;
     614             :                                 }
     615             :                             }
     616        1039 :                             CATCH_REQUIRE(good);
     617             :                         }
     618       10000 :                     }
     619        1000 :                 }
     620             : 
     621             :                 {
     622             :                     // pattern "starts/ends with"
     623             :                     // names are generated by the generate_string() so they are
     624             :                     // at least 20 characters long which is enough here
     625        1000 :                     int slen(rand() % 5 + 1);
     626        1000 :                     int elen(rand() % 5 + 1);
     627        1000 :                     std::string pattern;
     628        1000 :                     pattern += elements[j].f_element_name.substr(0, slen);
     629        1000 :                     pattern += '*';
     630        1000 :                     pattern += elements[j].f_element_name.substr(elements[j].f_element_name.length() - elen, elen);
     631        1000 :                     as2js::database::element::vector_t list(db_package->find_elements(pattern));
     632             : 
     633             :                     // check that the name of the elements found this way are valid
     634             :                     // matches
     635        1000 :                     std::size_t const max_elements(list.size());
     636        1000 :                     CATCH_REQUIRE(max_elements >= 1);
     637        2000 :                     for(std::size_t k(0); k < max_elements; ++k)
     638             :                     {
     639        1000 :                         std::string name(list[k]->get_element_name());
     640        1000 :                         std::string match;
     641        1000 :                         match += name.substr(0, slen);
     642        1000 :                         match += '*';
     643        1000 :                         match += name.substr(name.length() - elen, elen);
     644        1000 :                         CATCH_REQUIRE(pattern == match);
     645        1000 :                     }
     646             : 
     647             :                     // now verify that we found them all
     648       11000 :                     for(std::size_t q(0); q < 10; ++q)
     649             :                     {
     650       10000 :                         std::string name(elements[q].f_element_name);
     651       10000 :                         std::string end_with;
     652       10000 :                         end_with += name.substr(0, slen);
     653       10000 :                         end_with += '*';
     654       10000 :                         end_with += name.substr(name.length() - elen, elen);
     655       10000 :                         if(end_with == pattern)
     656             :                         {
     657             :                             // find that entry in the list
     658        1000 :                             bool good(false);
     659        1000 :                             for(size_t k(0); k < max_elements; ++k)
     660             :                             {
     661        1000 :                                 if(list[k]->get_element_name() == name)
     662             :                                 {
     663        1000 :                                     good = true;
     664        1000 :                                     break;
     665             :                                 }
     666             :                             }
     667        1000 :                             CATCH_REQUIRE(good);
     668             :                         }
     669       10000 :                     }
     670        1000 :                 }
     671             :             }
     672             : 
     673             :             // add a few more elements
     674        1100 :             for(size_t j(0); j < 10; ++j)
     675             :             {
     676             :                 // at this point the name of an element is not verified because
     677             :                 // all the internal code expects valid identifiers for those
     678             :                 // names so any random name will do in this test
     679        1000 :                 std::string name;
     680        1000 :                 generate_string(name);
     681        1000 :                 as2js::database::element::pointer_t e(db_package->add_element(name));
     682             : 
     683             :                 // it creates an empty element in this case
     684        1000 :                 CATCH_REQUIRE(e->get_element_name() == name);
     685        1000 :                 CATCH_REQUIRE(e->get_type() == "");
     686        1000 :                 CATCH_REQUIRE(e->get_filename() == "");
     687        1000 :                 CATCH_REQUIRE(e->get_line() == 1);
     688        1000 :             }
     689         100 :         }
     690             :     }
     691           3 :     CATCH_END_SECTION()
     692             : 
     693           3 :     CATCH_START_SECTION("db_package: erroneous packages")
     694             :     {
     695             :         // now check for erroneous data
     696             :         //
     697           1 :         as2js::position pos;
     698             : 
     699           1 :         std::string not_obj;
     700           1 :         generate_string(not_obj);
     701           1 :         as2js::json::json_value::pointer_t bad_package(new as2js::json::json_value(pos, not_obj));
     702             : 
     703           8 :         CATCH_REQUIRE_THROWS_MATCHES(
     704             :               new as2js::database::package("expect.a.throw", bad_package)
     705             :             , as2js::internal_error
     706             :             , Catch::Matchers::ExceptionMessage(
     707             :                       "internal_error: a package cannot be created with a json value which has a type other than object."));
     708           1 :     }
     709           3 :     CATCH_END_SECTION()
     710             : 
     711           3 :     CATCH_START_SECTION("db_package: more bad data")
     712             :     {
     713           1 :         as2js::position pos;
     714             : 
     715           1 :         int32_t bad_int((rand() & 0xFFFFFF) + 1);
     716           1 :         as2js::integer bad_integer(bad_int);
     717           1 :         as2js::json::json_value::pointer_t bad_a(new as2js::json::json_value(pos, bad_integer));
     718             : 
     719           1 :         double bad_float(static_cast<double>((rand() << 16) ^ rand()) / static_cast<double>((rand() << 16) ^ rand()));
     720           1 :         as2js::floating_point bad_floating_point(bad_float);
     721           1 :         as2js::json::json_value::pointer_t bad_b(new as2js::json::json_value(pos, bad_floating_point));
     722             : 
     723           1 :         std::string bad_string;
     724           1 :         generate_string(bad_string);
     725           1 :         as2js::json::json_value::pointer_t bad_c(new as2js::json::json_value(pos, bad_string));
     726             : 
     727             :         //as2js::json::json_value::object_t bad_obj;
     728             :         //std::string n1;
     729             :         //generate_string(n1);
     730             :         //bad_obj[n1] = bad_a;
     731             :         //std::string n2;
     732             :         //generate_string(n2);
     733             :         //bad_obj[n2] = bad_b;
     734             :         //std::string n3;
     735             :         //generate_string(n3);
     736             :         //bad_obj[n3] = bad_c;
     737             :         //as2js::json::json_value::pointer_t element(new as2js::json::json_value(pos, bad_obj));
     738             : 
     739           1 :         as2js::json::json_value::object_t package_obj;
     740           1 :         std::string e1_name;
     741           1 :         generate_string(e1_name);
     742           1 :         package_obj[e1_name] = bad_a;
     743             : 
     744           1 :         std::string e2_name;
     745           1 :         generate_string(e2_name);
     746           1 :         package_obj[e2_name] = bad_b;
     747             : 
     748           1 :         std::string e3_name;
     749           1 :         generate_string(e3_name);
     750           1 :         package_obj[e3_name] = bad_c;
     751             : 
     752             :         // WARNING: errors should be generated in the order the elements
     753             :         //          appear in the map
     754           1 :         test_callback tc;
     755             : 
     756           1 :         test_callback::expected_t expected1;
     757           1 :         expected1.f_message_level = as2js::message_level_t::MESSAGE_LEVEL_ERROR;
     758           1 :         expected1.f_error_code = as2js::err_code_t::AS_ERR_UNEXPECTED_DATABASE;
     759           1 :         expected1.f_pos.set_filename("unknown-file");
     760           1 :         expected1.f_pos.set_function("unknown-func");
     761           1 :         expected1.f_message = "A database is expected to be an object of object packages composed of object elements.";
     762           1 :         tc.f_expected.push_back(expected1);
     763             : 
     764           1 :         test_callback::expected_t expected2;
     765           1 :         expected2.f_message_level = as2js::message_level_t::MESSAGE_LEVEL_ERROR;
     766           1 :         expected2.f_error_code = as2js::err_code_t::AS_ERR_UNEXPECTED_DATABASE;
     767           1 :         expected2.f_pos.set_filename("unknown-file");
     768           1 :         expected2.f_pos.set_function("unknown-func");
     769           1 :         expected2.f_message = "A database is expected to be an object of object packages composed of object elements.";
     770           1 :         tc.f_expected.push_back(expected2);
     771             : 
     772           1 :         test_callback::expected_t expected3;
     773           1 :         expected3.f_message_level = as2js::message_level_t::MESSAGE_LEVEL_ERROR;
     774           1 :         expected3.f_error_code = as2js::err_code_t::AS_ERR_UNEXPECTED_DATABASE;
     775           1 :         expected3.f_pos.set_filename("unknown-file");
     776           1 :         expected3.f_pos.set_function("unknown-func");
     777           1 :         expected3.f_message = "A database is expected to be an object of object packages composed of object elements.";
     778           1 :         tc.f_expected.push_back(expected3);
     779             : 
     780           1 :         as2js::json::json_value::pointer_t package(new as2js::json::json_value(pos, package_obj));
     781             : 
     782           1 :         std::string package_name;
     783           1 :         generate_string(package_name);
     784           2 :         as2js::database::package::pointer_t db_package(new as2js::database::package(package_name, package));
     785           1 :         tc.got_called();
     786           1 :         CATCH_REQUIRE(!!db_package);
     787           1 :     }
     788           3 :     CATCH_END_SECTION()
     789           3 : }
     790             : 
     791             : 
     792           5 : CATCH_TEST_CASE("db_database", "[database]")
     793             : {
     794           5 :     CATCH_START_SECTION("db_database: database")
     795             :     {
     796           1 :         as2js::database::pointer_t db(new as2js::database);
     797             : 
     798             :         // saving without a load does nothing
     799           1 :         db->save();
     800             : 
     801             :         // whatever the package name, it does not exist...
     802           1 :         CATCH_REQUIRE(!db->get_package("name"));
     803             : 
     804             :         // adding a package fails with a throw
     805           5 :         CATCH_REQUIRE_THROWS_MATCHES(
     806             :               db->add_package("name")
     807             :             , as2js::internal_error
     808             :             , Catch::Matchers::ExceptionMessage(
     809             :                       "internal_error: attempting to add a package to the database before the database was loaded."));
     810             : 
     811             :         // the find_packages() function returns nothing
     812           3 :         as2js::database::package::vector_t v(db->find_packages("name"));
     813           1 :         CATCH_REQUIRE(v.empty());
     814             : 
     815             :         // now test a load()
     816           1 :         CATCH_REQUIRE(db->load("test.db"));
     817             : 
     818             :         // a second time returns true also
     819           1 :         CATCH_REQUIRE(db->load("test.db"));
     820             : 
     821           3 :         as2js::database::package::pointer_t p1(db->add_package("p1"));
     822           3 :         as2js::database::element::pointer_t e1(p1->add_element("e1"));
     823           1 :         e1->set_type("type-e1");
     824           1 :         e1->set_filename("e1.as");
     825           1 :         e1->set_line(33);
     826           3 :         as2js::database::element::pointer_t e2(p1->add_element("e2"));
     827           1 :         e2->set_type("type-e2");
     828           1 :         e2->set_filename("e2.as");
     829           1 :         e2->set_line(66);
     830           3 :         as2js::database::element::pointer_t e3(p1->add_element("e3"));
     831           1 :         e3->set_type("type-e3");
     832           1 :         e3->set_filename("e3.as");
     833           1 :         e3->set_line(99);
     834             : 
     835           3 :         as2js::database::package::pointer_t p2(db->add_package("p2"));
     836           3 :         as2js::database::element::pointer_t e4(p2->add_element("e4"));
     837           1 :         e4->set_type("type-e4");
     838           1 :         e4->set_filename("e4.as");
     839           1 :         e4->set_line(44);
     840           3 :         as2js::database::element::pointer_t e5(p2->add_element("e5"));
     841           1 :         e5->set_type("type-e5");
     842           1 :         e5->set_filename("e5.as");
     843           1 :         e5->set_line(88);
     844           3 :         as2js::database::element::pointer_t e6(p2->add_element("e6"));
     845           1 :         e6->set_type("type-e6");
     846           1 :         e6->set_filename("e6.as");
     847           1 :         e6->set_line(11);
     848             : 
     849           1 :         db->save();
     850             : 
     851           1 :         CATCH_REQUIRE(db->get_package("p1") == p1);
     852           1 :         CATCH_REQUIRE(db->get_package("p2") == p2);
     853             : 
     854           3 :         as2js::database::package::pointer_t q(db->get_package("p1"));
     855           1 :         CATCH_REQUIRE(q == p1);
     856           3 :         as2js::database::package::pointer_t r(db->get_package("p2"));
     857           1 :         CATCH_REQUIRE(r == p2);
     858             : 
     859           1 :         as2js::database::pointer_t qdb(new as2js::database);
     860           1 :         CATCH_REQUIRE(qdb->load("test.db"));
     861             : 
     862           3 :         as2js::database::package::pointer_t np1(qdb->get_package("p1"));
     863           3 :         as2js::database::element::pointer_t ne1(np1->get_element("e1"));
     864           1 :         CATCH_REQUIRE(ne1->get_type() == "type-e1");
     865           1 :         CATCH_REQUIRE(ne1->get_filename() == "e1.as");
     866           1 :         CATCH_REQUIRE(ne1->get_line() == 33);
     867           3 :         as2js::database::element::pointer_t ne2(np1->get_element("e2"));
     868           1 :         CATCH_REQUIRE(ne2->get_type() == "type-e2");
     869           1 :         CATCH_REQUIRE(ne2->get_filename() == "e2.as");
     870           1 :         CATCH_REQUIRE(ne2->get_line() == 66);
     871           3 :         as2js::database::element::pointer_t ne3(np1->get_element("e3"));
     872           1 :         CATCH_REQUIRE(ne3->get_type() == "type-e3");
     873           1 :         CATCH_REQUIRE(ne3->get_filename() == "e3.as");
     874           1 :         CATCH_REQUIRE(ne3->get_line() == 99);
     875           3 :         as2js::database::package::pointer_t np2(qdb->get_package("p2"));
     876           3 :         as2js::database::element::pointer_t ne4(np2->get_element("e4"));
     877           1 :         CATCH_REQUIRE(ne4->get_type() == "type-e4");
     878           1 :         CATCH_REQUIRE(ne4->get_filename() == "e4.as");
     879           1 :         CATCH_REQUIRE(ne4->get_line() == 44);
     880           3 :         as2js::database::element::pointer_t ne5(np2->get_element("e5"));
     881           1 :         CATCH_REQUIRE(ne5->get_type() == "type-e5");
     882           1 :         CATCH_REQUIRE(ne5->get_filename() == "e5.as");
     883           1 :         CATCH_REQUIRE(ne5->get_line() == 88);
     884           3 :         as2js::database::element::pointer_t ne6(np2->get_element("e6"));
     885           1 :         CATCH_REQUIRE(ne6->get_type() == "type-e6");
     886           1 :         CATCH_REQUIRE(ne6->get_filename() == "e6.as");
     887           1 :         CATCH_REQUIRE(ne6->get_line() == 11);
     888             : 
     889           3 :         as2js::database::package::vector_t np1a(qdb->find_packages("p1"));
     890           1 :         CATCH_REQUIRE(np1a.size() == 1);
     891           1 :         CATCH_REQUIRE(np1a[0] == np1);
     892           3 :         as2js::database::package::vector_t np2a(qdb->find_packages("p2"));
     893           1 :         CATCH_REQUIRE(np2a.size() == 1);
     894           1 :         CATCH_REQUIRE(np2a[0] == np2);
     895           3 :         as2js::database::package::vector_t np3a(qdb->find_packages("p*"));
     896           1 :         CATCH_REQUIRE(np3a.size() == 2);
     897           1 :         CATCH_REQUIRE(np3a[0] == np1);
     898           1 :         CATCH_REQUIRE(np3a[1] == np2);
     899             : 
     900             :         // done with that one
     901           1 :         unlink("test.db");
     902           1 :     }
     903           5 :     CATCH_END_SECTION()
     904             : 
     905           5 :     CATCH_START_SECTION("db_database: invalid file")
     906             :     {
     907             :         {
     908           1 :             std::ofstream db_file;
     909           1 :             db_file.open("t1.db");
     910           1 :             CATCH_REQUIRE(db_file.is_open());
     911             :             db_file << "// db file\n"
     912           1 :                     << "an invalid file\n";
     913           1 :         }
     914             : 
     915           1 :         as2js::database::pointer_t pdb(new as2js::database);
     916           1 :         CATCH_REQUIRE(!pdb->load("t1.db"));
     917             :         // make sure we can still create a package (because here f_value
     918             :         // is null)
     919           3 :         as2js::database::package::pointer_t tp(pdb->add_package("another"));
     920           1 :         CATCH_REQUIRE(!!tp);
     921             : 
     922           1 :         unlink("t1.db");
     923           1 :     }
     924           5 :     CATCH_END_SECTION()
     925             : 
     926           5 :     CATCH_START_SECTION("db_database: NULL db")
     927             :     {
     928             :         {
     929           1 :             std::ofstream db_file;
     930           1 :             db_file.open("t2.db");
     931           1 :             CATCH_REQUIRE(db_file.is_open());
     932             :             db_file << "// db file\n"
     933           1 :                     << "null\n";
     934           1 :         }
     935             : 
     936           1 :         as2js::database::pointer_t pdb(new as2js::database);
     937           1 :         CATCH_REQUIRE(pdb->load("t2.db"));
     938           3 :         as2js::database::package::vector_t np(pdb->find_packages("*"));
     939           1 :         CATCH_REQUIRE(np.empty());
     940             : 
     941           1 :         unlink("t2.db");
     942           1 :     }
     943           5 :     CATCH_END_SECTION()
     944             : 
     945           5 :     CATCH_START_SECTION("db_database: unexpected string")
     946             :     {
     947             :         {
     948           1 :             std::ofstream db_file;
     949           1 :             db_file.open("t3.db");
     950           1 :             CATCH_REQUIRE(db_file.is_open());
     951             :             db_file << "// db file\n"
     952           1 :                     << "\"unexpected string\"\n";
     953           1 :         }
     954             : 
     955           1 :         test_callback tc;
     956             : 
     957           1 :         test_callback::expected_t expected1;
     958           1 :         expected1.f_message_level = as2js::message_level_t::MESSAGE_LEVEL_ERROR;
     959           1 :         expected1.f_error_code = as2js::err_code_t::AS_ERR_UNEXPECTED_DATABASE;
     960           1 :         expected1.f_pos.set_filename("t3.db");
     961           1 :         expected1.f_pos.set_function("unknown-func");
     962           1 :         expected1.f_message = "A database must be defined as a json object, or set to \"null\".";
     963           1 :         tc.f_expected.push_back(expected1);
     964             : 
     965           1 :         as2js::database::pointer_t sdb(new as2js::database);
     966           1 :         CATCH_REQUIRE(!sdb->load("t3.db"));
     967           1 :         tc.got_called();
     968             : 
     969           3 :         as2js::database::package::vector_t np(sdb->find_packages("*"));
     970           1 :         CATCH_REQUIRE(np.empty());
     971             : 
     972           1 :         unlink("t3.db");
     973           1 :     }
     974           5 :     CATCH_END_SECTION()
     975             : 
     976           5 :     CATCH_START_SECTION("db_database: invalid object")
     977             :     {
     978             :         {
     979           1 :             std::ofstream db_file;
     980           1 :             db_file.open("t4.db");
     981           1 :             CATCH_REQUIRE(db_file.is_open());
     982             :             db_file << "// db file\n"
     983           1 :                     << "{\"invalid\":\"object-here\"}\n";
     984           1 :         }
     985             : 
     986           1 :         test_callback tc;
     987             : 
     988           1 :         test_callback::expected_t expected1;
     989           1 :         expected1.f_message_level = as2js::message_level_t::MESSAGE_LEVEL_ERROR;
     990           1 :         expected1.f_error_code = as2js::err_code_t::AS_ERR_UNEXPECTED_DATABASE;
     991           1 :         expected1.f_pos.set_filename("t4.db");
     992           1 :         expected1.f_pos.set_function("unknown-func");
     993           1 :         expected1.f_message = "A database is expected to be an object of object packages composed of elements.";
     994           1 :         tc.f_expected.push_back(expected1);
     995             : 
     996           1 :         as2js::database::pointer_t sdb(new as2js::database);
     997           1 :         CATCH_REQUIRE(!sdb->load("t4.db"));
     998           1 :         tc.got_called();
     999             : 
    1000           3 :         as2js::database::package::vector_t np(sdb->find_packages("*"));
    1001           1 :         CATCH_REQUIRE(np.empty());
    1002             : 
    1003           1 :         unlink("t4.db");
    1004           1 :     }
    1005           5 :     CATCH_END_SECTION()
    1006           5 : }
    1007             : 
    1008             : 
    1009             : 
    1010             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.14