1 /* Apache License, Version 2.0 */
2 
3 #include "testing/testing.h"
4 
5 #include "IMB_imbuf.h"
6 
7 #include "BLI_fileops.h"
8 #include "BLI_path_util.h"
9 #include "BLI_string.h"
10 
11 /* -------------------------------------------------------------------- */
12 /* tests */
13 
14 /* BLI_path_normalize */
15 #ifndef _WIN32
TEST(path_util,Clean)16 TEST(path_util, Clean)
17 {
18   /* "/./" -> "/" */
19   {
20     char path[FILE_MAX] = "/a/./b/./c/./";
21     BLI_path_normalize(NULL, path);
22     EXPECT_STREQ("/a/b/c/", path);
23   }
24 
25   {
26     char path[FILE_MAX] = "/./././";
27     BLI_path_normalize(NULL, path);
28     EXPECT_STREQ("/", path);
29   }
30 
31   {
32     char path[FILE_MAX] = "/a/./././b/";
33     BLI_path_normalize(NULL, path);
34     EXPECT_STREQ("/a/b/", path);
35   }
36 
37   /* "//" -> "/" */
38   {
39     char path[FILE_MAX] = "a////";
40     BLI_path_normalize(NULL, path);
41     EXPECT_STREQ("a/", path);
42   }
43 
44   if (0) /* FIXME */
45   {
46     char path[FILE_MAX] = "./a////";
47     BLI_path_normalize(NULL, path);
48     EXPECT_STREQ("./a/", path);
49   }
50 
51   /* "foo/bar/../" -> "foo/" */
52   {
53     char path[FILE_MAX] = "/a/b/c/../../../";
54     BLI_path_normalize(NULL, path);
55     EXPECT_STREQ("/", path);
56   }
57 
58   {
59     char path[FILE_MAX] = "/a/../a/b/../b/c/../c/";
60     BLI_path_normalize(NULL, path);
61     EXPECT_STREQ("/a/b/c/", path);
62   }
63 
64   {
65     char path[FILE_MAX] = "//../";
66     BLI_path_normalize("/a/b/c/", path);
67     EXPECT_STREQ("/a/b/", path);
68   }
69 }
70 #endif
71 
72 #define AT_INDEX(str_input, index_input, str_expect) \
73   { \
74     char path[] = str_input; \
75     const char *expect = str_expect; \
76     int index_output, len_output; \
77     const bool ret = BLI_path_name_at_index(path, index_input, &index_output, &len_output); \
78     if (expect == NULL) { \
79       EXPECT_FALSE(ret); \
80     } \
81     else { \
82       EXPECT_TRUE(ret); \
83       EXPECT_EQ(strlen(expect), len_output); \
84       path[index_output + len_output] = '\0'; \
85       EXPECT_STREQ(&path[index_output], expect); \
86     } \
87   } \
88   ((void)0)
89 
90 /* BLI_path_name_at_index */
TEST(path_util,NameAtIndex_Single)91 TEST(path_util, NameAtIndex_Single)
92 {
93   AT_INDEX("/a", 0, "a");
94   AT_INDEX("/a/", 0, "a");
95   AT_INDEX("a/", 0, "a");
96   AT_INDEX("//a//", 0, "a");
97   AT_INDEX("a/b", 0, "a");
98 
99   AT_INDEX("/a", 1, NULL);
100   AT_INDEX("/a/", 1, NULL);
101   AT_INDEX("a/", 1, NULL);
102   AT_INDEX("//a//", 1, NULL);
103 }
TEST(path_util,NameAtIndex_SingleNeg)104 TEST(path_util, NameAtIndex_SingleNeg)
105 {
106   AT_INDEX("/a", -1, "a");
107   AT_INDEX("/a/", -1, "a");
108   AT_INDEX("a/", -1, "a");
109   AT_INDEX("//a//", -1, "a");
110   AT_INDEX("a/b", -1, "b");
111 
112   AT_INDEX("/a", -2, NULL);
113   AT_INDEX("/a/", -2, NULL);
114   AT_INDEX("a/", -2, NULL);
115   AT_INDEX("//a//", -2, NULL);
116 }
117 
TEST(path_util,NameAtIndex_Double)118 TEST(path_util, NameAtIndex_Double)
119 {
120   AT_INDEX("/ab", 0, "ab");
121   AT_INDEX("/ab/", 0, "ab");
122   AT_INDEX("ab/", 0, "ab");
123   AT_INDEX("//ab//", 0, "ab");
124   AT_INDEX("ab/c", 0, "ab");
125 
126   AT_INDEX("/ab", 1, NULL);
127   AT_INDEX("/ab/", 1, NULL);
128   AT_INDEX("ab/", 1, NULL);
129   AT_INDEX("//ab//", 1, NULL);
130 }
131 
TEST(path_util,NameAtIndex_DoublNeg)132 TEST(path_util, NameAtIndex_DoublNeg)
133 {
134   AT_INDEX("/ab", -1, "ab");
135   AT_INDEX("/ab/", -1, "ab");
136   AT_INDEX("ab/", -1, "ab");
137   AT_INDEX("//ab//", -1, "ab");
138   AT_INDEX("ab/c", -1, "c");
139 
140   AT_INDEX("/ab", -2, NULL);
141   AT_INDEX("/ab/", -2, NULL);
142   AT_INDEX("ab/", -2, NULL);
143   AT_INDEX("//ab//", -2, NULL);
144 }
145 
TEST(path_util,NameAtIndex_Misc)146 TEST(path_util, NameAtIndex_Misc)
147 {
148   AT_INDEX("/how/now/brown/cow", 0, "how");
149   AT_INDEX("/how/now/brown/cow", 1, "now");
150   AT_INDEX("/how/now/brown/cow", 2, "brown");
151   AT_INDEX("/how/now/brown/cow", 3, "cow");
152   AT_INDEX("/how/now/brown/cow", 4, NULL);
153   AT_INDEX("/how/now/brown/cow/", 4, NULL);
154 }
155 
TEST(path_util,NameAtIndex_MiscNeg)156 TEST(path_util, NameAtIndex_MiscNeg)
157 {
158   AT_INDEX("/how/now/brown/cow", 0, "how");
159   AT_INDEX("/how/now/brown/cow", 1, "now");
160   AT_INDEX("/how/now/brown/cow", 2, "brown");
161   AT_INDEX("/how/now/brown/cow", 3, "cow");
162   AT_INDEX("/how/now/brown/cow", 4, NULL);
163   AT_INDEX("/how/now/brown/cow/", 4, NULL);
164 }
165 
TEST(path_util,NameAtIndex_MiscComplex)166 TEST(path_util, NameAtIndex_MiscComplex)
167 {
168   AT_INDEX("how//now/brown/cow", 0, "how");
169   AT_INDEX("//how///now\\/brown/cow", 1, "now");
170   AT_INDEX("/how/now\\//brown\\/cow", 2, "brown");
171   AT_INDEX("/how/now/brown/cow//\\", 3, "cow");
172   AT_INDEX("/how/now/brown/\\cow", 4, NULL);
173   AT_INDEX("how/now/brown/\\cow\\", 4, NULL);
174 }
175 
TEST(path_util,NameAtIndex_MiscComplexNeg)176 TEST(path_util, NameAtIndex_MiscComplexNeg)
177 {
178   AT_INDEX("how//now/brown/cow", -4, "how");
179   AT_INDEX("//how///now\\/brown/cow", -3, "now");
180   AT_INDEX("/how/now\\//brown\\/cow", -2, "brown");
181   AT_INDEX("/how/now/brown/cow//\\", -1, "cow");
182   AT_INDEX("/how/now/brown/\\cow", -5, NULL);
183   AT_INDEX("how/now/brown/\\cow\\", -5, NULL);
184 }
185 
TEST(path_util,NameAtIndex_NoneComplex)186 TEST(path_util, NameAtIndex_NoneComplex)
187 {
188   AT_INDEX("", 0, NULL);
189   AT_INDEX("/", 0, NULL);
190   AT_INDEX("//", 0, NULL);
191   AT_INDEX("///", 0, NULL);
192 }
193 
TEST(path_util,NameAtIndex_NoneComplexNeg)194 TEST(path_util, NameAtIndex_NoneComplexNeg)
195 {
196   AT_INDEX("", -1, NULL);
197   AT_INDEX("/", -1, NULL);
198   AT_INDEX("//", -1, NULL);
199   AT_INDEX("///", -1, NULL);
200 }
201 
202 #undef AT_INDEX
203 
204 #define JOIN(str_expect, out_size, ...) \
205   { \
206     const char *expect = str_expect; \
207     char result[(out_size) + 1024]; \
208     /* check we don't write past the last byte */ \
209     result[out_size] = '\0'; \
210     BLI_path_join(result, out_size, __VA_ARGS__, NULL); \
211     /* simplify expected string */ \
212     BLI_str_replace_char(result, '\\', '/'); \
213     EXPECT_STREQ(result, expect); \
214     EXPECT_EQ(result[out_size], '\0'); \
215   } \
216   ((void)0)
217 
218 /* BLI_path_join */
TEST(path_util,JoinNop)219 TEST(path_util, JoinNop)
220 {
221   JOIN("", 100, "");
222   JOIN("", 100, "", "");
223   JOIN("", 100, "", "", "");
224   JOIN("/", 100, "/", "", "");
225   JOIN("/", 100, "/", "/");
226   JOIN("/", 100, "/", "", "/");
227   JOIN("/", 100, "/", "", "/", "");
228 }
229 
TEST(path_util,JoinSingle)230 TEST(path_util, JoinSingle)
231 {
232   JOIN("test", 100, "test");
233   JOIN("", 100, "");
234   JOIN("a", 100, "a");
235   JOIN("/a", 100, "/a");
236   JOIN("a/", 100, "a/");
237   JOIN("/a/", 100, "/a/");
238   JOIN("/a/", 100, "/a//");
239   JOIN("//a/", 100, "//a//");
240 }
241 
TEST(path_util,JoinTriple)242 TEST(path_util, JoinTriple)
243 {
244   JOIN("/a/b/c", 100, "/a", "b", "c");
245   JOIN("/a/b/c", 100, "/a/", "/b/", "/c");
246   JOIN("/a/b/c", 100, "/a/b/", "/c");
247   JOIN("/a/b/c", 100, "/a/b/c");
248   JOIN("/a/b/c", 100, "/", "a/b/c");
249 
250   JOIN("/a/b/c/", 100, "/a/", "/b/", "/c/");
251   JOIN("/a/b/c/", 100, "/a/b/c/");
252   JOIN("/a/b/c/", 100, "/a/b/", "/c/");
253   JOIN("/a/b/c/", 100, "/a/b/c", "/");
254   JOIN("/a/b/c/", 100, "/", "a/b/c", "/");
255 }
256 
TEST(path_util,JoinTruncateShort)257 TEST(path_util, JoinTruncateShort)
258 {
259   JOIN("", 1, "/");
260   JOIN("/", 2, "/");
261   JOIN("a", 2, "", "aa");
262   JOIN("a", 2, "", "a/");
263   JOIN("a/b", 4, "a", "bc");
264   JOIN("ab/", 4, "ab", "c");
265   JOIN("/a/", 4, "/a", "b");
266   JOIN("/a/", 4, "/a/", "b/");
267   JOIN("/a/", 4, "/a", "/b/");
268   JOIN("/a/", 4, "/", "a/b/");
269   JOIN("//a", 4, "//", "a/b/");
270 
271   JOIN("/a/b", 5, "/a", "b", "c");
272 }
273 
TEST(path_util,JoinTruncateLong)274 TEST(path_util, JoinTruncateLong)
275 {
276   JOIN("", 1, "//", "//longer", "path");
277   JOIN("/", 2, "//", "//longer", "path");
278   JOIN("//", 3, "//", "//longer", "path");
279   JOIN("//l", 4, "//", "//longer", "path");
280   /* snip */
281   JOIN("//longe", 8, "//", "//longer", "path");
282   JOIN("//longer", 9, "//", "//longer", "path");
283   JOIN("//longer/", 10, "//", "//longer", "path");
284   JOIN("//longer/p", 11, "//", "//longer", "path");
285   JOIN("//longer/pa", 12, "//", "//longer", "path");
286   JOIN("//longer/pat", 13, "//", "//longer", "path");
287   JOIN("//longer/path", 14, "//", "//longer", "path"); /* not truncated. */
288   JOIN("//longer/path", 14, "//", "//longer", "path/");
289   JOIN("//longer/path/", 15, "//", "//longer", "path/"); /* not truncated. */
290   JOIN("//longer/path/", 15, "//", "//longer", "path/", "trunc");
291   JOIN("//longer/path/t", 16, "//", "//longer", "path/", "trunc");
292 }
293 
TEST(path_util,JoinComplex)294 TEST(path_util, JoinComplex)
295 {
296   JOIN("/a/b/c/d/e/f/g/", 100, "/", "\\a/b", "//////c/d", "", "e\\\\", "f", "g//");
297   JOIN("/aa/bb/cc/dd/ee/ff/gg/", 100, "/", "\\aa/bb", "//////cc/dd", "", "ee\\\\", "ff", "gg//");
298   JOIN("1/2/3/", 100, "1", "////////", "", "2", "3\\");
299 }
300 
301 #undef JOIN
302 
303 /* BLI_path_frame */
TEST(path_util,Frame)304 TEST(path_util, Frame)
305 {
306   bool ret;
307 
308   {
309     char path[FILE_MAX] = "";
310     ret = BLI_path_frame(path, 123, 1);
311     EXPECT_TRUE(ret);
312     EXPECT_STREQ("123", path);
313   }
314 
315   {
316     char path[FILE_MAX] = "";
317     ret = BLI_path_frame(path, 123, 12);
318     EXPECT_TRUE(ret);
319     EXPECT_STREQ("000000000123", path);
320   }
321 
322   {
323     char path[FILE_MAX] = "test_";
324     ret = BLI_path_frame(path, 123, 1);
325     EXPECT_TRUE(ret);
326     EXPECT_STREQ("test_123", path);
327   }
328 
329   {
330     char path[FILE_MAX] = "test_";
331     ret = BLI_path_frame(path, 1, 12);
332     EXPECT_TRUE(ret);
333     EXPECT_STREQ("test_000000000001", path);
334   }
335 
336   {
337     char path[FILE_MAX] = "test_############";
338     ret = BLI_path_frame(path, 1, 0);
339     EXPECT_TRUE(ret);
340     EXPECT_STREQ("test_000000000001", path);
341   }
342 
343   {
344     char path[FILE_MAX] = "test_#_#_middle";
345     ret = BLI_path_frame(path, 123, 0);
346     EXPECT_TRUE(ret);
347     EXPECT_STREQ("test_#_123_middle", path);
348   }
349 
350   /* intentionally fail */
351   {
352     char path[FILE_MAX] = "";
353     ret = BLI_path_frame(path, 123, 0);
354     EXPECT_FALSE(ret);
355     EXPECT_STREQ("", path);
356   }
357 
358   {
359     char path[FILE_MAX] = "test_middle";
360     ret = BLI_path_frame(path, 123, 0);
361     EXPECT_FALSE(ret);
362     EXPECT_STREQ("test_middle", path);
363   }
364 
365   /* negative frame numbers */
366   {
367     char path[FILE_MAX] = "test_####";
368     ret = BLI_path_frame(path, -1, 4);
369     EXPECT_TRUE(ret);
370     EXPECT_STREQ("test_-0001", path);
371   }
372   {
373     char path[FILE_MAX] = "test_####";
374     ret = BLI_path_frame(path, -100, 4);
375     EXPECT_TRUE(ret);
376     EXPECT_STREQ("test_-0100", path);
377   }
378 }
379 
380 /* BLI_split_dirfile */
TEST(path_util,SplitDirfile)381 TEST(path_util, SplitDirfile)
382 {
383   {
384     const char *path = "";
385     char dir[FILE_MAX], file[FILE_MAX];
386     BLI_split_dirfile(path, dir, file, sizeof(dir), sizeof(file));
387     EXPECT_STREQ("", dir);
388     EXPECT_STREQ("", file);
389   }
390 
391   {
392     const char *path = "/";
393     char dir[FILE_MAX], file[FILE_MAX];
394     BLI_split_dirfile(path, dir, file, sizeof(dir), sizeof(file));
395     EXPECT_STREQ("/", dir);
396     EXPECT_STREQ("", file);
397   }
398 
399   {
400     const char *path = "fileonly";
401     char dir[FILE_MAX], file[FILE_MAX];
402     BLI_split_dirfile(path, dir, file, sizeof(dir), sizeof(file));
403     EXPECT_STREQ("", dir);
404     EXPECT_STREQ("fileonly", file);
405   }
406 
407   {
408     const char *path = "dironly/";
409     char dir[FILE_MAX], file[FILE_MAX];
410     BLI_split_dirfile(path, dir, file, sizeof(dir), sizeof(file));
411     EXPECT_STREQ("dironly/", dir);
412     EXPECT_STREQ("", file);
413   }
414 
415   {
416     const char *path = "/a/b";
417     char dir[FILE_MAX], file[FILE_MAX];
418     BLI_split_dirfile(path, dir, file, sizeof(dir), sizeof(file));
419     EXPECT_STREQ("/a/", dir);
420     EXPECT_STREQ("b", file);
421   }
422 
423   {
424     const char *path = "/dirtoobig/filetoobig";
425     char dir[5], file[5];
426     BLI_split_dirfile(path, dir, file, sizeof(dir), sizeof(file));
427     EXPECT_STREQ("/dir", dir);
428     EXPECT_STREQ("file", file);
429 
430     BLI_split_dirfile(path, dir, file, 1, 1);
431     EXPECT_STREQ("", dir);
432     EXPECT_STREQ("", file);
433   }
434 }
435 
436 #define PATH_FRAME_STRIP(input_path, expect_path, expect_ext) \
437   { \
438     char path[FILE_MAX]; \
439     char ext[FILE_MAX]; \
440     BLI_strncpy(path, (input_path), FILE_MAX); \
441     BLI_path_frame_strip(path, ext); \
442     EXPECT_STREQ(path, expect_path); \
443     EXPECT_STREQ(ext, expect_ext); \
444   } \
445   ((void)0)
446 
447 /* BLI_path_frame_strip */
TEST(path_util,PathFrameStrip)448 TEST(path_util, PathFrameStrip)
449 {
450   PATH_FRAME_STRIP("", "", "");
451   PATH_FRAME_STRIP("nonum.abc", "nonum", ".abc");
452   PATH_FRAME_STRIP("fileonly.001.abc", "fileonly.###", ".abc");
453   PATH_FRAME_STRIP("/abspath/to/somefile.001.abc", "/abspath/to/somefile.###", ".abc");
454   PATH_FRAME_STRIP("/ext/longer/somefile.001.alembic", "/ext/longer/somefile.###", ".alembic");
455   PATH_FRAME_STRIP("/ext/shorter/somefile.123001.abc", "/ext/shorter/somefile.######", ".abc");
456 }
457 #undef PATH_FRAME_STRIP
458 
459 #define PATH_EXTENSION_CHECK(input_path, input_ext, expect_ext) \
460   { \
461     const bool ret = BLI_path_extension_check(input_path, input_ext); \
462     if (strcmp(input_ext, expect_ext) == 0) { \
463       EXPECT_TRUE(ret); \
464     } \
465     else { \
466       EXPECT_FALSE(ret); \
467     } \
468   } \
469   ((void)0)
470 
471 /* BLI_path_extension_check */
TEST(path_util,PathExtensionCheck)472 TEST(path_util, PathExtensionCheck)
473 {
474   PATH_EXTENSION_CHECK("a/b/c.exe", ".exe", ".exe");
475   PATH_EXTENSION_CHECK("correct/path/to/file.h", ".h", ".h");
476   PATH_EXTENSION_CHECK("correct/path/to/file.BLEND", ".BLEND", ".BLEND");
477   PATH_EXTENSION_CHECK("../tricky/path/to/file.h", ".h", ".h");
478   PATH_EXTENSION_CHECK("../dirty//../path\\to/file.h", ".h", ".h");
479   PATH_EXTENSION_CHECK("a/b/c.veryveryverylonglonglongextension",
480                        ".veryveryverylonglonglongextension",
481                        ".veryveryverylonglonglongextension");
482   PATH_EXTENSION_CHECK("filename.PNG", "pnG", "pnG");
483   PATH_EXTENSION_CHECK("a/b/c.h.exe", ".exe", ".exe");
484   PATH_EXTENSION_CHECK("a/b/c.h.exe", "exe", "exe");
485   PATH_EXTENSION_CHECK("a/b/c.exe", "c.exe", "c.exe");
486   PATH_EXTENSION_CHECK("a/b/noext", "noext", "noext");
487 
488   PATH_EXTENSION_CHECK("a/b/c.exe", ".png", ".exe");
489   PATH_EXTENSION_CHECK("a/b/c.exe", "c.png", ".exe");
490   PATH_EXTENSION_CHECK("a/b/s.l", "l.s", "s.l");
491   PATH_EXTENSION_CHECK(".hiddenfolder", "", ".hiddenfolder");
492   PATH_EXTENSION_CHECK("../dirty//../path\\to/actual.h.file.ext", ".h", ".ext");
493   PATH_EXTENSION_CHECK("..\\dirty//../path//to/.hiddenfile.JPEG", ".hiddenfile", ".JPEG");
494 }
495 #undef PATH_EXTENSION_CHECK
496 
497 #define PATH_FRAME_CHECK_CHARS(input_path, expect_hasChars) \
498   { \
499     const bool ret = BLI_path_frame_check_chars(input_path); \
500     if (expect_hasChars) { \
501       EXPECT_TRUE(ret); \
502     } \
503     else { \
504       EXPECT_FALSE(ret); \
505     } \
506   } \
507   ((void)0)
508 
509 /* BLI_path_frame_check_chars */
TEST(path_util,PathFrameCheckChars)510 TEST(path_util, PathFrameCheckChars)
511 {
512   PATH_FRAME_CHECK_CHARS("a#", true);
513   PATH_FRAME_CHECK_CHARS("aaaaa#", true);
514   PATH_FRAME_CHECK_CHARS("#aaaaa", true);
515   PATH_FRAME_CHECK_CHARS("a##.###", true);
516   PATH_FRAME_CHECK_CHARS("####.abc#", true);
517   PATH_FRAME_CHECK_CHARS("path/to/chars/a#", true);
518   PATH_FRAME_CHECK_CHARS("path/to/chars/123#123.exe", true);
519 
520   PATH_FRAME_CHECK_CHARS("&", false);
521   PATH_FRAME_CHECK_CHARS("\35", false);
522   PATH_FRAME_CHECK_CHARS("path#/to#/chars#/$.h", false);
523   PATH_FRAME_CHECK_CHARS("path#/to#/chars#/nochars.h", false);
524   PATH_FRAME_CHECK_CHARS("..\\dirty\\path#/..//to#\\chars#/nochars.h", false);
525   PATH_FRAME_CHECK_CHARS("..\\dirty\\path#/..//to#/chars#\\nochars.h", false);
526 }
527 #undef PATH_FRAME_CHECK_CHARS
528 
529 #define PATH_FRAME_RANGE(input_path, sta, end, digits, expect_outpath) \
530   { \
531     char path[FILE_MAX]; \
532     bool ret; \
533     BLI_strncpy(path, input_path, FILE_MAX); \
534     ret = BLI_path_frame_range(path, sta, end, digits); \
535     if (expect_outpath == NULL) { \
536       EXPECT_FALSE(ret); \
537     } \
538     else { \
539       EXPECT_TRUE(ret); \
540       EXPECT_STREQ(path, expect_outpath); \
541     } \
542   } \
543   ((void)0)
544 
545 /* BLI_path_frame_range */
TEST(path_util,PathFrameRange)546 TEST(path_util, PathFrameRange)
547 {
548   int dummy = -1;
549   PATH_FRAME_RANGE("#", 1, 2, dummy, "1-2");
550   PATH_FRAME_RANGE("##", 1, 2, dummy, "01-02");
551   PATH_FRAME_RANGE("##", 1000, 2000, dummy, "1000-2000");
552   PATH_FRAME_RANGE("###", 100, 200, dummy, "100-200");
553   PATH_FRAME_RANGE("###", 8, 9, dummy, "008-009");
554 
555   PATH_FRAME_RANGE("", 100, 200, 1, "100-200");
556   PATH_FRAME_RANGE("", 123, 321, 4, "0123-0321");
557   PATH_FRAME_RANGE("", 1, 0, 20, "00000000000000000001-00000000000000000000");
558 }
559 #undef PATH_FRAME_RANGE
560 
561 #define PATH_FRAME_GET(input_path, expect_frame, expect_numdigits, expect_pathisvalid) \
562   { \
563     char path[FILE_MAX]; \
564     int out_frame = -1, out_numdigits = -1; \
565     BLI_strncpy(path, input_path, FILE_MAX); \
566     const bool ret = BLI_path_frame_get(path, &out_frame, &out_numdigits); \
567     if (expect_pathisvalid) { \
568       EXPECT_TRUE(ret); \
569     } \
570     else { \
571       EXPECT_FALSE(ret); \
572     } \
573     EXPECT_EQ(out_frame, expect_frame); \
574     EXPECT_EQ(out_numdigits, expect_numdigits); \
575   } \
576   ((void)0)
577 
578 /* BLI_path_frame_get */
TEST(path_util,PathFrameGet)579 TEST(path_util, PathFrameGet)
580 {
581   PATH_FRAME_GET("001.avi", 1, 3, true);
582   PATH_FRAME_GET("0000299.ext", 299, 7, true);
583   PATH_FRAME_GET("path/to/frame_2810.dummy_quite_long_extension", 2810, 4, true);
584   PATH_FRAME_GET("notframe_7_frame00018.bla", 18, 5, true);
585 
586   PATH_FRAME_GET("", -1, -1, false);
587 }
588 #undef PATH_FRAME_GET
589 
590 /* BLI_path_extension */
TEST(path_util,PathExtension)591 TEST(path_util, PathExtension)
592 {
593   EXPECT_EQ(NULL, BLI_path_extension("some.def/file"));
594   EXPECT_EQ(NULL, BLI_path_extension("Text"));
595   EXPECT_EQ(NULL, BLI_path_extension("Text…001"));
596 
597   EXPECT_STREQ(".", BLI_path_extension("some/file."));
598   EXPECT_STREQ(".gz", BLI_path_extension("some/file.tar.gz"));
599   EXPECT_STREQ(".abc", BLI_path_extension("some.def/file.abc"));
600   EXPECT_STREQ(".abc", BLI_path_extension("C:\\some.def\\file.abc"));
601   EXPECT_STREQ(".001", BLI_path_extension("Text.001"));
602 }
603 
604 /* BLI_path_rel. */
605 #ifndef _WIN32
606 
607 #  define PATH_REL(abs_path, ref_path, rel_path) \
608     { \
609       char path[FILE_MAX]; \
610       BLI_strncpy(path, abs_path, sizeof(path)); \
611       BLI_path_rel(path, ref_path); \
612       EXPECT_STREQ(rel_path, path); \
613     } \
614     void(0)
615 
TEST(path_util,PathRelPath)616 TEST(path_util, PathRelPath)
617 {
618   PATH_REL("/foo/bar/blender.blend", "/foo/bar/", "//blender.blend");
619   PATH_REL("/foo/bar/blender.blend", "/foo/bar", "//bar/blender.blend");
620 
621   /* Check for potential buffer overflows. */
622   {
623     char abs_path_in[FILE_MAX];
624     abs_path_in[0] = '/';
625     for (int i = 1; i < FILE_MAX - 1; i++) {
626       abs_path_in[i] = 'A';
627     }
628     abs_path_in[FILE_MAX - 1] = '\0';
629     char abs_path_out[FILE_MAX];
630     abs_path_out[0] = '/';
631     abs_path_out[1] = '/';
632     for (int i = 2; i < FILE_MAX - 1; i++) {
633       abs_path_out[i] = 'A';
634     }
635     abs_path_out[FILE_MAX - 1] = '\0';
636     PATH_REL(abs_path_in, "/", abs_path_out);
637 
638     const char *ref_path_in = "/foo/bar/";
639     const size_t ref_path_in_len = strlen(ref_path_in);
640     strcpy(abs_path_in, ref_path_in);
641     for (int i = ref_path_in_len; i < FILE_MAX - 1; i++) {
642       abs_path_in[i] = 'A';
643     }
644     abs_path_in[FILE_MAX - 1] = '\0';
645     abs_path_out[0] = '/';
646     abs_path_out[1] = '/';
647     for (int i = 2; i < FILE_MAX - ((int)ref_path_in_len - 1); i++) {
648       abs_path_out[i] = 'A';
649     }
650     abs_path_out[FILE_MAX - (ref_path_in_len - 1)] = '\0';
651     PATH_REL(abs_path_in, ref_path_in, abs_path_out);
652   }
653 }
654 
655 #  undef PATH_REL
656 
657 #endif
658