Blender V4.3
BLI_path_utils_test.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: Apache-2.0 */
4
5#include "testing/testing.h"
6
7#include "IMB_imbuf.hh"
8
9#include "BLI_fileops.h"
10#include "BLI_path_utils.hh"
11#include "BLI_string.h"
12#include "BLI_string_utils.hh"
13
14#define DO_PERF_TESTS 0
15
16/* -------------------------------------------------------------------- */
20static void str_replace_char_with_relative_exception(char *str, char src, char dst)
21{
22 /* Always keep "//" or more leading slashes (special meaning). */
23 if (src == '/') {
24 if (str[0] == '/' && str[1] == '/') {
25 str += 2;
26 while (*str == '/') {
27 str++;
28 }
29 }
30 }
32}
33
34static char *str_replace_char_strdup(const char *str, char src, char dst)
35{
36 if (str == nullptr) {
37 return nullptr;
38 }
39 char *str_dupe = strdup(str);
40 BLI_string_replace_char(str_dupe, src, dst);
41 return str_dupe;
42}
43
46/* -------------------------------------------------------------------- */
50#define NORMALIZE(input, output_expect) \
51 { \
52 char path[FILE_MAX] = input; \
53 if (SEP == '\\') { \
54 str_replace_char_with_relative_exception(path, '/', '\\'); \
55 } \
56 const int path_len_test = BLI_path_normalize(path); \
57 if (SEP == '\\') { \
58 BLI_string_replace_char(path, '\\', '/'); \
59 } \
60 EXPECT_STREQ(path, output_expect); \
61 EXPECT_EQ(path_len_test, strlen(path)); \
62 } \
63 ((void)0)
64
65/* #BLI_path_normalize: do nothing. */
66TEST(path_utils, Normalize_Nop)
67{
68 NORMALIZE(".", ".");
69 NORMALIZE("./", "./");
70 NORMALIZE("/", "/");
71 NORMALIZE("//", "//");
72 NORMALIZE("//a", "//a");
73}
74
75TEST(path_utils, Normalize_NopRelative)
76{
77 NORMALIZE("..", "..");
78 NORMALIZE("../", "../");
79 NORMALIZE("../", "../");
80 NORMALIZE("../..", "../..");
81 NORMALIZE("../../", "../../");
82}
83
84/* #BLI_path_normalize: "/./" -> "/" */
85TEST(path_utils, Normalize_Dot)
86{
87 NORMALIZE("/./", "/");
88 NORMALIZE("/a/./b/./c/./", "/a/b/c/");
89 NORMALIZE("/./././", "/");
90 NORMALIZE("/a/./././b/", "/a/b/");
91}
92/* #BLI_path_normalize: complex "/./" -> "/", "//" -> "/", "./path/../" -> "./". */
93TEST(path_utils, Normalize_ComplexAbsolute)
94{
95 NORMALIZE("/a/./b/./c/./.././.././", "/a/");
96 NORMALIZE("/a//.//b//.//c//.//..//.//..//.//", "/a/");
97}
98TEST(path_utils, Normalize_ComplexRelative)
99{
100 NORMALIZE("a/b/c/d/e/f/g/../a/../b/../../c/../../../d/../../../..", ".");
101 NORMALIZE("a/b/c/d/e/f/g/../a/../../../../b/../../../c/../../d/..", ".");
102}
103/* #BLI_path_normalize: "//" -> "/" */
104TEST(path_utils, Normalize_DoubleSlash)
105{
106 NORMALIZE("//", "//"); /* Exception, double forward slash. */
107 NORMALIZE(".//", "./");
108 NORMALIZE("a////", "a/");
109 NORMALIZE("./a////", "a/");
110}
111/* #BLI_path_normalize: "foo/bar/../" -> "foo/" */
112TEST(path_utils, Normalize_Parent)
113{
114 NORMALIZE("/a/b/c/../../../", "/");
115 NORMALIZE("/a/../a/b/../b/c/../c/", "/a/b/c/");
116}
117/* #BLI_path_normalize: with too many "/../", match Python's behavior. */
118TEST(path_utils, Normalize_UnbalancedAbsolute)
119{
120 NORMALIZE("/../", "/");
121 NORMALIZE("/../a", "/a");
122 NORMALIZE("/a/b/c/../../../../../d", "/d");
123 NORMALIZE("/a/b/c/../../../../d", "/d");
124 NORMALIZE("/a/b/c/../../../d", "/d");
125
126 /* Use a longer path as it may hit corner cases. */
127 NORMALIZE("/home/username/Downloads/../../../../../Users/Example/Desktop/test.jpg",
128 "/Users/Example/Desktop/test.jpg");
129}
130
131/* #BLI_path_normalize: with relative paths that result in leading "../". */
132TEST(path_utils, Normalize_UnbalancedRelative)
133{
134 NORMALIZE("./a/b/c/../../../", ".");
135 NORMALIZE("a/b/c/../../../", ".");
136 NORMALIZE("//a/b/c/../../../", "//");
137
138 NORMALIZE("./a/../../../", "../../");
139 NORMALIZE("a/../../../", "../../");
140
141 NORMALIZE("///a/../../../", "//../../");
142 NORMALIZE("//./a/../../../", "//../../");
143
144 NORMALIZE("../a/../../../", "../../../");
145 NORMALIZE("a/b/../c/../../d/../../../e/../../../../f", "../../../../../f");
146 NORMALIZE(".../.../a/.../b/../c/../../d/../../../e/../../../.../../f", "../f");
147}
148
149TEST(path_utils, Normalize_UnbalancedRelativeTrailing)
150{
151 NORMALIZE("./a/b/c/../../..", ".");
152 NORMALIZE("a/b/c/../../..", ".");
153 NORMALIZE("//a/b/c/../../..", "//");
154
155 NORMALIZE("./a/../../..", "../..");
156 NORMALIZE("a/../../..", "../..");
157
158 NORMALIZE("///a/../../..", "//../..");
159 NORMALIZE("//./a/../../..", "//../..");
160
161 NORMALIZE("../a/../../..", "../../..");
162}
163
164#undef NORMALIZE
165
168/* -------------------------------------------------------------------- */
174TEST(path_utils, CompareNormalized)
175{
176 /* Trailing slash should not matter. */
177 EXPECT_EQ(BLI_path_cmp_normalized("/tmp/", "/tmp"), 0);
178 /* Slash direction should not matter. */
179 EXPECT_EQ(BLI_path_cmp_normalized("c:\\tmp\\", "c:/tmp/"), 0);
180 /* Empty paths should be supported. */
182
183 EXPECT_NE(BLI_path_cmp_normalized("A", "B"), 0);
184}
185
188/* -------------------------------------------------------------------- */
192#define PARENT_DIR(input, output_expect) \
193 { \
194 char path[FILE_MAX] = input; \
195 if (SEP == '\\') { \
196 BLI_string_replace_char(path, '/', '\\'); \
197 } \
198 BLI_path_parent_dir(path); \
199 if (SEP == '\\') { \
200 BLI_string_replace_char(path, '\\', '/'); \
201 } \
202 EXPECT_STREQ(path, output_expect); \
203 } \
204 ((void)0)
205
206TEST(path_utils, ParentDir_Simple)
207{
208 PARENT_DIR("/a/b/", "/a/");
209 PARENT_DIR("/a/b", "/a/");
210 PARENT_DIR("/a", "/");
211}
212
213TEST(path_utils, ParentDir_NOP)
214{
215 PARENT_DIR("/", "/");
216 PARENT_DIR("", "");
217 PARENT_DIR(".", ".");
218 PARENT_DIR("./", "./");
219 PARENT_DIR(".//", ".//");
220 PARENT_DIR("./.", "./.");
221}
222
223TEST(path_utils, ParentDir_TrailingPeriod)
224{
225 /* Ensure trailing dots aren't confused with parent path. */
226 PARENT_DIR("/.../.../.../", "/.../.../");
227 PARENT_DIR("/.../.../...", "/.../.../");
228
229 PARENT_DIR("/a../b../c../", "/a../b../");
230 PARENT_DIR("/a../b../c..", "/a../b../");
231
232 PARENT_DIR("/a./b./c./", "/a./b./");
233 PARENT_DIR("/a./b./c.", "/a./b./");
234}
235
236TEST(path_utils, ParentDir_Complex)
237{
238 PARENT_DIR("./a/", "./");
239 PARENT_DIR("./a", "./");
240 PARENT_DIR("../a/", "../");
241 PARENT_DIR("../a", "../");
242}
243
244#undef PARENT_DIR
245
248/* -------------------------------------------------------------------- */
252#define AT_INDEX(str_input, index_input, str_expect) \
253 { \
254 char path[] = str_input; \
255 /* Test input assumes forward slash, support back-slash on WIN32. */ \
256 if (SEP == '\\') { \
257 BLI_string_replace_char(path, '/', '\\'); \
258 } \
259 const char *expect = str_expect; \
260 int index_output, len_output; \
261 const bool ret = BLI_path_name_at_index(path, index_input, &index_output, &len_output); \
262 if (expect == nullptr) { \
263 EXPECT_FALSE(ret); \
264 } \
265 else { \
266 EXPECT_TRUE(ret); \
267 EXPECT_EQ(len_output, strlen(expect)); \
268 path[index_output + len_output] = '\0'; \
269 EXPECT_STREQ(&path[index_output], expect); \
270 } \
271 } \
272 ((void)0)
273
274TEST(path_utils, NameAtIndex_Single)
275{
276 AT_INDEX("/a", 0, "a");
277 AT_INDEX("/a/", 0, "a");
278 AT_INDEX("a/", 0, "a");
279 AT_INDEX("//a//", 0, "a");
280 AT_INDEX("a/b", 0, "a");
281
282 AT_INDEX("/a", 1, nullptr);
283 AT_INDEX("/a/", 1, nullptr);
284 AT_INDEX("a/", 1, nullptr);
285 AT_INDEX("//a//", 1, nullptr);
286}
287TEST(path_utils, NameAtIndex_SingleNeg)
288{
289 AT_INDEX("/a", -1, "a");
290 AT_INDEX("/a/", -1, "a");
291 AT_INDEX("a/", -1, "a");
292 AT_INDEX("//a//", -1, "a");
293 AT_INDEX("a/b", -1, "b");
294
295 AT_INDEX("/a", -2, nullptr);
296 AT_INDEX("/a/", -2, nullptr);
297 AT_INDEX("a/", -2, nullptr);
298 AT_INDEX("//a//", -2, nullptr);
299}
300
301TEST(path_utils, NameAtIndex_Double)
302{
303 AT_INDEX("/ab", 0, "ab");
304 AT_INDEX("/ab/", 0, "ab");
305 AT_INDEX("ab/", 0, "ab");
306 AT_INDEX("//ab//", 0, "ab");
307 AT_INDEX("ab/c", 0, "ab");
308
309 AT_INDEX("/ab", 1, nullptr);
310 AT_INDEX("/ab/", 1, nullptr);
311 AT_INDEX("ab/", 1, nullptr);
312 AT_INDEX("//ab//", 1, nullptr);
313}
314
315TEST(path_utils, NameAtIndex_DoublNeg)
316{
317 AT_INDEX("/ab", -1, "ab");
318 AT_INDEX("/ab/", -1, "ab");
319 AT_INDEX("ab/", -1, "ab");
320 AT_INDEX("//ab//", -1, "ab");
321 AT_INDEX("ab/c", -1, "c");
322
323 AT_INDEX("/ab", -2, nullptr);
324 AT_INDEX("/ab/", -2, nullptr);
325 AT_INDEX("ab/", -2, nullptr);
326 AT_INDEX("//ab//", -2, nullptr);
327}
328
329TEST(path_utils, NameAtIndex_Misc)
330{
331 AT_INDEX("/how/now/brown/cow", 0, "how");
332 AT_INDEX("/how/now/brown/cow", 1, "now");
333 AT_INDEX("/how/now/brown/cow", 2, "brown");
334 AT_INDEX("/how/now/brown/cow", 3, "cow");
335 AT_INDEX("/how/now/brown/cow", 4, nullptr);
336 AT_INDEX("/how/now/brown/cow/", 4, nullptr);
337}
338
339TEST(path_utils, NameAtIndex_MiscNeg)
340{
341 AT_INDEX("/how/now/brown/cow", 0, "how");
342 AT_INDEX("/how/now/brown/cow", 1, "now");
343 AT_INDEX("/how/now/brown/cow", 2, "brown");
344 AT_INDEX("/how/now/brown/cow", 3, "cow");
345 AT_INDEX("/how/now/brown/cow", 4, nullptr);
346 AT_INDEX("/how/now/brown/cow/", 4, nullptr);
347}
348
349#define TEST_STR "./a/./b/./c/."
350
351TEST(path_utils, NameAtIndex_SingleDot)
352{
353 AT_INDEX(TEST_STR, 0, ".");
354 AT_INDEX(TEST_STR, 1, "a");
355 AT_INDEX(TEST_STR, 2, "b");
356 AT_INDEX(TEST_STR, 3, "c");
357 AT_INDEX(TEST_STR, 4, nullptr);
358}
359
360TEST(path_utils, NameAtIndex_SingleDotNeg)
361{
362 AT_INDEX(TEST_STR, -5, nullptr);
363 AT_INDEX(TEST_STR, -4, ".");
364 AT_INDEX(TEST_STR, -3, "a");
365 AT_INDEX(TEST_STR, -2, "b");
366 AT_INDEX(TEST_STR, -1, "c");
367}
368
369#undef TEST_STR
370
371#define TEST_STR ".//a//.//b//.//c//.//"
372
373TEST(path_utils, NameAtIndex_SingleDotDoubleSlash)
374{
375 AT_INDEX(TEST_STR, 0, ".");
376 AT_INDEX(TEST_STR, 1, "a");
377 AT_INDEX(TEST_STR, 2, "b");
378 AT_INDEX(TEST_STR, 3, "c");
379 AT_INDEX(TEST_STR, 4, nullptr);
380}
381
382TEST(path_utils, NameAtIndex_SingleDotDoubleSlashNeg)
383{
384 AT_INDEX(TEST_STR, -5, nullptr);
385 AT_INDEX(TEST_STR, -4, ".");
386 AT_INDEX(TEST_STR, -3, "a");
387 AT_INDEX(TEST_STR, -2, "b");
388 AT_INDEX(TEST_STR, -1, "c");
389}
390
391#undef TEST_STR
392
393TEST(path_utils, NameAtIndex_SingleDotSeries)
394{
395 AT_INDEX("abc/././/././xyz", 0, "abc");
396 AT_INDEX("abc/././/././xyz", 1, "xyz");
397 AT_INDEX("abc/././/././xyz", 2, nullptr);
398}
399
400TEST(path_utils, NameAtIndex_SingleDotSeriesNeg)
401{
402 AT_INDEX("abc/././/././xyz", -3, nullptr);
403 AT_INDEX("abc/././/././xyz", -2, "abc");
404 AT_INDEX("abc/././/././xyz", -1, "xyz");
405}
406
407TEST(path_utils, NameAtIndex_MiscComplex)
408{
409 AT_INDEX("how//now/brown/cow", 0, "how");
410 AT_INDEX("//how///now//brown/cow", 1, "now");
411 AT_INDEX("/how/now///brown//cow", 2, "brown");
412 AT_INDEX("/how/now/brown/cow///", 3, "cow");
413 AT_INDEX("/how/now/brown//cow", 4, nullptr);
414 AT_INDEX("how/now/brown//cow/", 4, nullptr);
415}
416
417TEST(path_utils, NameAtIndex_MiscComplexNeg)
418{
419 AT_INDEX("how//now/brown/cow", -4, "how");
420 AT_INDEX("//how///now//brown/cow", -3, "now");
421 AT_INDEX("/how/now///brown//cow", -2, "brown");
422 AT_INDEX("/how/now/brown/cow///", -1, "cow");
423 AT_INDEX("/how/now/brown//cow", -5, nullptr);
424 AT_INDEX("how/now/brown//cow/", -5, nullptr);
425}
426
427TEST(path_utils, NameAtIndex_NoneComplex)
428{
429 AT_INDEX("", 0, nullptr);
430 AT_INDEX("/", 0, nullptr);
431 AT_INDEX("//", 0, nullptr);
432 AT_INDEX("///", 0, nullptr);
433}
434
435TEST(path_utils, NameAtIndex_NoneComplexNeg)
436{
437 AT_INDEX("", -1, nullptr);
438 AT_INDEX("/", -1, nullptr);
439 AT_INDEX("//", -1, nullptr);
440 AT_INDEX("///", -1, nullptr);
441}
442
443#undef AT_INDEX
444
447/* -------------------------------------------------------------------- */
451TEST(path_utils, IsUnc)
452{
453 EXPECT_TRUE(BLI_path_is_unc("\\\\server_name\\share_name"));
454 EXPECT_TRUE(BLI_path_is_unc("\\\\.\\C:\\file.txt"));
455 EXPECT_TRUE(BLI_path_is_unc("\\\\?\\C:\\file.txt"));
456
457 EXPECT_FALSE(BLI_path_is_unc(""));
458 EXPECT_FALSE(BLI_path_is_unc("."));
459 EXPECT_FALSE(BLI_path_is_unc("..\\relative\\path"));
460 EXPECT_FALSE(BLI_path_is_unc(".\\relative\\path"));
461 EXPECT_FALSE(BLI_path_is_unc("\\a_single_backslash"));
462 EXPECT_FALSE(BLI_path_is_unc("//must_be_backslashes"));
463}
464
467/* -------------------------------------------------------------------- */
471TEST(path_utils, IsWin32Drive)
472{
473 EXPECT_TRUE(BLI_path_is_win32_drive("E:\\file.txt"));
474 EXPECT_TRUE(BLI_path_is_win32_drive("E:/file.txt"));
475 EXPECT_TRUE(BLI_path_is_win32_drive("E:/"));
476 EXPECT_TRUE(BLI_path_is_win32_drive("E:\\"));
477 EXPECT_TRUE(BLI_path_is_win32_drive("E:"));
478 EXPECT_TRUE(BLI_path_is_win32_drive("e:"));
479
480 EXPECT_FALSE(BLI_path_is_win32_drive(""));
481 EXPECT_FALSE(BLI_path_is_win32_drive("."));
482 EXPECT_FALSE(BLI_path_is_win32_drive("Ef"));
483 EXPECT_FALSE(BLI_path_is_win32_drive("1:"));
484 EXPECT_FALSE(BLI_path_is_win32_drive("../file"));
485 EXPECT_FALSE(BLI_path_is_win32_drive("\\\\server_name\\share_name"));
486 EXPECT_FALSE(BLI_path_is_win32_drive("\\\\?\\C:\\file.txt"));
487 EXPECT_FALSE(BLI_path_is_win32_drive("//relative.txt"));
488}
489
492/* -------------------------------------------------------------------- */
496TEST(path_utils, IsWin32DriveOnly)
497{
498 EXPECT_FALSE(BLI_path_is_win32_drive_only("E:\\file.txt"));
499 EXPECT_FALSE(BLI_path_is_win32_drive_only("E:/file.txt"));
500 EXPECT_FALSE(BLI_path_is_win32_drive_only("E:/"));
501 EXPECT_FALSE(BLI_path_is_win32_drive_only("E:\\"));
502
503 EXPECT_TRUE(BLI_path_is_win32_drive_only("E:"));
504 EXPECT_TRUE(BLI_path_is_win32_drive_only("e:"));
505
506 EXPECT_FALSE(BLI_path_is_win32_drive_only(""));
507 EXPECT_FALSE(BLI_path_is_win32_drive_only("."));
508 EXPECT_FALSE(BLI_path_is_win32_drive_only("Ef"));
509 EXPECT_FALSE(BLI_path_is_win32_drive_only("1:"));
510 EXPECT_FALSE(BLI_path_is_win32_drive_only("../file"));
511 EXPECT_FALSE(BLI_path_is_win32_drive_only("\\\\server_name\\share_name"));
512 EXPECT_FALSE(BLI_path_is_win32_drive_only("\\\\?\\C:\\file.txt"));
513 EXPECT_FALSE(BLI_path_is_win32_drive_only("//relative.txt"));
514}
515
518/* -------------------------------------------------------------------- */
522TEST(path_utils, IsWin32DriveWithSlash)
523{
524 EXPECT_TRUE(BLI_path_is_win32_drive_with_slash("E:\\file.txt"));
525 EXPECT_TRUE(BLI_path_is_win32_drive_with_slash("E:/file.txt"));
526
527 EXPECT_TRUE(BLI_path_is_win32_drive_with_slash("E:/"));
528 EXPECT_TRUE(BLI_path_is_win32_drive_with_slash("E:\\"));
529
530 EXPECT_FALSE(BLI_path_is_win32_drive_with_slash("E:"));
531 EXPECT_FALSE(BLI_path_is_win32_drive_with_slash("e:"));
532 EXPECT_FALSE(BLI_path_is_win32_drive_with_slash("Ef"));
533 EXPECT_FALSE(BLI_path_is_win32_drive_with_slash("1:"));
534 EXPECT_FALSE(BLI_path_is_win32_drive_with_slash("../file"));
535 EXPECT_FALSE(BLI_path_is_win32_drive_with_slash("\\\\server_name\\share_name"));
536 EXPECT_FALSE(BLI_path_is_win32_drive_with_slash("\\\\?\\C:\\file.txt"));
537 EXPECT_FALSE(BLI_path_is_win32_drive_with_slash("//relative.txt"));
538}
539
542/* -------------------------------------------------------------------- */
546/* For systems with `/` path separator (non WIN32). */
547#define JOIN_FORWARD_SLASH(str_expect, out_size, ...) \
548 { \
549 const char *expect = str_expect; \
550 char result[(out_size) + 1024]; \
551 /* Check we don't write past the last byte. */ \
552 result[out_size] = '\0'; \
553 BLI_path_join(result, out_size, __VA_ARGS__); \
554 EXPECT_STREQ(result, expect); \
555 EXPECT_EQ(result[out_size], '\0'); \
556 } \
557 ((void)0)
558
559/* For systems with `\` path separator (WIN32).
560 * Perform additional manipulation to behave as if input arguments used `\` separators.
561 * Needed since #BLI_path_join uses native slashes. */
562#define JOIN_BACK_SLASH(str_expect, out_size, ...) \
563 { \
564 const char *expect = str_expect; \
565 char result[(out_size) + 1024]; \
566 const char *input_forward_slash[] = {__VA_ARGS__}; \
567 char *input_back_slash[ARRAY_SIZE(input_forward_slash)] = {nullptr}; \
568 for (int i = 0; i < ARRAY_SIZE(input_forward_slash); i++) { \
569 input_back_slash[i] = strdup(input_forward_slash[i]); \
570 BLI_string_replace_char(input_back_slash[i], '/', '\\'); \
571 } \
572 /* Check we don't write past the last byte. */ \
573 result[out_size] = '\0'; \
574 BLI_path_join_array(result, \
575 out_size, \
576 const_cast<const char **>(input_back_slash), \
577 ARRAY_SIZE(input_back_slash)); \
578 BLI_string_replace_char(result, '\\', '/'); \
579 EXPECT_STREQ(result, expect); \
580 EXPECT_EQ(result[out_size], '\0'); \
581 for (int i = 0; i < ARRAY_SIZE(input_forward_slash); i++) { \
582 free(input_back_slash[i]); \
583 } \
584 } \
585 ((void)0)
586
587#ifdef WIN32
588# define JOIN JOIN_BACK_SLASH
589#else
590# define JOIN JOIN_FORWARD_SLASH
591#endif
592
593TEST(path_utils, JoinNop)
594{
595 JOIN("", 100, "");
596 JOIN("", 100, "", "");
597 JOIN("", 100, "", "", "");
598 JOIN("/", 100, "/", "", "");
599 JOIN("/", 100, "/", "/");
600 JOIN("/", 100, "/", "", "/");
601 JOIN("/", 100, "/", "", "/", "");
602}
603
604TEST(path_utils, JoinSingle)
605{
606 JOIN("test", 100, "test");
607 JOIN("", 100, "");
608 JOIN("a", 100, "a");
609 JOIN("/a", 100, "/a");
610 JOIN("a/", 100, "a/");
611 JOIN("/a/", 100, "/a/");
612 JOIN("/a/", 100, "/a//");
613 JOIN("//a/", 100, "//a//");
614}
615
616TEST(path_utils, JoinTriple)
617{
618 JOIN("/a/b/c", 100, "/a", "b", "c");
619 JOIN("/a/b/c", 100, "/a/", "/b/", "/c");
620 JOIN("/a/b/c", 100, "/a/b/", "/c");
621 JOIN("/a/b/c", 100, "/a/b/c");
622 JOIN("/a/b/c", 100, "/", "a/b/c");
623
624 JOIN("/a/b/c/", 100, "/a/", "/b/", "/c/");
625 JOIN("/a/b/c/", 100, "/a/b/c/");
626 JOIN("/a/b/c/", 100, "/a/b/", "/c/");
627 JOIN("/a/b/c/", 100, "/a/b/c", "/");
628 JOIN("/a/b/c/", 100, "/", "a/b/c", "/");
629}
630
631TEST(path_utils, JoinTruncateShort)
632{
633 JOIN("", 1, "/");
634 JOIN("/", 2, "/");
635 JOIN("a", 2, "", "aa");
636 JOIN("a", 2, "", "a/");
637 JOIN("a/b", 4, "a", "bc");
638 JOIN("ab/", 4, "ab", "c");
639 JOIN("/a/", 4, "/a", "b");
640 JOIN("/a/", 4, "/a/", "b/");
641 JOIN("/a/", 4, "/a", "/b/");
642 JOIN("/a/", 4, "/", "a/b/");
643 JOIN("//a", 4, "//", "a/b/");
644
645 JOIN("/a/b", 5, "/a", "b", "c");
646}
647
648TEST(path_utils, JoinTruncateLong)
649{
650 JOIN("", 1, "//", "//longer", "path");
651 JOIN("/", 2, "//", "//longer", "path");
652 JOIN("//", 3, "//", "//longer", "path");
653 JOIN("//l", 4, "//", "//longer", "path");
654 /* snip */
655 JOIN("//longe", 8, "//", "//longer", "path");
656 JOIN("//longer", 9, "//", "//longer", "path");
657 JOIN("//longer/", 10, "//", "//longer", "path");
658 JOIN("//longer/p", 11, "//", "//longer", "path");
659 JOIN("//longer/pa", 12, "//", "//longer", "path");
660 JOIN("//longer/pat", 13, "//", "//longer", "path");
661 JOIN("//longer/path", 14, "//", "//longer", "path"); /* not truncated. */
662 JOIN("//longer/path", 14, "//", "//longer", "path/");
663 JOIN("//longer/path/", 15, "//", "//longer", "path/"); /* not truncated. */
664 JOIN("//longer/path/", 15, "//", "//longer", "path/", "trunc");
665 JOIN("//longer/path/t", 16, "//", "//longer", "path/", "trunc");
666}
667
668TEST(path_utils, JoinComplex)
669{
670 JOIN("/a/b/c/d/e/f/g/", 100, "/", "a/b", "//////c/d", "", "e", "f", "g//");
671 JOIN("/aa/bb/cc/dd/ee/ff/gg/", 100, "/", "aa/bb", "//////cc/dd", "", "ee", "ff", "gg//");
672 JOIN("1/2/3/", 100, "1", "////////", "", "2", "3///");
673}
674
675TEST(path_utils, JoinRelativePrefix)
676{
677 JOIN("//a/b/c", 100, "//a", "b", "c");
678 JOIN("//a/b/c", 100, "//", "//a//", "//b//", "//c");
679 JOIN("//a/b/c", 100, "//", "//", "a", "//", "b", "//", "c");
680}
681
682#undef JOIN
683#undef JOIN_BACK_SLASH
684#undef JOIN_FORWARD_SLASH
685
688/* -------------------------------------------------------------------- */
692/* For systems with `/` path separator (non WIN32). */
693#define APPEND(str_expect, size, path, filename) \
694 { \
695 const char *expect = str_expect; \
696 char result[(size) + 1024] = path; \
697 char filename_native[] = filename; \
698 /* Check we don't write past the last byte. */ \
699 if (SEP == '\\') { \
700 BLI_string_replace_char(filename_native, '/', '\\'); \
701 BLI_string_replace_char(result, '/', '\\'); \
702 } \
703 BLI_path_append(result, size, filename_native); \
704 if (SEP == '\\') { \
705 BLI_string_replace_char(result, '\\', '/'); \
706 } \
707 EXPECT_STREQ(result, expect); \
708 } \
709 ((void)0)
710
711TEST(path_utils, AppendFile)
712{
713 APPEND("a/b", 100, "a", "b");
714 APPEND("a/b", 100, "a/", "b");
715}
716
717TEST(path_utils, AppendFile_Truncate)
718{
719 APPEND("/A", 3, "/", "ABC");
720 APPEND("/", 2, "/", "test");
721 APPEND("X", 2, "X", "ABC");
722 APPEND("X/", 3, "X/", "ABC");
723}
724
725#undef APPEND
726
729/* -------------------------------------------------------------------- */
733TEST(path_utils, Frame)
734{
735 bool ret;
736
737 {
738 char path[FILE_MAX] = "";
739 ret = BLI_path_frame(path, sizeof(path), 123, 1);
740 EXPECT_TRUE(ret);
741 EXPECT_STREQ(path, "123");
742 }
743
744 {
745 char path[FILE_MAX] = "";
746 ret = BLI_path_frame(path, sizeof(path), 123, 12);
747 EXPECT_TRUE(ret);
748 EXPECT_STREQ(path, "000000000123");
749 }
750
751 {
752 char path[FILE_MAX] = "test_";
753 ret = BLI_path_frame(path, sizeof(path), 123, 1);
754 EXPECT_TRUE(ret);
755 EXPECT_STREQ(path, "test_123");
756 }
757
758 {
759 char path[FILE_MAX] = "test_";
760 ret = BLI_path_frame(path, sizeof(path), 1, 12);
761 EXPECT_TRUE(ret);
762 EXPECT_STREQ(path, "test_000000000001");
763 }
764
765 {
766 char path[FILE_MAX] = "test_############";
767 ret = BLI_path_frame(path, sizeof(path), 1, 0);
768 EXPECT_TRUE(ret);
769 EXPECT_STREQ(path, "test_000000000001");
770 }
771
772 {
773 char path[FILE_MAX] = "test_#_#_middle";
774 ret = BLI_path_frame(path, sizeof(path), 123, 0);
775 EXPECT_TRUE(ret);
776 EXPECT_STREQ(path, "test_#_123_middle");
777 }
778
779 /* intentionally fail */
780 {
781 char path[FILE_MAX] = "";
782 ret = BLI_path_frame(path, sizeof(path), 123, 0);
783 EXPECT_FALSE(ret);
784 EXPECT_STREQ(path, "");
785 }
786
787 {
788 char path[FILE_MAX] = "test_middle";
789 ret = BLI_path_frame(path, sizeof(path), 123, 0);
790 EXPECT_FALSE(ret);
791 EXPECT_STREQ(path, "test_middle");
792 }
793
794 /* negative frame numbers */
795 {
796 char path[FILE_MAX] = "test_####";
797 ret = BLI_path_frame(path, sizeof(path), -1, 4);
798 EXPECT_TRUE(ret);
799 EXPECT_STREQ(path, "test_-0001");
800 }
801 {
802 char path[FILE_MAX] = "test_####";
803 ret = BLI_path_frame(path, sizeof(path), -100, 4);
804 EXPECT_TRUE(ret);
805 EXPECT_STREQ(path, "test_-0100");
806 }
807
808 /* Ensure very large ranges work. */
809 {
810 char path[FILE_MAX * 2];
811 memset(path, '#', sizeof(path));
812 path[sizeof(path) - 1] = '\0';
813 ret = BLI_path_frame(path, sizeof(path), 123456789, 0);
814 EXPECT_TRUE(BLI_str_endswith(path, "0123456789"));
815 }
816}
817
820/* -------------------------------------------------------------------- */
824TEST(path_utils, SplitDirfile)
825{
826 {
827 const char *path = "";
828 char dir[FILE_MAX], file[FILE_MAX];
829 BLI_path_split_dir_file(path, dir, sizeof(dir), file, sizeof(file));
830 EXPECT_STREQ(dir, "");
831 EXPECT_STREQ(file, "");
832 }
833
834 {
835 const char *path = "/";
836 char dir[FILE_MAX], file[FILE_MAX];
837 BLI_path_split_dir_file(path, dir, sizeof(dir), file, sizeof(file));
838 EXPECT_STREQ(dir, "/");
839 EXPECT_STREQ(file, "");
840 }
841
842 {
843 const char *path = "fileonly";
844 char dir[FILE_MAX], file[FILE_MAX];
845 BLI_path_split_dir_file(path, dir, sizeof(dir), file, sizeof(file));
846 EXPECT_STREQ(dir, "");
847 EXPECT_STREQ(file, "fileonly");
848 }
849
850 {
851 const char *path = "dironly/";
852 char dir[FILE_MAX], file[FILE_MAX];
853 BLI_path_split_dir_file(path, dir, sizeof(dir), file, sizeof(file));
854 EXPECT_STREQ(dir, "dironly/");
855 EXPECT_STREQ(file, "");
856 }
857
858 {
859 const char *path = "/a/b";
860 char dir[FILE_MAX], file[FILE_MAX];
861 BLI_path_split_dir_file(path, dir, sizeof(dir), file, sizeof(file));
862 EXPECT_STREQ(dir, "/a/");
863 EXPECT_STREQ(file, "b");
864 }
865
866 {
867 const char *path = "/dirtoobig/filetoobig";
868 char dir[5], file[5];
869 BLI_path_split_dir_file(path, dir, sizeof(dir), file, sizeof(file));
870 EXPECT_STREQ(dir, "/dir");
871 EXPECT_STREQ(file, "file");
872
873 BLI_path_split_dir_file(path, dir, 1, file, 1);
874 EXPECT_STREQ(dir, "");
875 EXPECT_STREQ(file, "");
876 }
877}
878
881/* -------------------------------------------------------------------- */
885#define PATH_FRAME_STRIP(input_path, expect_path, expect_ext) \
886 { \
887 char path[FILE_MAX]; \
888 char ext[FILE_MAX]; \
889 STRNCPY(path, (input_path)); \
890 BLI_path_frame_strip(path, ext, sizeof(ext)); \
891 EXPECT_STREQ(path, expect_path); \
892 EXPECT_STREQ(ext, expect_ext); \
893 } \
894 ((void)0)
895
896TEST(path_utils, FrameStrip)
897{
898 PATH_FRAME_STRIP("", "", "");
899 PATH_FRAME_STRIP("nonum.abc", "nonum", ".abc");
900 PATH_FRAME_STRIP("fileonly.001.abc", "fileonly.###", ".abc");
901 PATH_FRAME_STRIP("/abspath/to/somefile.001.abc", "/abspath/to/somefile.###", ".abc");
902 PATH_FRAME_STRIP("/ext/longer/somefile.001.alembic", "/ext/longer/somefile.###", ".alembic");
903 PATH_FRAME_STRIP("/ext/shorter/somefile.123001.abc", "/ext/shorter/somefile.######", ".abc");
904}
905#undef PATH_FRAME_STRIP
906
909/* -------------------------------------------------------------------- */
913TEST(path_utils, Extension)
914{
915 EXPECT_EQ(BLI_path_extension("some.def/file"), nullptr);
916 EXPECT_EQ(BLI_path_extension("Text"), nullptr);
917 EXPECT_EQ(BLI_path_extension("Text…001"), nullptr);
918 EXPECT_EQ(BLI_path_extension(".hidden"), nullptr);
919 EXPECT_EQ(BLI_path_extension(".hidden/"), nullptr);
920 EXPECT_EQ(BLI_path_extension("/.hidden"), nullptr);
921 EXPECT_EQ(BLI_path_extension("dir/.hidden"), nullptr);
922 EXPECT_EQ(BLI_path_extension("/dir/.hidden"), nullptr);
923
924 EXPECT_EQ(BLI_path_extension("."), nullptr);
925 EXPECT_EQ(BLI_path_extension(".."), nullptr);
926 EXPECT_EQ(BLI_path_extension("..."), nullptr);
927 EXPECT_STREQ(BLI_path_extension("...a."), ".");
928 EXPECT_STREQ(BLI_path_extension("...a.."), ".");
929 EXPECT_EQ(BLI_path_extension("...a../"), nullptr);
930
931 EXPECT_STREQ(BLI_path_extension("some/file."), ".");
932 EXPECT_STREQ(BLI_path_extension("some/file.tar.gz"), ".gz");
933 EXPECT_STREQ(BLI_path_extension("some.def/file.abc"), ".abc");
934 EXPECT_STREQ(BLI_path_extension("C:\\some.def\\file.abc"), ".abc");
935 EXPECT_STREQ(BLI_path_extension("Text.001"), ".001");
936}
937
940/* -------------------------------------------------------------------- */
944#define PATH_EXTENSION_CHECK(input_path, input_ext, expect_ext) \
945 { \
946 const bool ret = BLI_path_extension_check(input_path, input_ext); \
947 if (STREQ(input_ext, expect_ext)) { \
948 EXPECT_TRUE(ret); \
949 } \
950 else { \
951 EXPECT_FALSE(ret); \
952 } \
953 } \
954 ((void)0)
955
956TEST(path_utils, ExtensionCheck)
957{
958 PATH_EXTENSION_CHECK("a/b/c.exe", ".exe", ".exe");
959 PATH_EXTENSION_CHECK("correct/path/to/file.h", ".h", ".h");
960 PATH_EXTENSION_CHECK("correct/path/to/file.BLEND", ".BLEND", ".BLEND");
961 PATH_EXTENSION_CHECK("../tricky/path/to/file.h", ".h", ".h");
962 PATH_EXTENSION_CHECK("../dirty//../path\\to/file.h", ".h", ".h");
963 PATH_EXTENSION_CHECK("a/b/c.veryveryverylonglonglongextension",
964 ".veryveryverylonglonglongextension",
965 ".veryveryverylonglonglongextension");
966 PATH_EXTENSION_CHECK("filename.PNG", "pnG", "pnG");
967 PATH_EXTENSION_CHECK("a/b/c.h.exe", ".exe", ".exe");
968 PATH_EXTENSION_CHECK("a/b/c.h.exe", "exe", "exe");
969 PATH_EXTENSION_CHECK("a/b/c.exe", "c.exe", "c.exe");
970 PATH_EXTENSION_CHECK("a/b/noext", "noext", "noext");
971
972 PATH_EXTENSION_CHECK("a/b/c.exe", ".png", ".exe");
973 PATH_EXTENSION_CHECK("a/b/c.exe", "c.png", ".exe");
974 PATH_EXTENSION_CHECK("a/b/s.l", "l.s", "s.l");
975 PATH_EXTENSION_CHECK(".hiddenfolder", "", ".hiddenfolder");
976 PATH_EXTENSION_CHECK("../dirty//../path\\to/actual.h.file.ext", ".h", ".ext");
977 PATH_EXTENSION_CHECK("..\\dirty//../path//to/.hiddenfile.JPEG", ".hiddenfile", ".JPEG");
978}
979#undef PATH_EXTENSION_CHECK
980
983/* -------------------------------------------------------------------- */
987#define PATH_EXTENSION_REPLACE_WITH_MAXLEN( \
988 input_path, input_ext, expect_result, expect_path, maxlen) \
989 { \
990 BLI_assert(maxlen <= FILE_MAX); \
991 char path[FILE_MAX]; \
992 STRNCPY(path, input_path); \
993 const bool ret = BLI_path_extension_replace(path, maxlen, input_ext); \
994 if (expect_result) { \
995 EXPECT_TRUE(ret); \
996 } \
997 else { \
998 EXPECT_FALSE(ret); \
999 } \
1000 EXPECT_STREQ(path, expect_path); \
1001 } \
1002 ((void)0)
1003
1004#define PATH_EXTENSION_REPLACE(input_path, input_ext, expect_result, expect_path) \
1005 PATH_EXTENSION_REPLACE_WITH_MAXLEN(input_path, input_ext, expect_result, expect_path, FILE_MAX)
1006
1007TEST(path_utils, ExtensionReplace)
1008{
1009 PATH_EXTENSION_REPLACE("test", ".txt", true, "test.txt");
1010 PATH_EXTENSION_REPLACE("test.", ".txt", true, "test.txt");
1011 /* Unlike #BLI_path_extension_ensure, excess '.' are not stripped. */
1012 PATH_EXTENSION_REPLACE("test..", ".txt", true, "test..txt");
1013
1014 PATH_EXTENSION_REPLACE("test.txt", ".txt", true, "test.txt");
1015 PATH_EXTENSION_REPLACE("test.ext", ".txt", true, "test.txt");
1016
1017 PATH_EXTENSION_REPLACE("test", "_txt", true, "test_txt");
1018 PATH_EXTENSION_REPLACE("test.ext", "_txt", true, "test_txt");
1019
1020 PATH_EXTENSION_REPLACE("test", "", true, "test");
1021
1022 /* Same as #BLI_path_extension_strip. */
1023 PATH_EXTENSION_REPLACE("test.txt", "", true, "test");
1024
1025 /* Empty strings. */
1026 PATH_EXTENSION_REPLACE("test", "", true, "test");
1027 PATH_EXTENSION_REPLACE("", "_txt", true, "_txt");
1028 PATH_EXTENSION_REPLACE("", "", true, "");
1029
1030 /* Ensure leading '.' isn't treated as an extension. */
1031 PATH_EXTENSION_REPLACE(".hidden", ".hidden", true, ".hidden.hidden");
1032 PATH_EXTENSION_REPLACE("..hidden", ".hidden", true, "..hidden.hidden");
1033 PATH_EXTENSION_REPLACE("._.hidden", ".hidden", true, "._.hidden");
1034}
1035
1036TEST(path_utils, ExtensionReplace_Overflow)
1037{
1038 /* Small values. */
1039 PATH_EXTENSION_REPLACE_WITH_MAXLEN("test", ".txt", false, "test", 0);
1040 PATH_EXTENSION_REPLACE_WITH_MAXLEN("test", ".txt", false, "test", 1);
1041 /* One under fails, and exactly enough space succeeds. */
1042 PATH_EXTENSION_REPLACE_WITH_MAXLEN("test", ".txt", false, "test", 8);
1043 PATH_EXTENSION_REPLACE_WITH_MAXLEN("test", ".txt", true, "test.txt", 9);
1044
1045 PATH_EXTENSION_REPLACE_WITH_MAXLEN("test.xx", ".txt", false, "test.xx", 8);
1046 PATH_EXTENSION_REPLACE_WITH_MAXLEN("test.xx", ".txt", true, "test.txt", 9);
1047}
1048
1049#undef PATH_EXTENSION_REPLACE
1050#undef PATH_EXTENSION_REPLACE_WITH_MAXLEN
1051
1054/* -------------------------------------------------------------------- */
1058#define PATH_EXTENSION_ENSURE_WITH_MAXLEN( \
1059 input_path, input_ext, expect_result, expect_path, maxlen) \
1060 { \
1061 BLI_assert(maxlen <= FILE_MAX); \
1062 char path[FILE_MAX]; \
1063 STRNCPY(path, input_path); \
1064 const bool ret = BLI_path_extension_ensure(path, maxlen, input_ext); \
1065 if (expect_result) { \
1066 EXPECT_TRUE(ret); \
1067 } \
1068 else { \
1069 EXPECT_FALSE(ret); \
1070 } \
1071 EXPECT_STREQ(path, expect_path); \
1072 } \
1073 ((void)0)
1074
1075#define PATH_EXTENSION_ENSURE(input_path, input_ext, expect_result, expect_path) \
1076 PATH_EXTENSION_ENSURE_WITH_MAXLEN(input_path, input_ext, expect_result, expect_path, FILE_MAX)
1077
1078TEST(path_utils, ExtensionEnsure)
1079{
1080 PATH_EXTENSION_ENSURE("test", ".txt", true, "test.txt");
1081 PATH_EXTENSION_ENSURE("test.", ".txt", true, "test.txt");
1082 PATH_EXTENSION_ENSURE("test..", ".txt", true, "test.txt");
1083
1084 PATH_EXTENSION_ENSURE("test.txt", ".txt", true, "test.txt");
1085 PATH_EXTENSION_ENSURE("test.ext", ".txt", true, "test.ext.txt");
1086
1087 PATH_EXTENSION_ENSURE("test", "_txt", true, "test_txt");
1088 PATH_EXTENSION_ENSURE("test.ext", "_txt", true, "test.ext_txt");
1089
1090 /* An empty string does nothing (unlike replace which strips). */
1091 PATH_EXTENSION_ENSURE("test.txt", "", true, "test.txt");
1092
1093 /* Empty strings. */
1094 PATH_EXTENSION_ENSURE("test", "", true, "test");
1095 PATH_EXTENSION_ENSURE("", "_txt", true, "_txt");
1096 PATH_EXTENSION_ENSURE("", "", true, "");
1097
1098 /* Ensure leading '.' isn't treated as an extension. */
1099 PATH_EXTENSION_ENSURE(".hidden", ".hidden", true, ".hidden.hidden");
1100 PATH_EXTENSION_ENSURE("..hidden", ".hidden", true, "..hidden.hidden");
1101 PATH_EXTENSION_ENSURE("._.hidden", ".hidden", true, "._.hidden");
1102}
1103
1104TEST(path_utils, ExtensionEnsure_Overflow)
1105{
1106 /* Small values. */
1107 PATH_EXTENSION_ENSURE_WITH_MAXLEN("test", ".txt", false, "test", 0);
1108 PATH_EXTENSION_ENSURE_WITH_MAXLEN("test", ".txt", false, "test", 1);
1109 /* One under fails, and exactly enough space succeeds. */
1110 PATH_EXTENSION_ENSURE_WITH_MAXLEN("test", ".txt", false, "test", 8);
1111 PATH_EXTENSION_ENSURE_WITH_MAXLEN("test", ".txt", true, "test.txt", 9);
1112}
1113
1114#undef PATH_EXTENSION_ENSURE
1115#undef PATH_EXTENSION_ENSURE_WITH_MAXLEN
1116
1119/* -------------------------------------------------------------------- */
1123#define PATH_FRAME_CHECK_CHARS(input_path, expect_hasChars) \
1124 { \
1125 const bool ret = BLI_path_frame_check_chars(input_path); \
1126 if (expect_hasChars) { \
1127 EXPECT_TRUE(ret); \
1128 } \
1129 else { \
1130 EXPECT_FALSE(ret); \
1131 } \
1132 } \
1133 ((void)0)
1134
1135TEST(path_utils, FrameCheckChars)
1136{
1137 PATH_FRAME_CHECK_CHARS("a#", true);
1138 PATH_FRAME_CHECK_CHARS("aaaaa#", true);
1139 PATH_FRAME_CHECK_CHARS("#aaaaa", true);
1140 PATH_FRAME_CHECK_CHARS("a##.###", true);
1141 PATH_FRAME_CHECK_CHARS("####.abc#", true);
1142 PATH_FRAME_CHECK_CHARS("path/to/chars/a#", true);
1143 PATH_FRAME_CHECK_CHARS("path/to/chars/123#123.exe", true);
1144
1145 PATH_FRAME_CHECK_CHARS("&", false);
1146 PATH_FRAME_CHECK_CHARS("\35", false);
1147 PATH_FRAME_CHECK_CHARS("path#/to#/chars#/$.h", false);
1148 PATH_FRAME_CHECK_CHARS("path#/to#/chars#/nochars.h", false);
1149 PATH_FRAME_CHECK_CHARS("..\\dirty\\path#/..//to#\\chars#/nochars.h", false);
1150 PATH_FRAME_CHECK_CHARS("..\\dirty\\path#/..//to#/chars#\\nochars.h", false);
1151}
1152#undef PATH_FRAME_CHECK_CHARS
1153
1156/* -------------------------------------------------------------------- */
1160#define PATH_FRAME_RANGE(input_path, sta, end, digits, expect_outpath) \
1161 { \
1162 char path[FILE_MAX]; \
1163 bool ret; \
1164 STRNCPY(path, input_path); \
1165 ret = BLI_path_frame_range(path, sizeof(path), sta, end, digits); \
1166 if (expect_outpath == nullptr) { \
1167 EXPECT_FALSE(ret); \
1168 } \
1169 else { \
1170 EXPECT_TRUE(ret); \
1171 EXPECT_STREQ(path, expect_outpath); \
1172 } \
1173 } \
1174 ((void)0)
1175
1176TEST(path_utils, FrameRange)
1177{
1178 int dummy = -1;
1179 PATH_FRAME_RANGE("#", 1, 2, dummy, "1-2");
1180 PATH_FRAME_RANGE("##", 1, 2, dummy, "01-02");
1181 PATH_FRAME_RANGE("##", 1000, 2000, dummy, "1000-2000");
1182 PATH_FRAME_RANGE("###", 100, 200, dummy, "100-200");
1183 PATH_FRAME_RANGE("###", 8, 9, dummy, "008-009");
1184
1185 PATH_FRAME_RANGE("", 100, 200, 1, "100-200");
1186 PATH_FRAME_RANGE("", 123, 321, 4, "0123-0321");
1187 PATH_FRAME_RANGE("", 1, 0, 20, "00000000000000000001-00000000000000000000");
1188}
1189#undef PATH_FRAME_RANGE
1190
1193/* -------------------------------------------------------------------- */
1197#define PATH_FRAME_GET(input_path, expect_frame, expect_numdigits, expect_pathisvalid) \
1198 { \
1199 char path[FILE_MAX]; \
1200 int out_frame = -1, out_numdigits = -1; \
1201 STRNCPY(path, input_path); \
1202 const bool ret = BLI_path_frame_get(path, &out_frame, &out_numdigits); \
1203 if (expect_pathisvalid) { \
1204 EXPECT_TRUE(ret); \
1205 } \
1206 else { \
1207 EXPECT_FALSE(ret); \
1208 } \
1209 EXPECT_EQ(out_frame, expect_frame); \
1210 EXPECT_EQ(out_numdigits, expect_numdigits); \
1211 } \
1212 ((void)0)
1213
1214TEST(path_utils, FrameGet)
1215{
1216 PATH_FRAME_GET("001.avi", 1, 3, true);
1217 PATH_FRAME_GET("0000299.ext", 299, 7, true);
1218 PATH_FRAME_GET("path/to/frame_2810.dummy_quite_long_extension", 2810, 4, true);
1219 PATH_FRAME_GET("notframe_7_frame00018.bla", 18, 5, true);
1220
1221 PATH_FRAME_GET("", -1, -1, false);
1222}
1223#undef PATH_FRAME_GET
1224
1227/* -------------------------------------------------------------------- */
1231#define PATH_SEQ_DECODE(path_literal, expect_result, expect_head, expect_tail, expect_numdigits) \
1232 { \
1233 const char *path = path_literal; \
1234 char head[FILE_MAX]; \
1235 char tail[FILE_MAX]; \
1236 ushort numdigits = 0; \
1237 const int result = BLI_path_sequence_decode( \
1238 path, head, sizeof(head), tail, sizeof(tail), &numdigits); \
1239 EXPECT_EQ(result, expect_result); \
1240 EXPECT_STREQ(head, expect_head); \
1241 EXPECT_STREQ(tail, expect_tail); \
1242 EXPECT_EQ(numdigits, expect_numdigits); \
1243 } \
1244 (void)0;
1245
1246TEST(path_utils, SequenceDecode)
1247{
1248 /* Basic use. */
1249 PATH_SEQ_DECODE("file_123.txt", 123, "file_", ".txt", 3);
1250 PATH_SEQ_DECODE("file_123.321", 123, "file_", ".321", 3);
1251 PATH_SEQ_DECODE(".file_123.txt", 123, ".file_", ".txt", 3);
1252
1253 /* No-op. */
1254 PATH_SEQ_DECODE("file.txt", 0, "file", ".txt", 0);
1255 PATH_SEQ_DECODE("file.123", 0, "file", ".123", 0);
1256 PATH_SEQ_DECODE("file", 0, "file", "", 0);
1257 PATH_SEQ_DECODE("file_123.txt/", 0, "file_123.txt/", "", 0);
1258}
1259
1260#undef PATH_SEQ_DECODE
1261
1264/* -------------------------------------------------------------------- */
1268#define PATH_SUFFIX(path_literal, path_literal_max, sep, suffix, expect_result, expect_path) \
1269 { \
1270 char path[FILE_MAX] = path_literal; \
1271 const bool result = BLI_path_suffix(path, path_literal_max, suffix, sep); \
1272 EXPECT_EQ(result, expect_result); \
1273 EXPECT_STREQ(path, expect_path); \
1274 } \
1275 (void)0;
1276
1277TEST(path_utils, Suffix)
1278{
1279 /* Extension. */
1280 PATH_SUFFIX("file.txt", FILE_MAX, "_", "123", true, "file_123.txt");
1281 PATH_SUFFIX("/dir/file.txt", FILE_MAX, "_", "123", true, "/dir/file_123.txt");
1282 /* No-extension. */
1283 PATH_SUFFIX("file", FILE_MAX, "_", "123", true, "file_123");
1284 PATH_SUFFIX("/dir/file", FILE_MAX, "_", "123", true, "/dir/file_123");
1285 /* No-op. */
1286 PATH_SUFFIX("file.txt", FILE_MAX, "", "", true, "file.txt");
1287 /* Size limit, too short by 1. */
1288 PATH_SUFFIX("file.txt", 10, "A", "B", false, "file.txt");
1289 /* Size limit, fits exactly. */
1290 PATH_SUFFIX("file.txt", 11, "A", "B", true, "fileAB.txt");
1291 /* Empty path. */
1292 PATH_SUFFIX("", FILE_MAX, "_", "123", true, "_123");
1293 /* Empty input/output. */
1294 PATH_SUFFIX("", FILE_MAX, "", "", true, "");
1295
1296 /* Long suffix. */
1297 PATH_SUFFIX("file.txt", FILE_MAX, "_", "1234567890", true, "file_1234567890.txt");
1298 /* Long extension. */
1299 PATH_SUFFIX("file.txt1234567890", FILE_MAX, "_", "123", true, "file_123.txt1234567890");
1300}
1301
1302#undef PATH_SUFFIX
1303
1306/* -------------------------------------------------------------------- */
1310#define PATH_SLASH_FIND(path, expect_index) \
1311 { \
1312 const char *result = BLI_path_slash_find(path); \
1313 EXPECT_EQ(result, &path[expect_index]); \
1314 } \
1315 (void)0;
1316
1317TEST(path_util, SlashFind)
1318{
1319 PATH_SLASH_FIND("/", 0);
1320 PATH_SLASH_FIND("\\", 0);
1321 PATH_SLASH_FIND("\\tmp\\", 0);
1322 PATH_SLASH_FIND("/tmp\\", 0);
1323 PATH_SLASH_FIND("\\tmp/", 0);
1324 PATH_SLASH_FIND("/tmp/", 0);
1325 PATH_SLASH_FIND("tmp\\", 3);
1326 PATH_SLASH_FIND("tmp/", 3);
1327
1328 EXPECT_EQ(BLI_path_slash_find("no_slashes"), nullptr);
1329 EXPECT_EQ(BLI_path_slash_find(""), nullptr);
1330 EXPECT_EQ(BLI_path_slash_find("."), nullptr);
1331}
1332
1333#undef PATH_SLASH_FIND
1334
1337/* -------------------------------------------------------------------- */
1341#define PATH_SLASH_RFIND(path, expect_index) \
1342 { \
1343 const char *result = BLI_path_slash_rfind(path); \
1344 EXPECT_STREQ(result, &path[expect_index]); \
1345 } \
1346 (void)0;
1347
1348TEST(path_util, SlashRFind)
1349{
1350 PATH_SLASH_RFIND("/", 0);
1351 PATH_SLASH_RFIND("\\", 0);
1352 PATH_SLASH_RFIND("\\tmp\\", 4);
1353 PATH_SLASH_RFIND("/tmp\\", 4);
1354 PATH_SLASH_RFIND("\\tmp/", 4);
1355 PATH_SLASH_RFIND("/tmp/", 4);
1356 PATH_SLASH_RFIND("tmp\\", 3);
1357 PATH_SLASH_RFIND("tmp/", 3);
1358 PATH_SLASH_RFIND("/tmp", 0);
1359 PATH_SLASH_RFIND("\\tmp", 0);
1360
1361 EXPECT_EQ(BLI_path_slash_rfind("no_slashes"), nullptr);
1362 EXPECT_EQ(BLI_path_slash_rfind(""), nullptr);
1363 EXPECT_EQ(BLI_path_slash_rfind("."), nullptr);
1364}
1365
1366#undef PATH_SLASH_RFIND
1367
1370/* -------------------------------------------------------------------- */
1374#define PATH_SLASH_ENSURE(input, size, output_expect, length_expect) \
1375 { \
1376 char path[size] = input; \
1377 if (SEP == '\\') { \
1378 BLI_string_replace_char(path, '/', '\\'); \
1379 } \
1380 int result = BLI_path_slash_ensure(path, size); \
1381 if (SEP == '\\') { \
1382 BLI_string_replace_char(path, '\\', '/'); \
1383 } \
1384 EXPECT_STREQ(path, output_expect); \
1385 EXPECT_EQ(result, length_expect); \
1386 } \
1387 ((void)0)
1388
1389TEST(path_util, SlashEnsure)
1390{
1391 PATH_SLASH_ENSURE("/tmp", FILE_MAX, "/tmp/", 5);
1392 PATH_SLASH_ENSURE("", FILE_MAX, "/", 1);
1393 PATH_SLASH_ENSURE("", 2, "/", 1);
1394
1395 /* no change */
1396 PATH_SLASH_ENSURE("/tmp/", FILE_MAX, "/tmp/", 5);
1397 PATH_SLASH_ENSURE("/", FILE_MAX, "/", 1);
1398
1399 /* Not enough space reserved to add a slash, so do nothing. */
1400 PATH_SLASH_ENSURE("", 1, "", 0);
1401 PATH_SLASH_ENSURE("/tmp", 5, "/tmp", 4);
1402}
1403
1404#undef PATH_SLASH_ENSURE
1405
1408/* -------------------------------------------------------------------- */
1412#define PATH_SLASH_RSTRIP(input, expected) \
1413 { \
1414 char path[FILE_MAX] = input; \
1415 if (SEP == '\\') { \
1416 BLI_string_replace_char(path, '/', '\\'); \
1417 } \
1418 BLI_path_slash_rstrip(path); \
1419 if (SEP == '\\') { \
1420 BLI_string_replace_char(path, '\\', '/'); \
1421 } \
1422 EXPECT_STREQ(path, expected); \
1423 } \
1424 ((void)0)
1425
1426TEST(path_util, SlashRStrip)
1427{
1428 PATH_SLASH_RSTRIP("/brown/cow/", "/brown/cow");
1429 PATH_SLASH_RSTRIP("/brown/cow", "/brown/cow");
1430 PATH_SLASH_RSTRIP("/brown/", "/brown");
1431 PATH_SLASH_RSTRIP("/brown", "/brown");
1432 PATH_SLASH_RSTRIP("/brown/../", "/brown/..");
1433 PATH_SLASH_RSTRIP("/brown/..", "/brown/..");
1434 PATH_SLASH_RSTRIP("/brown///", "/brown");
1435 PATH_SLASH_RSTRIP("/", "");
1436 PATH_SLASH_RSTRIP("", "");
1437 PATH_SLASH_RSTRIP(".", ".");
1438}
1439
1440#undef PATH_SLASH_RSTRIP
1441
1444/* -------------------------------------------------------------------- */
1448#define PATH_SLASH_SKIP(input, expected) \
1449 { \
1450 char path[FILE_MAX] = input; \
1451 if (SEP == '\\') { \
1452 BLI_string_replace_char(path, '/', '\\'); \
1453 } \
1454 const char *skipped = BLI_path_slash_skip(path); \
1455 if (SEP == '\\') { \
1456 BLI_string_replace_char(path, '\\', '/'); \
1457 } \
1458 EXPECT_STREQ(skipped, expected); \
1459 } \
1460 ((void)0)
1461
1462TEST(path_util, SlashSkip)
1463{
1464 PATH_SLASH_SKIP("/brown", "brown");
1465 PATH_SLASH_SKIP("brown", "brown");
1466 PATH_SLASH_SKIP("////brown", "brown");
1467 PATH_SLASH_SKIP("/../brown", "../brown");
1468 PATH_SLASH_SKIP("../brown", "../brown");
1469 PATH_SLASH_SKIP("/", "");
1470 PATH_SLASH_SKIP("/////", "");
1471 PATH_SLASH_SKIP("", "");
1472 PATH_SLASH_SKIP(".", ".");
1473}
1474
1475#undef PATH_SLASH_SKIP
1476
1479/* -------------------------------------------------------------------- */
1483#define PATH_SLASH_NATIVE(input, expected) \
1484 { \
1485 char path[FILE_MAX] = input; \
1486 BLI_path_slash_native(path); \
1487 EXPECT_STREQ(path, expected); \
1488 } \
1489 ((void)0)
1490
1491TEST(path_util, SlashNative)
1492{
1493#ifdef WIN32
1494 PATH_SLASH_NATIVE("C:/", "C:\\");
1495 PATH_SLASH_NATIVE("C:\\", "C:\\");
1496 PATH_SLASH_NATIVE("C:\\tmp\\", "C:\\tmp\\");
1497 PATH_SLASH_NATIVE("C:/tmp\\", "C:\\tmp\\");
1498 PATH_SLASH_NATIVE("C:\\tmp/", "C:\\tmp\\");
1499 PATH_SLASH_NATIVE("C:/tmp/", "C:\\tmp\\");
1500 PATH_SLASH_NATIVE("tmp\\", "tmp\\");
1501 PATH_SLASH_NATIVE("tmp/", "tmp\\");
1502 PATH_SLASH_NATIVE("..\\tmp\\", "..\\tmp\\");
1503 PATH_SLASH_NATIVE("../tmp/", "..\\tmp\\");
1504 PATH_SLASH_NATIVE("C:/tmp", "C:\\tmp");
1505 PATH_SLASH_NATIVE("C:\\tmp", "C:\\tmp");
1506 PATH_SLASH_NATIVE("tmp", "tmp");
1507 PATH_SLASH_NATIVE("", "");
1508 PATH_SLASH_NATIVE(".", ".");
1509
1510 PATH_SLASH_NATIVE("\\\\server\\share", "\\\\server\\share");
1511 PATH_SLASH_NATIVE("\\\\server/share", "\\\\server\\share");
1512 PATH_SLASH_NATIVE("\\\\?\\server\\share", "\\\\?\\server\\share");
1513 PATH_SLASH_NATIVE("\\\\?\\server/share", "\\\\?\\server\\share");
1514 PATH_SLASH_NATIVE("\\\\?\\C:\\file.txt", "\\\\?\\C:\\file.txt");
1515 PATH_SLASH_NATIVE("\\\\?\\C:/file.txt", "\\\\?\\C:\\file.txt");
1516#else
1517 PATH_SLASH_NATIVE("/", "/");
1518 PATH_SLASH_NATIVE("\\", "/");
1519 PATH_SLASH_NATIVE("\\tmp\\", "/tmp/");
1520 PATH_SLASH_NATIVE("/tmp\\", "/tmp/");
1521 PATH_SLASH_NATIVE("\\tmp/", "/tmp/");
1522 PATH_SLASH_NATIVE("/tmp/", "/tmp/");
1523 PATH_SLASH_NATIVE("tmp\\", "tmp/");
1524 PATH_SLASH_NATIVE("tmp/", "tmp/");
1525 PATH_SLASH_NATIVE("..\\tmp\\", "../tmp/");
1526 PATH_SLASH_NATIVE("../tmp/", "../tmp/");
1527 PATH_SLASH_NATIVE("/tmp", "/tmp");
1528 PATH_SLASH_NATIVE("\\tmp", "/tmp");
1529 PATH_SLASH_NATIVE("tmp", "tmp");
1530 PATH_SLASH_NATIVE("", "");
1531 PATH_SLASH_NATIVE(".", ".");
1532
1533 PATH_SLASH_NATIVE("\\\\server\\share", "\\\\server/share");
1534 PATH_SLASH_NATIVE("\\\\server/share", "\\\\server/share");
1535 PATH_SLASH_NATIVE("\\\\?\\server\\share", "\\\\?\\server/share");
1536 PATH_SLASH_NATIVE("\\\\?\\server/share", "\\\\?\\server/share");
1537 PATH_SLASH_NATIVE("\\\\?\\home\\user\\file.txt", "\\\\?\\home/user/file.txt");
1538 PATH_SLASH_NATIVE("\\\\?\\home\\user/file.txt", "\\\\?\\home/user/file.txt");
1539#endif
1540}
1541
1542#undef PATH_SLASH_NATIVE
1543
1546/* -------------------------------------------------------------------- */
1550#define PATH_REL(abs_path, ref_path, rel_path_expect) \
1551 { \
1552 char path[FILE_MAX]; \
1553 const char *ref_path_test = ref_path; \
1554 STRNCPY(path, abs_path); \
1555 if (SEP == '\\') { \
1556 BLI_string_replace_char(path, '/', '\\'); \
1557 ref_path_test = str_replace_char_strdup(ref_path_test, '/', '\\'); \
1558 } \
1559 BLI_path_rel(path, ref_path_test); \
1560 if (SEP == '\\') { \
1561 BLI_string_replace_char(path, '\\', '/'); \
1562 free((void *)ref_path_test); \
1563 } \
1564 EXPECT_STREQ(path, rel_path_expect); \
1565 } \
1566 void(0)
1567
1568#ifdef WIN32
1569# define ABS_PREFIX "C:"
1570#else
1571# define ABS_PREFIX ""
1572#endif
1573
1574TEST(path_utils, RelPath_Simple)
1575{
1576 PATH_REL(ABS_PREFIX "/foo/bar/blender.blend", ABS_PREFIX "/foo/bar/", "//blender.blend");
1577}
1578
1579TEST(path_utils, RelPath_SimpleSubdir)
1580{
1581 PATH_REL(ABS_PREFIX "/foo/bar/blender.blend", ABS_PREFIX "/foo/bar", "//bar/blender.blend");
1582}
1583
1584TEST(path_utils, RelPath_BufferOverflowRoot)
1585{
1586 char abs_path_in[FILE_MAX];
1587 const char *abs_prefix = ABS_PREFIX "/";
1588 for (int i = STRNCPY_RLEN(abs_path_in, abs_prefix); i < FILE_MAX - 1; i++) {
1589 abs_path_in[i] = 'A';
1590 }
1591 abs_path_in[FILE_MAX - 1] = '\0';
1592 char abs_path_out[FILE_MAX];
1593 for (int i = STRNCPY_RLEN(abs_path_out, "//"); i < FILE_MAX - 1; i++) {
1594 abs_path_out[i] = 'A';
1595 }
1596 abs_path_out[FILE_MAX - std::max((strlen(abs_prefix) - 1), size_t(1))] = '\0';
1597 PATH_REL(abs_path_in, abs_prefix, abs_path_out);
1598}
1599
1600TEST(path_utils, RelPath_BufferOverflowSubdir)
1601{
1602 char abs_path_in[FILE_MAX];
1603 const char *ref_path_in = ABS_PREFIX "/foo/bar/";
1604 const size_t ref_path_in_len = strlen(ref_path_in);
1605 for (int i = STRNCPY_RLEN(abs_path_in, ref_path_in); i < FILE_MAX - 1; i++) {
1606 abs_path_in[i] = 'A';
1607 }
1608 abs_path_in[FILE_MAX - 1] = '\0';
1609 char abs_path_out[FILE_MAX];
1610 for (int i = STRNCPY_RLEN(abs_path_out, "//"); i < FILE_MAX - (int(ref_path_in_len) - 1); i++) {
1611 abs_path_out[i] = 'A';
1612 }
1613 abs_path_out[FILE_MAX - std::max((ref_path_in_len - 1), size_t(1))] = '\0';
1614 PATH_REL(abs_path_in, ref_path_in, abs_path_out);
1615}
1616
1617#undef PATH_REL
1618#undef ABS_PREFIX
1619
1622/* -------------------------------------------------------------------- */
1626TEST(path_utils, PathIsRel)
1627{
1628 EXPECT_TRUE(BLI_path_is_rel("//file.txt"));
1629
1630 EXPECT_FALSE(BLI_path_is_rel(""));
1631 EXPECT_FALSE(BLI_path_is_rel("."));
1632 EXPECT_FALSE(BLI_path_is_rel("\\file.txt"));
1633 EXPECT_FALSE(BLI_path_is_rel("\\\\file.txt"));
1634 EXPECT_FALSE(BLI_path_is_rel(".hide/file.txt"));
1635 EXPECT_FALSE(BLI_path_is_rel("file.txt"));
1636 EXPECT_FALSE(BLI_path_is_rel("C:/file.txt"));
1637 EXPECT_FALSE(BLI_path_is_rel("../file.txt"));
1638 EXPECT_FALSE(BLI_path_is_rel("\\\\host\\server\\file.txt"));
1639 EXPECT_FALSE(BLI_path_is_rel("\\\\?\\C:\\server\\file.txt"));
1640}
1641
1644/* -------------------------------------------------------------------- */
1648TEST(path_utils, PathIsAbsFromCwd)
1649{
1650#ifdef WIN32
1651 EXPECT_FALSE(BLI_path_is_abs_from_cwd("/file.txt"));
1652 EXPECT_FALSE(BLI_path_is_abs_from_cwd("/"));
1653
1654 EXPECT_TRUE(BLI_path_is_abs_from_cwd("C:"));
1655 EXPECT_TRUE(BLI_path_is_abs_from_cwd("C:/file.txt"));
1656 EXPECT_TRUE(BLI_path_is_abs_from_cwd("C:\\file.txt"));
1657 EXPECT_TRUE(BLI_path_is_abs_from_cwd("\\\\host\\server\\file.txt"));
1658 EXPECT_TRUE(BLI_path_is_abs_from_cwd("\\\\?\\C:\\server\\file.txt"));
1659#else
1660 EXPECT_TRUE(BLI_path_is_abs_from_cwd("/file.txt"));
1661 EXPECT_TRUE(BLI_path_is_abs_from_cwd("/"));
1662
1663 EXPECT_FALSE(BLI_path_is_abs_from_cwd("C:"));
1664 EXPECT_FALSE(BLI_path_is_abs_from_cwd("C:/file.txt"));
1665 EXPECT_FALSE(BLI_path_is_abs_from_cwd("C:\\file.txt"));
1666 EXPECT_FALSE(BLI_path_is_abs_from_cwd("\\\\host\\server\\file.txt"));
1667 EXPECT_FALSE(BLI_path_is_abs_from_cwd("\\\\?\\C:\\server\\file.txt"));
1668#endif
1669
1670 EXPECT_FALSE(BLI_path_is_abs_from_cwd(""));
1671 EXPECT_FALSE(BLI_path_is_abs_from_cwd("."));
1672 EXPECT_FALSE(BLI_path_is_abs_from_cwd("file.txt"));
1673 EXPECT_FALSE(BLI_path_is_abs_from_cwd("../file.txt"));
1674 EXPECT_FALSE(BLI_path_is_abs_from_cwd("./file.txt"));
1675}
1676
1679/* -------------------------------------------------------------------- */
1683TEST(path_utils, Contains)
1684{
1685 EXPECT_TRUE(BLI_path_contains("/some/path", "/some/path")) << "A path contains itself";
1686 EXPECT_TRUE(BLI_path_contains("/some/path", "/some/path/inside"))
1687 << "A path contains its subdirectory";
1688 EXPECT_TRUE(BLI_path_contains("/some/path", "/some/path/../path/inside"))
1689 << "Paths should be normalized";
1690 EXPECT_TRUE(BLI_path_contains("C:\\some\\path", "C:\\some\\path\\inside"))
1691 << "Windows paths should be supported as well";
1692
1693 EXPECT_FALSE(BLI_path_contains("C:\\some\\path", "C:\\some\\other\\path"))
1694 << "Windows paths should be supported as well";
1695 EXPECT_FALSE(BLI_path_contains("/some/path", "/"))
1696 << "Root directory not be contained in a subdirectory";
1697 EXPECT_FALSE(BLI_path_contains("/some/path", "/some/path/../outside"))
1698 << "Paths should be normalized";
1699 EXPECT_FALSE(BLI_path_contains("/some/path", "/some/path_library"))
1700 << "Just sharing a suffix is not enough, path semantics should be followed";
1701 EXPECT_FALSE(BLI_path_contains("/some/path", "./contents"))
1702 << "Relative paths are not supported";
1703}
1704
1705#ifdef WIN32
1706TEST(path_utils, Contains_Windows_case_insensitive)
1707{
1708 EXPECT_TRUE(BLI_path_contains("C:\\some\\path", "c:\\SOME\\path\\inside"))
1709 << "On Windows path comparison should ignore case";
1710}
1711#endif /* WIN32 */
1712
1715/* -------------------------------------------------------------------- */
1719TEST(path_utils, HasHiddenComponents)
1720{
1721 /* No hidden components: */
1722 EXPECT_FALSE(BLI_path_has_hidden_component(""));
1723 EXPECT_FALSE(BLI_path_has_hidden_component(" "));
1724 EXPECT_FALSE(BLI_path_has_hidden_component(".."));
1725 EXPECT_FALSE(BLI_path_has_hidden_component("../.."));
1726 EXPECT_FALSE(BLI_path_has_hidden_component("..\\.."));
1727 EXPECT_FALSE(BLI_path_has_hidden_component("a/../b"));
1728 EXPECT_FALSE(BLI_path_has_hidden_component("a\\..\\b"));
1729 EXPECT_FALSE(BLI_path_has_hidden_component("a"));
1730 EXPECT_FALSE(BLI_path_has_hidden_component("a~b"));
1731 EXPECT_FALSE(BLI_path_has_hidden_component("a/b"));
1732 EXPECT_FALSE(BLI_path_has_hidden_component("a\\b"));
1733 EXPECT_FALSE(BLI_path_has_hidden_component("a/b/c"));
1734 EXPECT_FALSE(BLI_path_has_hidden_component("a\\b\\c"));
1735 EXPECT_FALSE(BLI_path_has_hidden_component("/a/b"));
1736 EXPECT_FALSE(BLI_path_has_hidden_component("C:/a/b"));
1737 EXPECT_FALSE(BLI_path_has_hidden_component("C:/\a\\b"));
1738 EXPECT_FALSE(BLI_path_has_hidden_component("a.txt"));
1739 EXPECT_FALSE(BLI_path_has_hidden_component("a/b.txt"));
1740 EXPECT_FALSE(BLI_path_has_hidden_component("a\\b.txt"));
1741 EXPECT_FALSE(BLI_path_has_hidden_component("/"));
1742 EXPECT_FALSE(BLI_path_has_hidden_component("\\"));
1743 EXPECT_FALSE(BLI_path_has_hidden_component("a."));
1744 EXPECT_FALSE(BLI_path_has_hidden_component("a./b."));
1745
1746 /* NOTE: path component that is just a dot is not considered hidden. */
1747 EXPECT_FALSE(BLI_path_has_hidden_component("."));
1748 EXPECT_FALSE(BLI_path_has_hidden_component("a/."));
1749 EXPECT_FALSE(BLI_path_has_hidden_component("a\\."));
1750 EXPECT_FALSE(BLI_path_has_hidden_component("a/./b"));
1751 EXPECT_FALSE(BLI_path_has_hidden_component("a\\.\\b"));
1752 EXPECT_FALSE(BLI_path_has_hidden_component("./a"));
1753 EXPECT_FALSE(BLI_path_has_hidden_component(".\\a"));
1754
1755 /* Does contain hidden components: */
1756 EXPECT_TRUE(BLI_path_has_hidden_component(".a"));
1757 EXPECT_TRUE(BLI_path_has_hidden_component(".a.b"));
1758 EXPECT_TRUE(BLI_path_has_hidden_component("a/.b"));
1759 EXPECT_TRUE(BLI_path_has_hidden_component("a\\.b"));
1760 EXPECT_TRUE(BLI_path_has_hidden_component(".a/b"));
1761 EXPECT_TRUE(BLI_path_has_hidden_component(".a\\b"));
1762 EXPECT_TRUE(BLI_path_has_hidden_component(".a/.b"));
1763 EXPECT_TRUE(BLI_path_has_hidden_component(".a\\.b"));
1764 EXPECT_TRUE(BLI_path_has_hidden_component("a/.b.c"));
1765 EXPECT_TRUE(BLI_path_has_hidden_component("a/.b/c.txt"));
1766 EXPECT_TRUE(BLI_path_has_hidden_component("a\\.b\\c.txt"));
1767
1768 /* Tilde at end of path component: considered hidden. */
1769 EXPECT_TRUE(BLI_path_has_hidden_component("~"));
1770 EXPECT_TRUE(BLI_path_has_hidden_component("a~"));
1771 EXPECT_TRUE(BLI_path_has_hidden_component("a/~/c"));
1772 EXPECT_TRUE(BLI_path_has_hidden_component("a/b~/c"));
1773 EXPECT_TRUE(BLI_path_has_hidden_component("a\\b~\\c"));
1774 EXPECT_TRUE(BLI_path_has_hidden_component("~/b"));
1775 EXPECT_TRUE(BLI_path_has_hidden_component("a~/b"));
1776 EXPECT_TRUE(BLI_path_has_hidden_component("a~\\b"));
1777}
1778
1779#if DO_PERF_TESTS
1780
1781# include "BLI_timeit.hh"
1782
1783TEST(path_utils, HasHiddenComponents_Performance)
1784{
1785 SCOPED_TIMER(__func__);
1786 const char *test_paths[] = {
1787 "test.txt",
1788 "test/a_fairly_long/path/here/shall_we/ok.txt",
1789 "test/a_fairly_long/path/here/.with_a_hidden_component/shall_we/ok.txt",
1790 "test/.another_path_with_hidden_component/yes.txt",
1791 "test/another/path/with/.hidden_filename",
1792 };
1793 const int RUN_COUNT = 10'000'000;
1794 int hidden = 0;
1795 for (int i = 0; i < RUN_COUNT; i++) {
1796 for (int j = 0; j < ARRAY_SIZE(test_paths); j++) {
1797 hidden += BLI_path_has_hidden_component(test_paths[j]) ? 1 : 0;
1798 }
1799 }
1800 EXPECT_EQ(RUN_COUNT * 3, hidden);
1801}
1802
1803#endif
1804
EXPECT_EQ(BLI_expr_pylike_eval(expr, nullptr, 0, &result), EXPR_PYLIKE_INVALID)
File and directory operations.
bool BLI_path_has_hidden_component(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
#define FILE_MAX
bool BLI_path_contains(const char *container_path, const char *containee_path) ATTR_NONNULL(1
bool BLI_path_is_win32_drive(const char *path)
bool BLI_path_is_abs_from_cwd(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
void BLI_path_split_dir_file(const char *filepath, char *dir, size_t dir_maxncpy, char *file, size_t file_maxncpy) ATTR_NONNULL(1
bool BLI_path_is_rel(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
const char * BLI_path_slash_find(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
int BLI_path_cmp_normalized(const char *p1, const char *p2) ATTR_NONNULL(1
bool BLI_path_is_win32_drive_only(const char *path)
bool BLI_path_is_win32_drive_with_slash(const char *path)
const char * BLI_path_slash_rfind(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
const char * BLI_path_extension(const char *filepath) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
bool BLI_path_frame(char *path, size_t path_maxncpy, int frame, int digits) ATTR_NONNULL(1)
bool BLI_path_is_unc(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
#define PATH_EXTENSION_REPLACE(input_path, input_ext, expect_result, expect_path)
#define PATH_SLASH_NATIVE(input, expected)
#define PATH_FRAME_RANGE(input_path, sta, end, digits, expect_outpath)
#define PATH_SLASH_RSTRIP(input, expected)
#define JOIN
#define PATH_SLASH_ENSURE(input, size, output_expect, length_expect)
#define PATH_EXTENSION_CHECK(input_path, input_ext, expect_ext)
#define PATH_SLASH_FIND(path, expect_index)
#define PATH_FRAME_STRIP(input_path, expect_path, expect_ext)
#define APPEND(str_expect, size, path, filename)
#define TEST_STR
#define PATH_SLASH_RFIND(path, expect_index)
#define PATH_SEQ_DECODE(path_literal, expect_result, expect_head, expect_tail, expect_numdigits)
#define AT_INDEX(str_input, index_input, str_expect)
#define ABS_PREFIX
#define PATH_EXTENSION_REPLACE_WITH_MAXLEN(input_path, input_ext, expect_result, expect_path, maxlen)
static void str_replace_char_with_relative_exception(char *str, char src, char dst)
#define PATH_SLASH_SKIP(input, expected)
#define NORMALIZE(input, output_expect)
TEST(path_utils, Normalize_Nop)
#define PATH_EXTENSION_ENSURE_WITH_MAXLEN(input_path, input_ext, expect_result, expect_path, maxlen)
#define PATH_FRAME_GET(input_path, expect_frame, expect_numdigits, expect_pathisvalid)
#define PATH_FRAME_CHECK_CHARS(input_path, expect_hasChars)
#define PARENT_DIR(input, output_expect)
static char * str_replace_char_strdup(const char *str, char src, char dst)
#define PATH_SUFFIX(path_literal, path_literal_max, sep, suffix, expect_result, expect_path)
#define PATH_REL(abs_path, ref_path, rel_path_expect)
#define PATH_EXTENSION_ENSURE(input_path, input_ext, expect_result, expect_path)
#define STRNCPY_RLEN(dst, src)
Definition BLI_string.h:596
int bool bool BLI_str_endswith(const char *__restrict str, const char *__restrict end) ATTR_NONNULL(1
void BLI_string_replace_char(char *str, char src, char dst) ATTR_NONNULL(1)
#define SCOPED_TIMER(name)
Definition BLI_timeit.hh:61
#define ARRAY_SIZE(arr)
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
#define str(s)
return ret