Line data Source code
1 : // Copyright (c) 2021-2024 Made to Order Software Corp. All Rights Reserved
2 : //
3 : // https://snapwebsites.org/project/snapdev
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 : /** \file
20 : * \brief Verify that the path functions work.
21 : *
22 : * This file implements tests for the pathinfo function.
23 : */
24 :
25 : // self
26 : //
27 : #include <snapdev/pathinfo.h>
28 :
29 : #include "catch_main.h"
30 :
31 :
32 : // C++ lib
33 : //
34 : #include <set>
35 :
36 :
37 : // last include
38 : //
39 : #include <snapdev/poison.h>
40 :
41 :
42 :
43 :
44 5 : CATCH_TEST_CASE("pathinfo_replace_suffix", "[filename][pathinfo]")
45 : {
46 5 : CATCH_START_SECTION("pathinfo: replace existing suffix")
47 : {
48 1 : CATCH_REQUIRE(snapdev::pathinfo::replace_suffix<std::string>(
49 : "/full/path/example/pathinfo.cpp"
50 : , ".cpp"
51 : , ".h") == "/full/path/example/pathinfo.h");
52 :
53 1 : CATCH_REQUIRE(snapdev::pathinfo::replace_suffix<std::string>(
54 : "/full/path/example/pathinfo.h"
55 : , ".h"
56 : , ".cpp") == "/full/path/example/pathinfo.cpp");
57 :
58 1 : CATCH_REQUIRE(snapdev::pathinfo::replace_suffix<std::string>(
59 : "relative/path/pathinfo.cpp"
60 : , ".cpp"
61 : , ".h") == "relative/path/pathinfo.h");
62 :
63 1 : CATCH_REQUIRE(snapdev::pathinfo::replace_suffix<std::string>(
64 : "relative/path/pathinfo.h"
65 : , ".h"
66 : , ".cpp") == "relative/path/pathinfo.cpp");
67 :
68 1 : CATCH_REQUIRE(snapdev::pathinfo::replace_suffix<std::string>(
69 : "no-path.cpp"
70 : , ".cpp"
71 : , ".h") == "no-path.h");
72 :
73 1 : CATCH_REQUIRE(snapdev::pathinfo::replace_suffix<std::string>(
74 : "no-path.h"
75 : , ".h"
76 : , ".cpp") == "no-path.cpp");
77 : }
78 5 : CATCH_END_SECTION()
79 :
80 5 : CATCH_START_SECTION("pathinfo: replace non-existant suffix")
81 : {
82 2 : std::string full_path_c("/full/path/example/pathinfo.c");
83 2 : std::string full_path_hpp("/full/path/example/pathinfo.hpp");
84 :
85 1 : CATCH_REQUIRE(snapdev::pathinfo::replace_suffix(
86 : full_path_c
87 : , ".cpp"
88 : , ".h") == "/full/path/example/pathinfo.c.h");
89 :
90 1 : CATCH_REQUIRE(snapdev::pathinfo::replace_suffix(
91 : full_path_hpp
92 : , ".h"
93 : , ".cpp") == "/full/path/example/pathinfo.hpp.cpp");
94 :
95 2 : std::string relative_path_c("relative/path/pathinfo.c");
96 2 : std::string relative_path_hpp("relative/path/pathinfo.hpp");
97 :
98 1 : CATCH_REQUIRE(snapdev::pathinfo::replace_suffix(
99 : relative_path_c
100 : , ".cpp"
101 : , ".h") == "relative/path/pathinfo.c.h");
102 :
103 1 : CATCH_REQUIRE(snapdev::pathinfo::replace_suffix(
104 : relative_path_hpp
105 : , ".h"
106 : , ".cpp") == "relative/path/pathinfo.hpp.cpp");
107 :
108 2 : std::string no_path_c("no-path.c");
109 2 : std::string no_path_hpp("no-path.hpp");
110 :
111 1 : CATCH_REQUIRE(snapdev::pathinfo::replace_suffix(
112 : no_path_c
113 : , ".cpp"
114 : , ".h") == "no-path.c.h");
115 :
116 1 : CATCH_REQUIRE(snapdev::pathinfo::replace_suffix(
117 : no_path_hpp
118 : , ".h"
119 : , ".cpp") == "no-path.hpp.cpp");
120 1 : }
121 5 : CATCH_END_SECTION()
122 :
123 5 : CATCH_START_SECTION("pathinfo: remove suffix when present")
124 : {
125 1 : CATCH_REQUIRE(snapdev::pathinfo::replace_suffix<std::string>(
126 : "/full/path/example/pathinfo.cpp"
127 : , ".cpp") == "/full/path/example/pathinfo");
128 :
129 1 : CATCH_REQUIRE(snapdev::pathinfo::replace_suffix<std::string>(
130 : "/full/path/example/pathinfo.h"
131 : , ".h") == "/full/path/example/pathinfo");
132 :
133 1 : CATCH_REQUIRE(snapdev::pathinfo::replace_suffix<std::string>(
134 : "relative/path/pathinfo.cpp"
135 : , ".cpp") == "relative/path/pathinfo");
136 :
137 1 : CATCH_REQUIRE(snapdev::pathinfo::replace_suffix<std::string>(
138 : "relative/path/pathinfo.h"
139 : , ".h") == "relative/path/pathinfo");
140 :
141 1 : CATCH_REQUIRE(snapdev::pathinfo::replace_suffix<std::string>(
142 : "no-path.cpp"
143 : , ".cpp") == "no-path");
144 :
145 1 : CATCH_REQUIRE(snapdev::pathinfo::replace_suffix<std::string>(
146 : "no-path.h"
147 : , ".h") == "no-path");
148 : }
149 5 : CATCH_END_SECTION()
150 :
151 5 : CATCH_START_SECTION("pathinfo: remove suffix when absent")
152 : {
153 1 : CATCH_REQUIRE(snapdev::pathinfo::replace_suffix<std::string>(
154 : "/full/path/example/pathinfo.c"
155 : , ".cpp") == "/full/path/example/pathinfo.c");
156 :
157 1 : CATCH_REQUIRE(snapdev::pathinfo::replace_suffix<std::string>(
158 : "/full/path/example/pathinfo.hpp"
159 : , ".h") == "/full/path/example/pathinfo.hpp");
160 :
161 1 : CATCH_REQUIRE(snapdev::pathinfo::replace_suffix<std::string>(
162 : "relative/path/pathinfo.c"
163 : , ".cpp") == "relative/path/pathinfo.c");
164 :
165 1 : CATCH_REQUIRE(snapdev::pathinfo::replace_suffix<std::string>(
166 : "relative/path/pathinfo.hpp"
167 : , ".h") == "relative/path/pathinfo.hpp");
168 :
169 1 : CATCH_REQUIRE(snapdev::pathinfo::replace_suffix<std::string>(
170 : "no-path.c"
171 : , ".cpp") == "no-path.c");
172 :
173 1 : CATCH_REQUIRE(snapdev::pathinfo::replace_suffix<std::string>(
174 : "no-path.hpp"
175 : , ".h") == "no-path.hpp");
176 : }
177 5 : CATCH_END_SECTION()
178 :
179 5 : CATCH_START_SECTION("pathinfo: do nothing if non-existant suffix")
180 : {
181 1 : CATCH_REQUIRE(snapdev::pathinfo::replace_suffix<std::string>(
182 : "/full/path/example/pathinfo.c"
183 : , ".cpp"
184 : , ".h"
185 : , true) == "/full/path/example/pathinfo.c");
186 :
187 1 : CATCH_REQUIRE(snapdev::pathinfo::replace_suffix<std::string>(
188 : "/full/path/example/pathinfo.c"
189 : , ".cpp"
190 : , ""
191 : , true) == "/full/path/example/pathinfo.c");
192 :
193 1 : CATCH_REQUIRE(snapdev::pathinfo::replace_suffix<std::string>(
194 : "/full/path/example/pathinfo.hpp"
195 : , ".h"
196 : , ".cpp"
197 : , true) == "/full/path/example/pathinfo.hpp");
198 :
199 1 : CATCH_REQUIRE(snapdev::pathinfo::replace_suffix<std::string>(
200 : "/full/path/example/pathinfo.hpp"
201 : , ".h"
202 : , std::string()
203 : , true) == "/full/path/example/pathinfo.hpp");
204 : }
205 5 : CATCH_END_SECTION()
206 5 : }
207 :
208 :
209 1 : CATCH_TEST_CASE("pathinfo_canonicalize", "[filename][pathinfo]")
210 : {
211 1 : CATCH_START_SECTION("pathinfo: canonicalize paths")
212 : {
213 1 : char const * to_canonicalize[] =
214 : {
215 : "", "", ".",
216 :
217 : "/", "/", "/",
218 :
219 : "/full/path", "", "/full/path",
220 : "///full//path/", "", "/full/path",
221 :
222 : "relative///path", "and.this", "relative/path/and.this",
223 : "relative///path/", "and.this", "relative/path/and.this",
224 : "relative///path", "/and.this", "relative/path/and.this",
225 :
226 : "relative///with///", "///more-path///", "relative/with/more-path",
227 : };
228 :
229 4 : for(std::size_t idx(0); idx < std::size(to_canonicalize) / 3; idx += 3)
230 : {
231 3 : CATCH_REQUIRE(snapdev::pathinfo::canonicalize(
232 : to_canonicalize[idx + 0]
233 : , to_canonicalize[idx + 1]) == to_canonicalize[idx + 2]);
234 : }
235 : }
236 1 : CATCH_END_SECTION()
237 1 : }
238 :
239 :
240 1 : CATCH_TEST_CASE("pathinfo_has_pattern", "[filename][pathinfo]")
241 : {
242 1 : CATCH_START_SECTION("pathinfo: has pattern function")
243 : {
244 : struct test_data
245 : {
246 : char const * f_path = nullptr;
247 : int f_true = 0;
248 : };
249 1 : constexpr test_data const patterns[] =
250 : {
251 : // no pattern
252 : { ".", 0x00 },
253 : { "without-pattern", 0x00 },
254 : { "regular/path/without/pattern", 0x00 },
255 : { "path/../without/../pattern", 0x00 },
256 :
257 : // *
258 : { "path/*/with/pattern", 0xFF },
259 : { "path/\\*/with/pattern", 0x55 },
260 :
261 : // ?
262 : { "path/?/with/pattern", 0xFF },
263 : { "path/\\?/with/pattern", 0x55 },
264 :
265 : // [...]
266 : { "path/[a-z]/with/pattern", 0xFF },
267 : { "path/[a-\\]/with/pattern", 0xFF },
268 : { "path/\\[a-z]/with/pattern", 0x55 },
269 : { "path/\\[a-z*]/with/pattern", 0xFF },
270 : { "path/\\[a-z?]/with/pattern", 0xFF },
271 :
272 : // {...}
273 : { "path/{abc,def}/with/pattern", 0xCC },
274 : { "path/\\{abc,dev}/with/pattern", 0x44 },
275 : { "path/\\{abc,*dev}/with/pattern", 0xFF },
276 : { "path/\\{abc?,dev}/with/pattern", 0xFF },
277 :
278 : // [*?+@!](...)
279 : { "path/*(abc,def)/with/pattern", 0xFF },
280 : { "path/?(abc,dev)/with/pattern", 0xFF },
281 : { "path/+(abc,dev)/with/pattern", 0xF0 },
282 : { "path/@(abc,dev)/with/pattern", 0xF0 },
283 : { "path/!(abc,dev)/with/pattern", 0xF0 },
284 : { "path/+(a*bc,dev)/with/pattern", 0xFF },
285 : { "path/@(ab*c,dev)/with/pattern", 0xFF },
286 : { "path/!(abc*,dev)/with/pattern", 0xFF },
287 : { "path/+(a?bc,dev)/with/pattern", 0xFF },
288 : { "path/@(ab?c,dev)/with/pattern", 0xFF },
289 : { "path/!(abc?,dev)/with/pattern", 0xFF },
290 : { "path/\\*(abc,def)/with/pattern", 0x55 },
291 : { "path/\\?(abc,dev)/with/pattern", 0x55 },
292 : { "path/\\+(abc,dev)/with/pattern", 0x50 },
293 : { "path/\\@(abc,dev)/with/pattern", 0x50 },
294 : { "path/\\!(abc,dev)/with/pattern", 0x50 },
295 : { "path/*\\(abc,def)/with/pattern", 0xFF },
296 : { "path/?\\(abc,dev)/with/pattern", 0xFF },
297 : { "path/+\\(abc,dev)/with/pattern", 0x00 },
298 : { "path/@\\(abc,dev)/with/pattern", 0x00 },
299 : { "path/!\\(abc,dev)/with/pattern", 0x00 },
300 : };
301 :
302 39 : for(std::size_t idx(0); idx < std::size(patterns); ++idx)
303 : {
304 342 : for(int mask(0); mask < 8; ++mask)
305 : {
306 304 : bool const result((patterns[idx].f_true & (1 << mask)) != 0);
307 : //std::cerr << "--- idx: " << idx << " path: \"" << patterns[idx].f_path << "\" mask: " << mask << " result: " << std::boolalpha << result << "\n";
308 304 : CATCH_REQUIRE(snapdev::pathinfo::has_pattern(
309 : patterns[idx].f_path
310 : , (mask & 1) != 0
311 : , (mask & 2) != 0
312 : , (mask & 4) != 0) == result);
313 : }
314 : }
315 : }
316 1 : CATCH_END_SECTION()
317 1 : }
318 :
319 :
320 1 : CATCH_TEST_CASE("pathinfo_is_child_path", "[filename][pathinfo]")
321 : {
322 1 : CATCH_START_SECTION("pathinfo: is child path function")
323 : {
324 : struct test_data
325 : {
326 : char const * f_parent = nullptr;
327 : char const * f_child = nullptr;
328 : bool f_equal = true;
329 : bool f_result = false;
330 : };
331 1 : constexpr test_data const parent_child[] =
332 : {
333 : // not a child / mismatch
334 : {
335 : ".",
336 : "..",
337 : true,
338 : false,
339 : },
340 : {
341 : ".",
342 : "..",
343 : false,
344 : false,
345 : },
346 : {
347 : "/var",
348 : "/usr/share/snapdev",
349 : true,
350 : false,
351 : },
352 : {
353 : "/var",
354 : "/usr/share/snapdev",
355 : false,
356 : false,
357 : },
358 : {
359 : "/var",
360 : "Desktop",
361 : true,
362 : false,
363 : },
364 : {
365 : "/var",
366 : "Desktop",
367 : false,
368 : false,
369 : },
370 : {
371 : "",
372 : "/usr/share/snapdev",
373 : true,
374 : false,
375 : },
376 : {
377 : "/usr/share",
378 : "",
379 : true,
380 : false,
381 : },
382 :
383 : // child, not equal
384 : {
385 : "/var",
386 : "/var/lib/snapdev",
387 : true,
388 : true,
389 : },
390 : {
391 : "/var",
392 : "/var//lib/snapdev",
393 : true,
394 : true,
395 : },
396 : {
397 : "//var",
398 : "/var/lib/snapdev/",
399 : true,
400 : true,
401 : },
402 : {
403 : "//var//",
404 : "/var/lib//snapdev/",
405 : true,
406 : true,
407 : },
408 : {
409 : "/var",
410 : "/var/lib/snapdev",
411 : false,
412 : true,
413 : },
414 : {
415 : "/var",
416 : "/var//lib/snapdev",
417 : false,
418 : true,
419 : },
420 : {
421 : "//var",
422 : "/var/lib/snapdev/",
423 : false,
424 : true,
425 : },
426 : {
427 : "//var//",
428 : "/var/lib//snapdev/",
429 : false,
430 : true,
431 : },
432 :
433 : // child, equal
434 : {
435 : "/var",
436 : "/var",
437 : true,
438 : true,
439 : },
440 : {
441 : "/var",
442 : "/var",
443 : false,
444 : false,
445 : },
446 : {
447 : "/var/",
448 : "/var",
449 : true,
450 : true,
451 : },
452 : {
453 : "/var/",
454 : "/var",
455 : false,
456 : false,
457 : },
458 : {
459 : "/var",
460 : "/var/",
461 : true,
462 : true,
463 : },
464 : {
465 : "/var",
466 : "/var/",
467 : false,
468 : false,
469 : },
470 : {
471 : "",
472 : "",
473 : true,
474 : true,
475 : },
476 : {
477 : "",
478 : "",
479 : false,
480 : false,
481 : },
482 : };
483 :
484 25 : for(std::size_t idx(0); idx < std::size(parent_child); ++idx)
485 : {
486 72 : bool const result(snapdev::pathinfo::is_child_path(
487 24 : parent_child[idx].f_parent
488 24 : , parent_child[idx].f_child
489 24 : , parent_child[idx].f_equal
490 48 : ));
491 :
492 : //std::cout << "--- idx: " << idx
493 : // << " path: \"" << parent_child[idx].f_parent
494 : // << "\" child: " << parent_child[idx].f_child
495 : // << " equal: " << std::boolalpha << parent_child[idx].f_equal
496 : // << " expected result: " << std::boolalpha << parent_child[idx].f_result
497 : // << " result: " << std::boolalpha << result
498 : // << "\n";
499 24 : CATCH_REQUIRE(result == parent_child[idx].f_result);
500 : }
501 : }
502 1 : CATCH_END_SECTION()
503 1 : }
504 :
505 :
506 :
507 : // vim: ts=4 sw=4 et
|