Line data Source code
1 : // Copyright (c) 2006-2021 Made to Order Software Corp. All Rights Reserved
2 : //
3 : // https://snapwebsites.org/project/cppthread
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 2 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 along
17 : // with this program; if not, write to the Free Software Foundation, Inc.,
18 : // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 :
20 : // self
21 : //
22 : #include "catch_main.h"
23 :
24 : #include "plugin_testme.h"
25 :
26 :
27 : // cppthread lib
28 : //
29 : #include <cppthread/plugins.h>
30 :
31 :
32 : // snapdev lib
33 : //
34 : #include <snapdev/not_reached.h>
35 :
36 :
37 : // C++ lib
38 : //
39 : #include <fstream>
40 :
41 :
42 : // C lib
43 : //
44 : #include <unistd.h>
45 : #include <sys/stat.h>
46 : #include <sys/types.h>
47 :
48 :
49 : // last include
50 : //
51 : #include <snapdev/poison.h>
52 :
53 :
54 :
55 :
56 :
57 12 : CATCH_TEST_CASE("plugin_paths", "[plugins] [paths]")
58 : {
59 20 : CATCH_START_SECTION("empty size/at when empty")
60 : {
61 2 : cppthread::plugin_paths p;
62 :
63 1 : CATCH_REQUIRE(p.size() == 0);
64 :
65 22 : for(int idx(-10); idx <= 10; ++idx)
66 : {
67 21 : CATCH_REQUIRE(p.at(idx) == std::string());
68 : }
69 : }
70 : CATCH_END_SECTION()
71 :
72 20 : CATCH_START_SECTION("canonicalize empty path")
73 : {
74 2 : cppthread::plugin_paths p;
75 :
76 1 : CATCH_REQUIRE_FALSE(p.get_allow_redirects());
77 1 : CATCH_REQUIRE_THROWS_MATCHES(
78 : p.canonicalize(cppthread::plugin_paths::path_t())
79 : , cppthread::cppthread_invalid_error
80 : , Catch::Matchers::ExceptionMessage(
81 : "cppthread_exception: path cannot be an empty string."));
82 :
83 1 : p.set_allow_redirects(true);
84 1 : CATCH_REQUIRE(p.get_allow_redirects());
85 1 : CATCH_REQUIRE_THROWS_MATCHES(
86 : p.canonicalize(cppthread::plugin_paths::path_t())
87 : , cppthread::cppthread_invalid_error
88 : , Catch::Matchers::ExceptionMessage(
89 : "cppthread_exception: path cannot be an empty string."));
90 :
91 1 : p.set_allow_redirects(false);
92 1 : CATCH_REQUIRE_FALSE(p.get_allow_redirects());
93 1 : CATCH_REQUIRE_THROWS_MATCHES(
94 : p.canonicalize(cppthread::plugin_paths::path_t())
95 : , cppthread::cppthread_invalid_error
96 : , Catch::Matchers::ExceptionMessage(
97 : "cppthread_exception: path cannot be an empty string."));
98 : }
99 : CATCH_END_SECTION()
100 :
101 20 : CATCH_START_SECTION("canonicalize base root path")
102 : {
103 11 : for(int idx(1); idx <= 10; ++idx)
104 : {
105 20 : cppthread::plugin_paths p;
106 :
107 20 : cppthread::plugin_paths::path_t root(idx, '/');
108 10 : CATCH_REQUIRE(p.canonicalize(root) == "/");
109 10 : p.set_allow_redirects(true);
110 10 : CATCH_REQUIRE(p.canonicalize(root) == "/");
111 10 : p.set_allow_redirects(false);
112 10 : CATCH_REQUIRE(p.canonicalize(root) == "/");
113 : }
114 : }
115 : CATCH_END_SECTION()
116 :
117 20 : CATCH_START_SECTION("canonicalize root path with one \"..\"")
118 : {
119 1 : std::vector<cppthread::plugin_paths::path_t> paths =
120 : {
121 : "this",
122 : "long",
123 : "..",
124 : "short",
125 : "root",
126 : "path",
127 2 : };
128 :
129 6 : for(cppthread::plugin_paths::path_t::size_type l(1); l < paths.size(); ++l)
130 : {
131 10 : cppthread::plugin_paths p;
132 10 : cppthread::plugin_paths::path_t expected;
133 5 : int count(rand() % 10 + 1);
134 10 : cppthread::plugin_paths::path_t path(count , '/');
135 20 : for(cppthread::plugin_paths::path_t::size_type c(0); c < l; ++c)
136 : {
137 30 : if(paths[c] != ".."
138 15 : && (c + 1 >= l || paths[c + 1] != ".."))
139 : {
140 9 : expected += '/';
141 9 : expected += paths[c];
142 : }
143 :
144 15 : path += paths[c];
145 :
146 15 : count = rand() % 10 + 1;
147 30 : cppthread::plugin_paths::path_t sep(count , '/');
148 15 : path += sep;
149 : }
150 :
151 : //std::cerr << "+++ expected = [" << expected << "] and path [" << path << "]\n";
152 :
153 : // verify that we got expected as a canonicalize path
154 : //
155 5 : CATCH_CHECK(p.canonicalize(expected) == expected);
156 5 : CATCH_REQUIRE(p.canonicalize(path) == expected);
157 :
158 5 : p.set_allow_redirects(true);
159 5 : CATCH_CHECK(p.canonicalize(expected) == expected);
160 5 : CATCH_REQUIRE(p.canonicalize(path) == expected);
161 :
162 5 : p.set_allow_redirects(false);
163 5 : CATCH_CHECK(p.canonicalize(expected) == expected);
164 5 : CATCH_REQUIRE(p.canonicalize(path) == expected);
165 : }
166 : }
167 : CATCH_END_SECTION()
168 :
169 20 : CATCH_START_SECTION("canonicalize root path with too many \"..\"")
170 : {
171 2 : cppthread::plugin_paths p;
172 :
173 1 : p.set_allow_redirects(false);
174 1 : CATCH_REQUIRE(p.canonicalize("/this/long/../../../..//") == "/");
175 1 : p.set_allow_redirects(true);
176 1 : CATCH_REQUIRE(p.canonicalize("/this/long/../../../..//") == "/");
177 :
178 1 : p.set_allow_redirects(false);
179 1 : CATCH_REQUIRE(p.canonicalize("/this//long/../../../../root/home/path/") == "/root/home/path");
180 1 : p.set_allow_redirects(true);
181 1 : CATCH_REQUIRE(p.canonicalize("/this//long/../../../../root/home/path/") == "/root/home/path");
182 1 : p.set_allow_redirects(false);
183 1 : CATCH_REQUIRE(p.canonicalize("/this/long/../..//./../root/home/path/") == "/root/home/path");
184 1 : p.set_allow_redirects(true);
185 1 : CATCH_REQUIRE(p.canonicalize("/this/long/../..//./../root/home/path/") == "/root/home/path");
186 1 : p.set_allow_redirects(false);
187 1 : CATCH_REQUIRE(p.canonicalize("/this/long/.././../../root//home/path/") == "/root/home/path");
188 1 : p.set_allow_redirects(true);
189 1 : CATCH_REQUIRE(p.canonicalize("/this/long/.././../../root//home/path/") == "/root/home/path");
190 : }
191 : CATCH_END_SECTION()
192 :
193 20 : CATCH_START_SECTION("canonicalize relative path with \".\" and \"..\"")
194 : {
195 2 : cppthread::plugin_paths p;
196 :
197 1 : CATCH_REQUIRE(p.canonicalize("this/./relative/./angle/.././path//cleaned/up") == "this/relative/path/cleaned/up");
198 1 : p.set_allow_redirects(true);
199 1 : CATCH_REQUIRE(p.canonicalize("this/./relative/./angle/.././path//cleaned/up") == "this/relative/path/cleaned/up");
200 1 : p.set_allow_redirects(false);
201 1 : CATCH_REQUIRE(p.canonicalize("this/./relative/./angle/.././path//cleaned/up") == "this/relative/path/cleaned/up");
202 : }
203 : CATCH_END_SECTION()
204 :
205 20 : CATCH_START_SECTION("canonicalize relative path with too many \"..\"")
206 : {
207 2 : cppthread::plugin_paths p;
208 :
209 1 : p.set_allow_redirects(true);
210 1 : CATCH_REQUIRE(p.canonicalize("this/long/../../../..//") == "../..");
211 1 : p.set_allow_redirects(false);
212 1 : CATCH_REQUIRE_THROWS_MATCHES(
213 : p.canonicalize("this/long/../../../..//")
214 : , cppthread::cppthread_invalid_error
215 : , Catch::Matchers::ExceptionMessage(
216 : "cppthread_exception: the path \"this/long/../../../..//\" going outside of the allowed range."));
217 :
218 1 : p.set_allow_redirects(true);
219 1 : CATCH_REQUIRE(p.canonicalize("this//long/../../../../root/home/path/") == "../../root/home/path");
220 1 : p.set_allow_redirects(false);
221 1 : CATCH_REQUIRE_THROWS_MATCHES(
222 : p.canonicalize("this//long/../../../../root/home/path/")
223 : , cppthread::cppthread_invalid_error
224 : , Catch::Matchers::ExceptionMessage(
225 : "cppthread_exception: the path \"this//long/../../../../root/home/path/\" going outside of the allowed range."));
226 :
227 1 : p.set_allow_redirects(true);
228 1 : CATCH_REQUIRE(p.canonicalize("this/long/..//./../../root/home/path/") == "../root/home/path");
229 1 : p.set_allow_redirects(false);
230 1 : CATCH_REQUIRE_THROWS_MATCHES(
231 : p.canonicalize("this/long/..//./../../root/home/path/")
232 : , cppthread::cppthread_invalid_error
233 : , Catch::Matchers::ExceptionMessage(
234 : "cppthread_exception: the path \"this/long/..//./../../root/home/path/\" going outside of the allowed range."));
235 :
236 1 : p.set_allow_redirects(true);
237 1 : CATCH_REQUIRE(p.canonicalize("this/long/../.././../root//home//path//") == "../root/home/path");
238 1 : p.set_allow_redirects(false);
239 1 : CATCH_REQUIRE_THROWS_MATCHES(
240 : p.canonicalize("this/long/../.././../root//home//path//")
241 : , cppthread::cppthread_invalid_error
242 : , Catch::Matchers::ExceptionMessage(
243 : "cppthread_exception: the path \"this/long/../.././../root//home//path//\" going outside of the allowed range."));
244 : }
245 : CATCH_END_SECTION()
246 :
247 20 : CATCH_START_SECTION("push the same paths")
248 : {
249 2 : cppthread::plugin_paths p;
250 :
251 1 : p.push("path/one");
252 1 : p.push("path/two");
253 1 : p.push("path/three");
254 1 : p.push("path/two");
255 1 : p.push("path/one");
256 :
257 1 : CATCH_REQUIRE(p.size() == 3);
258 1 : CATCH_REQUIRE(p.at(0) == "path/one");
259 1 : CATCH_REQUIRE(p.at(1) == "path/two");
260 1 : CATCH_REQUIRE(p.at(2) == "path/three");
261 1 : CATCH_REQUIRE(p.at(3) == "");
262 :
263 1 : p.erase("path/four");
264 :
265 1 : CATCH_REQUIRE(p.size() == 3);
266 1 : CATCH_REQUIRE(p.at(0) == "path/one");
267 1 : CATCH_REQUIRE(p.at(1) == "path/two");
268 1 : CATCH_REQUIRE(p.at(2) == "path/three");
269 1 : CATCH_REQUIRE(p.at(3) == "");
270 :
271 1 : p.erase("path/two");
272 :
273 1 : CATCH_REQUIRE(p.size() == 2);
274 1 : CATCH_REQUIRE(p.at(0) == "path/one");
275 1 : CATCH_REQUIRE(p.at(1) == "path/three");
276 1 : CATCH_REQUIRE(p.at(2) == "");
277 1 : CATCH_REQUIRE(p.at(3) == "");
278 :
279 1 : p.erase("path/one");
280 :
281 1 : CATCH_REQUIRE(p.size() == 1);
282 1 : CATCH_REQUIRE(p.at(0) == "path/three");
283 1 : CATCH_REQUIRE(p.at(1) == "");
284 1 : CATCH_REQUIRE(p.at(2) == "");
285 1 : CATCH_REQUIRE(p.at(3) == "");
286 :
287 1 : p.erase("path/three");
288 :
289 1 : CATCH_REQUIRE(p.size() == 0);
290 1 : CATCH_REQUIRE(p.at(0) == "");
291 1 : CATCH_REQUIRE(p.at(1) == "");
292 1 : CATCH_REQUIRE(p.at(2) == "");
293 1 : CATCH_REQUIRE(p.at(3) == "");
294 : }
295 : CATCH_END_SECTION()
296 :
297 20 : CATCH_START_SECTION("push invalid path")
298 : {
299 2 : cppthread::plugin_paths p;
300 :
301 1 : CATCH_REQUIRE_THROWS_MATCHES(
302 : p.canonicalize("this/long/../.././../root//home//path//")
303 : , cppthread::cppthread_invalid_error
304 : , Catch::Matchers::ExceptionMessage(
305 : "cppthread_exception: the path \"this/long/../.././../root//home//path//\" going outside of the allowed range."));
306 : }
307 : CATCH_END_SECTION()
308 :
309 20 : CATCH_START_SECTION("add paths")
310 : {
311 2 : cppthread::plugin_paths p;
312 :
313 1 : p.set_allow_redirects(true);
314 1 : p.add("this/long/../../../..//"
315 : ":this//long/../../../../root/home/path/"
316 : ":this/long/..//./../../root/home/path/"
317 : ":this/long/../.././..//home/user/path//");
318 1 : CATCH_REQUIRE(p.size() == 4);
319 1 : CATCH_REQUIRE(p.at(0) == "../..");
320 1 : CATCH_REQUIRE(p.at(1) == "../../root/home/path");
321 1 : CATCH_REQUIRE(p.at(2) == "../root/home/path");
322 1 : CATCH_REQUIRE(p.at(3) == "../home/user/path");
323 : }
324 : CATCH_END_SECTION()
325 10 : }
326 :
327 :
328 :
329 11 : CATCH_TEST_CASE("plugin_names", "[plugins] [names]")
330 : {
331 18 : CATCH_START_SECTION("empty by default")
332 : {
333 2 : cppthread::plugin_paths p;
334 1 : p.add("/usr/local/lib/snaplogger/plugins:/usr/lib/snaplogger/plugins");
335 :
336 2 : cppthread::plugin_names n(p);
337 :
338 1 : CATCH_REQUIRE(n.names().empty());
339 : }
340 : CATCH_END_SECTION()
341 :
342 18 : CATCH_START_SECTION("validate names")
343 : {
344 2 : cppthread::plugin_paths p;
345 1 : p.add("/usr/local/lib/snaplogger/plugins:/usr/lib/snaplogger/plugins");
346 :
347 2 : cppthread::plugin_names n(p);
348 :
349 1 : CATCH_CHECK(n.validate("_"));
350 1 : CATCH_CHECK(n.validate("_valid"));
351 1 : CATCH_CHECK(n.validate("_identifier6"));
352 1 : CATCH_CHECK(n.validate("_9"));
353 :
354 1 : CATCH_CHECK_FALSE(n.validate(""));
355 1 : CATCH_CHECK_FALSE(n.validate(cppthread::plugin_names::name_t()));
356 1 : CATCH_CHECK_FALSE(n.validate("0"));
357 1 : CATCH_CHECK_FALSE(n.validate("9_"));
358 1 : CATCH_CHECK_FALSE(n.validate("dotted.word"));
359 1 : CATCH_CHECK_FALSE(n.validate(".dot"));
360 1 : CATCH_CHECK_FALSE(n.validate("dashed-word"));
361 1 : CATCH_CHECK_FALSE(n.validate("-dash"));
362 :
363 27 : for(int c('a'); c <= 'z'; ++c)
364 : {
365 52 : std::string word;
366 26 : word += c;
367 26 : CATCH_CHECK(n.validate(word));
368 : }
369 :
370 27 : for(int c('A'); c <= 'Z'; ++c)
371 : {
372 52 : std::string word;
373 26 : word += c;
374 26 : CATCH_CHECK(n.validate(word));
375 : }
376 :
377 11 : for(int c('0'); c <= '9'; ++c)
378 : {
379 20 : std::string word;
380 10 : word += '_';
381 10 : word += c;
382 10 : CATCH_CHECK(n.validate(word));
383 : }
384 :
385 128 : for(int c(1); c <= 0x7F; ++c)
386 : {
387 190 : if(c == '_'
388 126 : || (c >= 'a' && c <= 'z')
389 100 : || (c >= 'A' && c <= 'Z')
390 74 : || (c >= '0' && c <= '9'))
391 : {
392 63 : continue;
393 : }
394 128 : std::string word;
395 64 : word += '_';
396 64 : word += c;
397 64 : CATCH_CHECK_FALSE(n.validate(word));
398 : }
399 : }
400 : CATCH_END_SECTION()
401 :
402 18 : CATCH_START_SECTION("validate non-script names")
403 : {
404 2 : cppthread::plugin_paths p;
405 1 : p.add("/usr/local/lib/snaplogger/plugins:/usr/lib/snaplogger/plugins");
406 :
407 2 : cppthread::plugin_names n(p, true);
408 :
409 1 : CATCH_CHECK(n.validate("_"));
410 1 : CATCH_CHECK(n.validate("_valid"));
411 1 : CATCH_CHECK(n.validate("_identifier6"));
412 1 : CATCH_CHECK(n.validate("_9"));
413 :
414 1 : CATCH_CHECK_FALSE(n.validate(""));
415 1 : CATCH_CHECK_FALSE(n.validate(cppthread::plugin_names::name_t()));
416 1 : CATCH_CHECK_FALSE(n.validate("0"));
417 1 : CATCH_CHECK_FALSE(n.validate("9_"));
418 1 : CATCH_CHECK_FALSE(n.validate("dotted.word"));
419 1 : CATCH_CHECK_FALSE(n.validate(".dot"));
420 1 : CATCH_CHECK_FALSE(n.validate("dashed-word"));
421 1 : CATCH_CHECK_FALSE(n.validate("-dash"));
422 :
423 27 : for(int c('a'); c <= 'z'; ++c)
424 : {
425 52 : std::string word;
426 26 : word += c;
427 26 : CATCH_CHECK(n.validate(word));
428 : }
429 :
430 27 : for(int c('A'); c <= 'Z'; ++c)
431 : {
432 52 : std::string word;
433 26 : word += c;
434 26 : CATCH_CHECK(n.validate(word));
435 : }
436 :
437 11 : for(int c('0'); c <= '9'; ++c)
438 : {
439 20 : std::string word;
440 10 : word += '_';
441 10 : word += c;
442 10 : CATCH_CHECK(n.validate(word));
443 : }
444 :
445 128 : for(int c(1); c <= 0x7F; ++c)
446 : {
447 190 : if(c == '_'
448 126 : || (c >= 'a' && c <= 'z')
449 100 : || (c >= 'A' && c <= 'Z')
450 74 : || (c >= '0' && c <= '9'))
451 : {
452 63 : continue;
453 : }
454 128 : std::string word;
455 64 : word += '_';
456 64 : word += c;
457 64 : CATCH_CHECK_FALSE(n.validate(word));
458 : }
459 :
460 1 : std::vector<std::string> const reserved_keywords = {
461 : "await"
462 : , "break"
463 : , "case"
464 : , "catch"
465 : , "class"
466 : , "const"
467 : , "continue"
468 : , "debugger"
469 : , "default"
470 : , "delete"
471 : , "do"
472 : , "else"
473 : , "enum"
474 : , "export"
475 : , "extends"
476 : , "false"
477 : , "finally"
478 : , "for"
479 : , "function"
480 : , "if"
481 : , "import"
482 : , "in"
483 : , "instanceof"
484 : , "new"
485 : , "null"
486 : , "return"
487 : , "super"
488 : , "switch"
489 : , "this"
490 : , "throw"
491 : , "true"
492 : , "try"
493 : , "typeof"
494 : , "var"
495 : , "void"
496 : , "while"
497 : , "with"
498 : , "yield"
499 2 : };
500 39 : for(auto k : reserved_keywords)
501 : {
502 38 : CATCH_CHECK_FALSE(n.validate(k));
503 : }
504 : }
505 : CATCH_END_SECTION()
506 :
507 18 : CATCH_START_SECTION("add one unknown and one known name")
508 : {
509 2 : cppthread::plugin_paths p;
510 1 : p.add(CMAKE_BINARY_DIR "/tests:/usr/local/lib/snaplogger/plugins:/usr/lib/snaplogger/plugins");
511 :
512 2 : cppthread::plugin_names n(p, true);
513 :
514 : // test with an obviously unexistant plugin
515 : //
516 2 : cppthread::plugin_names::filename_t filename(n.to_filename("unknown"));
517 1 : CATCH_REQUIRE(filename.empty());
518 :
519 : // test with the real thing
520 : //
521 1 : filename = n.to_filename("testme");
522 1 : CATCH_REQUIRE(filename == CMAKE_BINARY_DIR "/tests/libtestme.so");
523 :
524 : // the following creates fake plugins so we can test all possible
525 : // cases (there are 4 of them)
526 : //
527 : { // <name>.so
528 2 : std::string fake(CMAKE_BINARY_DIR "/tests/fake.so");
529 1 : unlink(fake.c_str());
530 : {
531 2 : std::ofstream out(fake);
532 1 : out << "fake plugin 1\n";
533 : }
534 1 : filename = n.to_filename("fake");
535 1 : CATCH_REQUIRE(filename.empty());
536 1 : chmod(fake.c_str(), 0755);
537 1 : filename = n.to_filename("fake");
538 1 : CATCH_REQUIRE(filename == fake);
539 1 : unlink(fake.c_str());
540 : }
541 : { // lib<name>.so
542 2 : std::string fake(CMAKE_BINARY_DIR "/tests/libfake.so");
543 1 : unlink(fake.c_str());
544 : {
545 2 : std::ofstream out(fake);
546 1 : out << "fake plugin 2\n";
547 : }
548 1 : filename = n.to_filename("fake");
549 1 : CATCH_REQUIRE(filename.empty());
550 1 : chmod(fake.c_str(), 0755);
551 1 : filename = n.to_filename("fake");
552 1 : CATCH_REQUIRE(filename == fake);
553 1 : unlink(fake.c_str());
554 : }
555 : { // <name>/<name>.so
556 2 : std::string subdir(CMAKE_BINARY_DIR "/tests/fake");
557 1 : mkdir(subdir.c_str(), 0750);
558 : {
559 2 : std::string fake(CMAKE_BINARY_DIR "/tests/fake/fake.so");
560 1 : unlink(fake.c_str());
561 : {
562 2 : std::ofstream out(fake);
563 1 : out << "fake plugin 3\n";
564 : }
565 1 : filename = n.to_filename("fake");
566 1 : CATCH_REQUIRE(filename.empty());
567 1 : chmod(fake.c_str(), 0755);
568 1 : filename = n.to_filename("fake");
569 1 : CATCH_REQUIRE(filename == fake);
570 1 : unlink(fake.c_str());
571 : }
572 : {
573 2 : std::string fake(CMAKE_BINARY_DIR "/tests/fake/libfake.so");
574 1 : unlink(fake.c_str());
575 : {
576 2 : std::ofstream out(fake);
577 1 : out << "fake plugin 4\n";
578 : }
579 1 : filename = n.to_filename("fake");
580 1 : CATCH_REQUIRE(filename.empty());
581 1 : chmod(fake.c_str(), 0755);
582 1 : filename = n.to_filename("fake");
583 1 : CATCH_REQUIRE(filename == fake);
584 1 : unlink(fake.c_str());
585 : }
586 1 : rmdir(subdir.c_str());
587 : }
588 : }
589 : CATCH_END_SECTION()
590 :
591 18 : CATCH_START_SECTION("test filename without any paths")
592 : {
593 2 : cppthread::plugin_paths p;
594 2 : cppthread::plugin_names n(p);
595 :
596 : // test with an obviously unexistant plugin
597 : //
598 2 : cppthread::plugin_names::filename_t filename(n.to_filename("unknown"));
599 1 : CATCH_REQUIRE(filename.empty());
600 :
601 : // test with the real thing
602 : //
603 1 : filename = n.to_filename("testme");
604 1 : CATCH_REQUIRE(filename.empty());
605 :
606 : // the following creates fake plugins so we can test all possible
607 : // cases (there are 4 of them)
608 : //
609 : { // <name>.so
610 2 : std::string fake("fake.so");
611 1 : unlink(fake.c_str());
612 : {
613 2 : std::ofstream out(fake);
614 1 : out << "fake plugin 1\n";
615 : }
616 1 : filename = n.to_filename("fake");
617 1 : CATCH_REQUIRE(filename.empty());
618 1 : chmod(fake.c_str(), 0755);
619 1 : filename = n.to_filename("fake");
620 1 : CATCH_REQUIRE(filename == "./" + fake);
621 1 : unlink(fake.c_str());
622 : }
623 : { // lib<name>.so
624 2 : std::string fake("libfake.so");
625 1 : unlink(fake.c_str());
626 : {
627 2 : std::ofstream out(fake);
628 1 : out << "fake plugin 2\n";
629 : }
630 1 : filename = n.to_filename("fake");
631 1 : CATCH_REQUIRE(filename.empty());
632 1 : chmod(fake.c_str(), 0755);
633 1 : filename = n.to_filename("fake");
634 1 : CATCH_REQUIRE(filename == "./" + fake);
635 1 : unlink(fake.c_str());
636 : }
637 : { // <name>/<name>.so
638 2 : std::string subdir("fake");
639 1 : mkdir(subdir.c_str(), 0750);
640 : {
641 2 : std::string fake("fake/fake.so");
642 1 : unlink(fake.c_str());
643 : {
644 2 : std::ofstream out(fake);
645 1 : out << "fake plugin 3\n";
646 : }
647 1 : filename = n.to_filename("fake");
648 1 : CATCH_REQUIRE(filename.empty());
649 1 : chmod(fake.c_str(), 0755);
650 1 : filename = n.to_filename("fake");
651 1 : CATCH_REQUIRE(filename == "./" + fake);
652 1 : unlink(fake.c_str());
653 : }
654 : {
655 2 : std::string fake("fake/libfake.so");
656 1 : unlink(fake.c_str());
657 : {
658 2 : std::ofstream out(fake);
659 1 : out << "fake plugin 4\n";
660 : }
661 1 : filename = n.to_filename("fake");
662 1 : CATCH_REQUIRE(filename.empty());
663 1 : chmod(fake.c_str(), 0755);
664 1 : filename = n.to_filename("fake");
665 1 : CATCH_REQUIRE(filename == "./" + fake);
666 1 : unlink(fake.c_str());
667 : }
668 1 : rmdir(subdir.c_str());
669 : }
670 : }
671 : CATCH_END_SECTION()
672 :
673 18 : CATCH_START_SECTION("add a new names by hand (push)")
674 : {
675 2 : cppthread::plugin_paths p;
676 1 : p.add(CMAKE_BINARY_DIR "/tests:/usr/local/lib/snaplogger/plugins:/usr/lib/snaplogger/plugins");
677 2 : cppthread::plugin_names n(p);
678 :
679 : // test with an obviously unexistant plugin
680 : //
681 1 : n.push("testme");
682 1 : CATCH_REQUIRE(n.names().size() == 1);
683 1 : CATCH_REQUIRE(n.names().begin()->second == CMAKE_BINARY_DIR "/tests/libtestme.so");
684 : }
685 : CATCH_END_SECTION()
686 :
687 18 : CATCH_START_SECTION("add a new names by hand (add)")
688 : {
689 2 : cppthread::plugin_paths p;
690 1 : p.add(CMAKE_BINARY_DIR "/tests:/usr/local/lib/snaplogger/plugins:/usr/lib/snaplogger/plugins");
691 2 : cppthread::plugin_names n(p);
692 :
693 : // TODO: look into having multiple plugins because that would allow
694 : // us to test ':'
695 : //
696 1 : n.add("testme");
697 1 : CATCH_REQUIRE(n.names().size() == 1);
698 1 : CATCH_REQUIRE(n.names().begin()->second == CMAKE_BINARY_DIR "/tests/libtestme.so");
699 : }
700 : CATCH_END_SECTION()
701 :
702 18 : CATCH_START_SECTION("add a names through the find_plugins() function")
703 : {
704 2 : cppthread::plugin_paths p;
705 1 : p.add(CMAKE_BINARY_DIR "/tests:/usr/local/lib/snaplogger/plugins:/usr/lib/snaplogger/plugins");
706 2 : cppthread::plugin_names n(p);
707 1 : n.find_plugins();
708 1 : CATCH_REQUIRE(n.names().size() == 1);
709 1 : CATCH_REQUIRE(n.names().begin()->second == CMAKE_BINARY_DIR "/tests/libtestme.so");
710 : }
711 : CATCH_END_SECTION()
712 :
713 18 : CATCH_START_SECTION("add invalid names")
714 : {
715 2 : cppthread::plugin_paths p;
716 1 : p.add(CMAKE_BINARY_DIR "/tests:/usr/local/lib/snaplogger/plugins:/usr/lib/snaplogger/plugins");
717 2 : cppthread::plugin_names n(p);
718 :
719 1 : CATCH_REQUIRE_THROWS_MATCHES(
720 : n.push("invalid-name")
721 : , cppthread::cppthread_invalid_error
722 : , Catch::Matchers::ExceptionMessage(
723 : "cppthread_exception: invalid plugin name in \"invalid-name\"."));
724 :
725 1 : CATCH_REQUIRE_THROWS_MATCHES(
726 : n.push("non_existant")
727 : , cppthread::cppthread_not_found
728 : , Catch::Matchers::ExceptionMessage(
729 : "cppthread_exception: plugin named \"non_existant\" not found in any of the specified paths."));
730 :
731 1 : CATCH_REQUIRE_THROWS_MATCHES(
732 : n.push("./libserver.so")
733 : , cppthread::cppthread_invalid_error
734 : , Catch::Matchers::ExceptionMessage(
735 : "cppthread_exception: the name \"server\" is reserved for the main running process."));
736 :
737 1 : CATCH_REQUIRE_THROWS_MATCHES(
738 : n.push("./libjuju1.23.so")
739 : , cppthread::cppthread_invalid_error
740 : , Catch::Matchers::ExceptionMessage(
741 : "cppthread_exception: invalid plugin name in \"juju1.23\" (from path \"./libjuju1.23.so\")."));
742 : }
743 : CATCH_END_SECTION()
744 9 : }
745 :
746 :
747 3 : CATCH_TEST_CASE("plugin_collection", "[plugins] [collection]")
748 : {
749 2 : CATCH_START_SECTION("load the plugin")
750 : {
751 2 : cppthread::plugin_paths p;
752 1 : p.add(CMAKE_BINARY_DIR "/tests:/usr/local/lib/snaplogger/plugins:/usr/lib/snaplogger/plugins");
753 2 : cppthread::plugin_names n(p);
754 1 : n.find_plugins();
755 2 : cppthread::plugin_collection c(n);
756 1 : optional_namespace::data_t d;
757 1 : d.f_value = 0xA987;
758 1 : c.set_data(&d);
759 1 : CATCH_REQUIRE(c.load_plugins());
760 2 : optional_namespace::testme::pointer_t r(c.get_plugin_by_name<optional_namespace::testme>("testme"));
761 1 : CATCH_REQUIRE(r != nullptr);
762 :
763 1 : cppthread::version_t const v(r->version());
764 1 : CATCH_CHECK(v.f_major == 5);
765 1 : CATCH_CHECK(v.f_minor == 3);
766 1 : CATCH_CHECK(v.f_patch == 0);
767 :
768 : //time_t m(last_modification());
769 :
770 1 : CATCH_REQUIRE(r->name() == "testme");
771 1 : CATCH_REQUIRE(r->filename() == CMAKE_BINARY_DIR "/tests/libtestme.so");
772 1 : CATCH_REQUIRE(r->description() == "a test plugin to make sure it all works.");
773 1 : CATCH_REQUIRE(r->help_uri() == "https://snapwebsites.org/");
774 1 : CATCH_REQUIRE(r->icon() == "cute.ico");
775 :
776 2 : cppthread::string_set_t tags(r->categorization_tags());
777 1 : CATCH_REQUIRE(tags.size() == 3);
778 1 : CATCH_REQUIRE(tags.find("test") != tags.end());
779 1 : CATCH_REQUIRE(tags.find("powerful") != tags.end());
780 1 : CATCH_REQUIRE(tags.find("software") != tags.end());
781 1 : CATCH_REQUIRE(tags.find("undefined") == tags.end());
782 :
783 : // at this time we have a single plugins so not dependencies
784 : //
785 2 : cppthread::string_set_t dependencies(r->dependencies());
786 1 : CATCH_REQUIRE(dependencies.empty());
787 :
788 2 : cppthread::string_set_t conflicts(r->conflicts());
789 1 : CATCH_REQUIRE(conflicts.size() == 3);
790 1 : CATCH_REQUIRE(conflicts.find("other_test") != conflicts.end());
791 1 : CATCH_REQUIRE(conflicts.find("power_test") != conflicts.end());
792 1 : CATCH_REQUIRE(conflicts.find("unknown") != conflicts.end());
793 1 : CATCH_REQUIRE(conflicts.find("undefined") == conflicts.end());
794 :
795 1 : cppthread::string_set_t suggestions(r->suggestions());
796 :
797 : // TODO: this requires a signal...
798 : //std::string const msg(r->it_worked());
799 : //CATCH_CHECK(msg == "it worked, didn't it?");
800 : }
801 : CATCH_END_SECTION()
802 7 : }
803 :
804 :
805 :
806 :
807 : // vim: ts=4 sw=4 et
|