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
|