mpv/test/paths.c

127 lines
4.0 KiB
C
Raw Normal View History

#include "common/common.h"
#include "common/msg.h"
#include "config.h"
#include "options/path.h"
#include "test_utils.h"
static void test_join(char *file, int line, char *a, char *b, char *c)
{
char *res = mp_path_join(NULL, a, b);
if (strcmp(res, c) != 0) {
printf("%s:%d: '%s' + '%s' = '%s', expected '%s'\n", file, line,
a, b, res, c);
fflush(stdout);
abort();
}
talloc_free(res);
}
static void test_abs(char *file, int line, bool abs, char *a)
{
if (mp_path_is_absolute(bstr0(a)) != abs) {
printf("%s:%d: mp_path_is_absolute('%s') => %d, expected %d\n",
file, line, a, !abs, abs);
fflush(stdout);
abort();
}
}
static void test_normalize(char *file, int line, char *expected, char *path)
{
void *ctx = talloc_new(NULL);
char *normalized = mp_normalize_path(ctx, path);
if (strcmp(normalized, expected)) {
printf("%s:%d: mp_normalize_path('%s') => %s, expected %s\n",
file, line, path, normalized, expected);
fflush(stdout);
abort();
}
talloc_free(ctx);
}
#define TEST_JOIN(a, b, c) \
test_join(__FILE__, __LINE__, a, b, c);
#define TEST_ABS(abs, a) \
test_abs(__FILE__, __LINE__, abs, a)
#define TEST_NORMALIZE(expected, path) \
test_normalize(__FILE__, __LINE__, expected, path)
int main(void)
{
TEST_ABS(true, "/ab");
TEST_ABS(false, "ab");
TEST_JOIN("", "", "");
TEST_JOIN("a", "", "a");
TEST_JOIN("/a", "", "/a");
TEST_JOIN("", "b", "b");
TEST_JOIN("", "/b", "/b");
TEST_JOIN("ab", "cd", "ab/cd");
TEST_JOIN("ab/", "cd", "ab/cd");
TEST_JOIN("ab/", "/cd", "/cd");
// Note: we prefer "/" on win32, but tolerate "\".
#if HAVE_DOS_PATHS
TEST_ABS(true, "\\ab");
TEST_ABS(true, "c:\\");
TEST_ABS(true, "c:/");
TEST_ABS(false, "c:");
TEST_ABS(false, "c:a");
TEST_ABS(false, "c:a\\");
TEST_JOIN("ab\\", "cd", "ab\\cd");
TEST_JOIN("ab\\", "\\cd", "\\cd");
TEST_JOIN("c:/", "de", "c:/de");
TEST_JOIN("c:/a", "de", "c:/a/de");
TEST_JOIN("c:\\a", "c:\\b", "c:\\b");
TEST_JOIN("c:/a", "c:/b", "c:/b");
// Note: drive-relative paths are not always supported "properly"
path: change win32 semantics for joining drive-relative paths win32 is a cursed abomination which has "drive letters" at the root of the filesystem namespace for no reason. This requires special handling beyond tolerating the idiotic "\" path separator. Even more cursed is the fact that a path starting with a drive letter can be a relative path. For example, "c:billsucks" is actually a relative path to the current working directory of the C drive. So for example if the current working directory is "c:/windowsphone", then "c:billsucks" would reference "c:/windowsphone/billsucks". You should realize that win32 is a ridiculous satanic trash fire by the point you realize that win32 has at least 26 current working directories, one for each drive letter. Anyway, the actual problem is that mpv's mp_path_join() function would return a relative path if an absolute relative path is joined with a drive-relative path. This should never happen; I bet it breaks a lot of assumptions (maybe even some security or safety relevant ones, but probably not). Since relative drive paths are such a fucked up shit idea, don't try to support them "properly", and just solve the problem at hand. The solution produces a path that should be invalid on win32. Joining two relative paths still behaves the same; this is probably OK (maybe). The change isn't very minimal due to me rewriting parts of it without strict need, but I don't care. Note that the Python os.path.join() function (after which the mpv function was apparently modeled) has the same problem.
2020-02-06 13:06:53 +00:00
TEST_JOIN("c:/a", "d:b", "c:/a/d:b");
TEST_JOIN("c:a", "b", "c:a/b");
TEST_JOIN("c:", "b", "c:b");
#endif
TEST_NORMALIZE("https://foo", "https://foo");
2024-05-05 16:50:38 +00:00
#if !HAVE_DOS_PATHS
TEST_NORMALIZE("/foo", "/foo");
2024-05-05 16:50:38 +00:00
#endif
#if defined(_WIN32) && (!defined(HAVE_PATHCCH) || !HAVE_PATHCCH)
return 0;
#endif
void *ctx = talloc_new(NULL);
bstr dst = bstr0(mp_getcwd(ctx));
bstr_xappend(ctx, &dst, bstr0("/foo"));
2024-05-05 16:50:38 +00:00
#if HAVE_DOS_PATHS
char *p = dst.start;
while (*p) {
*p = *p == '/' ? '\\' : *p;
p++;
}
#endif
TEST_NORMALIZE(dst.start, "foo");
talloc_free(ctx);
2024-05-05 16:50:38 +00:00
#if HAVE_DOS_PATHS
TEST_NORMALIZE("C:\\foo\\baz", "C:/foo/bar/../baz");
TEST_NORMALIZE("C:\\", "C:/foo/../..");
TEST_NORMALIZE("C:\\foo\\baz", "C:/foo/bar/./../baz");
TEST_NORMALIZE("C:\\foo\\bar\\baz", "C:/foo//bar/./baz");
TEST_NORMALIZE("C:\\foo\\bar\\baz", "C:/foo\\./bar\\/baz");
TEST_NORMALIZE("C:\\file.mkv", "\\\\?\\C:\\folder\\..\\file.mkv");
TEST_NORMALIZE("C:\\dir", "\\\\?\\C:\\dir\\subdir\\..\\.");
TEST_NORMALIZE("D:\\newfile.txt", "\\\\?\\D:\\\\new\\subdir\\..\\..\\newfile.txt");
TEST_NORMALIZE("\\\\server\\share\\path", "\\\\?\\UNC/server/share/path/.");
TEST_NORMALIZE("C:\\", "C:/.");
TEST_NORMALIZE("C:\\", "C:/../");
#else
TEST_NORMALIZE("/foo/bar", "/foo//bar");
TEST_NORMALIZE("/foo/bar", "/foo///bar");
TEST_NORMALIZE("/foo/bar", "/foo/bar/");
TEST_NORMALIZE("/foo/bar", "/foo/./bar");
TEST_NORMALIZE("/usr", "/usr/bin/..");
#endif
return 0;
}