aboutsummaryrefslogtreecommitdiffstats
path: root/tests/path_test.c
blob: 1f1442315e47ff25dae5273f26bdfe6ff2b8c1a6 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
/* Paths, as the two platforms spell them.
 *
 * Windows takes `/` and `\` and mixes them without being asked, and calls a
 * path absolute when it starts with a drive. POSIX does neither: `\` is an
 * ordinary character in a file name there, and `C:` an ordinary directory.
 * So half of what follows asserts that the Windows rules are *not* applied on
 * POSIX -- which is the half that would otherwise rot, because the platform
 * where these functions are interesting is not the platform the suite runs on.
 */
#include "slosh.h"

#include <stdio.h>
#include <string.h>

static int fails = 0;

static void ok(const char *name, bool cond, const char *detail) {
  if (!cond) fails++;
  printf("%s %-52s %s\n", cond ? "ok  " : "FAIL", name, cond ? "" : detail);
}

static void eq(const char *name, const char *got, const char *want) {
  bool same = got && want && strcmp(got, want) == 0;
  char detail[512];
  snprintf(detail, sizeof detail, "got %s, wanted %s", got ? got : "(null)",
           want);
  ok(name, same, detail);
}

int main(void) {
  char buf[512];

  /* ---- absoluteness ----------------------------------------------------- */
  ok("a leading slash is absolute", path_is_absolute("/etc/slosh.kdl"), "");
  ok("a bare name is not", !path_is_absolute("themes/t.kdl"), "");
  ok("a dotted name is not", !path_is_absolute("./themes/t.kdl"), "");
  ok("an empty path is not", !path_is_absolute(""), "");
  ok("NULL is not", !path_is_absolute(NULL), "");

#ifdef _WIN32
  ok("a drive with a slash is absolute", path_is_absolute("C:/themes"), "");
  ok("a drive with a backslash is absolute", path_is_absolute("C:\\themes"),
     "");
  ok("a lowercase drive counts", path_is_absolute("d:/x"), "");
  ok("a drive-relative root is absolute", path_is_absolute("\\themes"), "");
  ok("a UNC share is absolute", path_is_absolute("\\\\host\\share\\t.kdl"), "");
  /* `C:t.kdl` is relative to the current directory *of drive C*, which is a
   * real thing and not one we can resolve for anybody. */
  ok("a drive without a separator is not", !path_is_absolute("C:t.kdl"), "");
#else
  /* The whole reason the drive rules are #ifdef'd: these are ordinary
   * relative paths here, and reading them as absolute would break the
   * platform that works in order to fix the one that did not. */
  ok("a drive letter is just a name on POSIX", !path_is_absolute("C:/themes"),
     "");
  ok("a backslash is just a character on POSIX", !path_is_absolute("\\themes"),
     "");
#endif

  /* ---- splitting -------------------------------------------------------- */
  eq("the directory of a nested path", path_dir("/a/b/c.kdl", buf, sizeof buf),
     "/a/b");
  eq("the name of a nested path", path_base("/a/b/c.kdl"), "c.kdl");
  eq("a bare name is in the current directory",
     path_dir("c.kdl", buf, sizeof buf), ".");
  eq("and is its own name", path_base("c.kdl"), "c.kdl");
  eq("a path at the root", path_dir("/c.kdl", buf, sizeof buf), "/");
  eq("its name", path_base("/c.kdl"), "c.kdl");

#ifdef _WIN32
  eq("a backslash separates",
     path_dir("C:\\Users\\you\\config.kdl", buf, sizeof buf), "C:\\Users\\you");
  eq("and names", path_base("C:\\Users\\you\\config.kdl"), "config.kdl");
  /* The mixture is not hypothetical: slosh joins with '/' and $HOME arrives
   * with '\', so the default config path is spelled both ways at once. */
  eq("the last separator wins in a mixed path",
     path_dir("C:\\Users\\you/.config/slosh/config.kdl", buf, sizeof buf),
     "C:\\Users\\you/.config/slosh");
  eq("and the other order",
     path_dir("C:/Users/you\\config.kdl", buf, sizeof buf), "C:/Users/you");
  /* `C:` alone is the current directory on drive C, which is somewhere else. */
  eq("a file at a drive root keeps the separator",
     path_dir("C:\\config.kdl", buf, sizeof buf), "C:\\");
  eq("forward-slash spelling too", path_dir("C:/config.kdl", buf, sizeof buf),
     "C:/");
#else
  /* A POSIX file may legitimately be called `a\b`; splitting there would
   * invent a directory that does not exist. */
  eq("a backslash does not split on POSIX", path_dir("a\\b", buf, sizeof buf),
     ".");
  eq("nor name", path_base("a\\b"), "a\\b");
  eq("a colon is not a drive on POSIX", path_dir("a:/b", buf, sizeof buf),
     "a:");
#endif

  /* ---- resolving against a base ----------------------------------------- */
  eq("a relative path joins the base",
     path_resolve("themes/t.kdl", "/cfg", buf, sizeof buf),
     "/cfg/themes/t.kdl");
  eq("an absolute path ignores the base",
     path_resolve("/etc/t.kdl", "/cfg", buf, sizeof buf), "/etc/t.kdl");
  eq("no base leaves it alone",
     path_resolve("themes/t.kdl", NULL, buf, sizeof buf), "themes/t.kdl");
  eq("`.` is the base itself", path_resolve(".", "/cfg", buf, sizeof buf),
     "/cfg");
#ifdef _WIN32
  /* The bug this was written for: joined instead of taken as it stood, and
   * opened as C:/cfg/C:/themes/t.kdl. */
  eq("a drive path ignores the base",
     path_resolve("C:/themes/t.kdl", "C:/cfg", buf, sizeof buf),
     "C:/themes/t.kdl");
#endif

  if (fails) printf("\n%d failed\n", fails);
  return fails ? 1 : 0;
}