Skip to content

Commit

Permalink
fix(mockfs): Improve Windows support and add tests
Browse files Browse the repository at this point in the history
On Windows, the root has a name, which is the drive,
unlike on POSIX where the root is an empty name.
This led to a flurry of problems because we assumed
a POSIX style, where the FS is a directed graph,
while on Windows it is multiple unconnected graphs
(the drives cannot be accessed via a relative path).
  • Loading branch information
Geod24 committed Jan 3, 2025
1 parent 626f39c commit c223b19
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 6 deletions.
64 changes: 59 additions & 5 deletions source/dub/internal/io/mockfs.d
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,29 @@ public final class MockFS : Filesystem {
///
private FSEntry root;

///
public this () scope
{
this.root = this.cwd = new FSEntry();
/***************************************************************************
Instantiate a `MockFS` with a given root
A parameter-less overload exists for POSIX, while on Windows a parameter
needs to be provided, as Windows' root has a drive letter.
Params:
root = The name of the root, e.g. "C:\"
***************************************************************************/

version (Windows) {
public this (char dir = 'C') scope
{
this.root = this.cwd = new FSEntry();
this.root.name = [ dir, ':' ];
}
} else {
public this () scope
{
this.root = this.cwd = new FSEntry();
}
}

public override NativePath getcwd () const scope
Expand Down Expand Up @@ -436,7 +455,8 @@ public class FSEntry
public NativePath path () const scope
{
if (this.parent is null)
return NativePath("/");
// The first runtime branch is for Windows, the second for POSIX
return this.name ? NativePath(this.name) : NativePath("/");
auto thisPath = this.parent.path ~ this.name;
thisPath.endsWithSlash = (this.attributes.type == Type.Directory);
return thisPath;
Expand Down Expand Up @@ -485,3 +505,37 @@ public class FSEntry
this.attributes.attrs = attributes;
}
}

unittest {
alias P = NativePath;
scope fs = new MockFS();

version (Windows) immutable NativePath root = NativePath(`C:\`);
else immutable NativePath root = NativePath(`/`);

assert(fs.getcwd == root);
// We shouldn't be able to chdir into a non-existent directory
assertThrown(fs.chdir(P("foo/bar")));
// Even with an absolute path
assertThrown(fs.chdir(root ~ "foo/bar"));
// Now we should be
fs.mkdir(P("foo/bar"));
fs.chdir(P("foo/bar"));
assert(fs.getcwd == root ~ "foo/bar/", fs.getcwd.toNativeString());
// chdir with absolute path
fs.chdir(root ~ "foo");
assert(fs.getcwd == root ~ "foo/", fs.getcwd.toNativeString());
// This still does not exists
assertThrown(fs.chdir(root ~ "bar"));
// Test pseudo entries / meta locations
version (POSIX) {
fs.chdir(P("."));
assert(fs.getcwd == P("/foo/"));
fs.chdir(P(".."));
assert(fs.getcwd == P("/"));
fs.chdir(P("."));
assert(fs.getcwd == P("/"));
fs.chdir(NativePath("/foo/bar/../"));
assert(fs.getcwd == P("/foo/"));
}
}
2 changes: 1 addition & 1 deletion source/dub/test/base.d
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ public class TestDub : Dub

/// Convenience constants for use in unittests
version (Windows)
public static immutable Root = NativePath("T:\\dub\\");
public static immutable Root = NativePath(`C:\dub\`);
else
public static immutable Root = NativePath("/dub/");

Expand Down

0 comments on commit c223b19

Please sign in to comment.