mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 14:23:09 +00:00
std/fs/test.zig: Factor out the symlink-creation wrappers
Because creation of a symlink can fail on Windows with an Access Denied error (https://learn.microsoft.com/en-us/windows/security/threat-protection/security-policy-settings/create-symbolic-links) any tests that need a symbolic link "skip" if they run into this problem. This change factors out a "setupSymbolicLink()" routine to make this clearer, a bit tighter, and easier to use in future tests. I also collapsed the "symlink in parent directory" test into the existing "Dir.readlink" test, because the latter uses the more comprehensive testWithAllSupportedPathTypes wrapper.
This commit is contained in:
parent
95a0e127b3
commit
c36962bb19
@ -10,6 +10,7 @@ const ArenaAllocator = std.heap.ArenaAllocator;
|
|||||||
const Dir = std.fs.Dir;
|
const Dir = std.fs.Dir;
|
||||||
const File = std.fs.File;
|
const File = std.fs.File;
|
||||||
const tmpDir = testing.tmpDir;
|
const tmpDir = testing.tmpDir;
|
||||||
|
const SymLinkFlags = std.fs.Dir.SymLinkFlags;
|
||||||
|
|
||||||
const PathType = enum {
|
const PathType = enum {
|
||||||
relative,
|
relative,
|
||||||
@ -119,6 +120,25 @@ fn testWithAllSupportedPathTypes(test_func: anytype) !void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// For use in test setup. If the symlink creation fails on Windows with
|
||||||
|
// AccessDenied, then make the test failure silent (it is not a Zig failure).
|
||||||
|
fn setupSymlink(dir: Dir, target: []const u8, link: []const u8, flags: SymLinkFlags) !void {
|
||||||
|
return dir.symLink(target, link, flags) catch |err| switch (err) {
|
||||||
|
// Symlink requires admin privileges on windows, so this test can legitimately fail.
|
||||||
|
error.AccessDenied => if (builtin.os.tag == .windows) return error.SkipZigTest else return err,
|
||||||
|
else => return err,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// For use in test setup. If the symlink creation fails on Windows with
|
||||||
|
// AccessDenied, then make the test failure silent (it is not a Zig failure).
|
||||||
|
fn setupSymlinkAbsolute(target: []const u8, link: []const u8, flags: SymLinkFlags) !void {
|
||||||
|
return fs.symLinkAbsolute(target, link, flags) catch |err| switch (err) {
|
||||||
|
error.AccessDenied => if (builtin.os.tag == .windows) return error.SkipZigTest else return err,
|
||||||
|
else => return err,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
test "Dir.readLink" {
|
test "Dir.readLink" {
|
||||||
try testWithAllSupportedPathTypes(struct {
|
try testWithAllSupportedPathTypes(struct {
|
||||||
fn impl(ctx: *TestContext) !void {
|
fn impl(ctx: *TestContext) !void {
|
||||||
@ -128,31 +148,33 @@ test "Dir.readLink" {
|
|||||||
const dir_target_path = try ctx.transformPath("subdir");
|
const dir_target_path = try ctx.transformPath("subdir");
|
||||||
try ctx.dir.makeDir(dir_target_path);
|
try ctx.dir.makeDir(dir_target_path);
|
||||||
|
|
||||||
{
|
// test 1: symlink to a file
|
||||||
// Create symbolic link by path
|
try setupSymlink(ctx.dir, file_target_path, "symlink1", .{});
|
||||||
ctx.dir.symLink(file_target_path, "symlink1", .{}) catch |err| switch (err) {
|
try testReadLink(ctx.dir, file_target_path, "symlink1");
|
||||||
// Symlink requires admin privileges on windows, so this test can legitimately fail.
|
|
||||||
error.AccessDenied => return error.SkipZigTest,
|
// test 2: symlink to a directory (can be different on Windows)
|
||||||
else => return err,
|
try setupSymlink(ctx.dir, dir_target_path, "symlink2", .{ .is_directory = true });
|
||||||
};
|
try testReadLink(ctx.dir, dir_target_path, "symlink2");
|
||||||
try testReadLink(ctx.dir, file_target_path, "symlink1");
|
|
||||||
}
|
// test 3: relative path symlink
|
||||||
{
|
const parent_file = ".." ++ fs.path.sep_str ++ "target.txt";
|
||||||
// Create symbolic link by path
|
var subdir = try ctx.dir.makeOpenPath("subdir", .{});
|
||||||
ctx.dir.symLink(dir_target_path, "symlink2", .{ .is_directory = true }) catch |err| switch (err) {
|
defer subdir.close();
|
||||||
// Symlink requires admin privileges on windows, so this test can legitimately fail.
|
try setupSymlink(subdir, parent_file, "relative-link.txt", .{});
|
||||||
error.AccessDenied => return error.SkipZigTest,
|
try testReadLink(subdir, parent_file, "relative-link.txt");
|
||||||
else => return err,
|
|
||||||
};
|
|
||||||
try testReadLink(ctx.dir, dir_target_path, "symlink2");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}.impl);
|
}.impl);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn testReadLink(dir: Dir, target_path: []const u8, symlink_path: []const u8) !void {
|
fn testReadLink(dir: Dir, target_path: []const u8, symlink_path: []const u8) !void {
|
||||||
var buffer: [fs.MAX_PATH_BYTES]u8 = undefined;
|
var buffer: [fs.MAX_PATH_BYTES]u8 = undefined;
|
||||||
const given = try dir.readLink(symlink_path, buffer[0..]);
|
const actual = try dir.readLink(symlink_path, buffer[0..]);
|
||||||
|
try testing.expectEqualStrings(target_path, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn testReadLinkAbsolute(target_path: []const u8, symlink_path: []const u8) !void {
|
||||||
|
var buffer: [fs.MAX_PATH_BYTES]u8 = undefined;
|
||||||
|
const given = try fs.readLinkAbsolute(symlink_path, buffer[0..]);
|
||||||
try testing.expectEqualStrings(target_path, given);
|
try testing.expectEqualStrings(target_path, given);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -169,11 +191,7 @@ test "File.stat on a File that is a symlink returns Kind.sym_link" {
|
|||||||
const dir_target_path = try ctx.transformPath("subdir");
|
const dir_target_path = try ctx.transformPath("subdir");
|
||||||
try ctx.dir.makeDir(dir_target_path);
|
try ctx.dir.makeDir(dir_target_path);
|
||||||
|
|
||||||
ctx.dir.symLink(dir_target_path, "symlink", .{ .is_directory = true }) catch |err| switch (err) {
|
try setupSymlink(ctx.dir, dir_target_path, "symlink", .{ .is_directory = true });
|
||||||
// Symlink requires admin privileges on windows, so this test can legitimately fail.
|
|
||||||
error.AccessDenied => return error.SkipZigTest,
|
|
||||||
else => return err,
|
|
||||||
};
|
|
||||||
|
|
||||||
var symlink = switch (builtin.target.os.tag) {
|
var symlink = switch (builtin.target.os.tag) {
|
||||||
.windows => windows_symlink: {
|
.windows => windows_symlink: {
|
||||||
@ -238,23 +256,6 @@ test "File.stat on a File that is a symlink returns Kind.sym_link" {
|
|||||||
}.impl);
|
}.impl);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "relative symlink to parent directory" {
|
|
||||||
var tmp = tmpDir(.{});
|
|
||||||
defer tmp.cleanup();
|
|
||||||
|
|
||||||
var subdir = try tmp.dir.makeOpenPath("subdir", .{});
|
|
||||||
defer subdir.close();
|
|
||||||
|
|
||||||
const expected_link_name = ".." ++ std.fs.path.sep_str ++ "b.txt";
|
|
||||||
|
|
||||||
try subdir.symLink(expected_link_name, "a.txt", .{});
|
|
||||||
|
|
||||||
var buf: [1000]u8 = undefined;
|
|
||||||
const link_name = try subdir.readLink("a.txt", &buf);
|
|
||||||
|
|
||||||
try testing.expectEqualStrings(expected_link_name, link_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
test "openDir" {
|
test "openDir" {
|
||||||
try testWithAllSupportedPathTypes(struct {
|
try testWithAllSupportedPathTypes(struct {
|
||||||
fn impl(ctx: *TestContext) !void {
|
fn impl(ctx: *TestContext) !void {
|
||||||
@ -373,33 +374,19 @@ test "readLinkAbsolute" {
|
|||||||
const symlink_path = try fs.path.join(allocator, &.{ base_path, "symlink1" });
|
const symlink_path = try fs.path.join(allocator, &.{ base_path, "symlink1" });
|
||||||
|
|
||||||
// Create symbolic link by path
|
// Create symbolic link by path
|
||||||
fs.symLinkAbsolute(target_path, symlink_path, .{}) catch |err| switch (err) {
|
try setupSymlinkAbsolute(target_path, symlink_path, .{});
|
||||||
// Symlink requires admin privileges on windows, so this test can legitimately fail.
|
|
||||||
error.AccessDenied => return error.SkipZigTest,
|
|
||||||
else => return err,
|
|
||||||
};
|
|
||||||
try testReadLinkAbsolute(target_path, symlink_path);
|
try testReadLinkAbsolute(target_path, symlink_path);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
const target_path = try fs.path.join(allocator, &.{ base_path, "subdir" });
|
const target_path = try fs.path.join(allocator, &.{ base_path, "subdir" });
|
||||||
const symlink_path = try fs.path.join(allocator, &.{ base_path, "symlink2" });
|
const symlink_path = try fs.path.join(allocator, &.{ base_path, "symlink2" });
|
||||||
|
|
||||||
// Create symbolic link by path
|
// Create symbolic link to a directory by path
|
||||||
fs.symLinkAbsolute(target_path, symlink_path, .{ .is_directory = true }) catch |err| switch (err) {
|
try setupSymlinkAbsolute(target_path, symlink_path, .{ .is_directory = true });
|
||||||
// Symlink requires admin privileges on windows, so this test can legitimately fail.
|
|
||||||
error.AccessDenied => return error.SkipZigTest,
|
|
||||||
else => return err,
|
|
||||||
};
|
|
||||||
try testReadLinkAbsolute(target_path, symlink_path);
|
try testReadLinkAbsolute(target_path, symlink_path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn testReadLinkAbsolute(target_path: []const u8, symlink_path: []const u8) !void {
|
|
||||||
var buffer: [fs.MAX_PATH_BYTES]u8 = undefined;
|
|
||||||
const given = try fs.readLinkAbsolute(symlink_path, buffer[0..]);
|
|
||||||
try testing.expectEqualStrings(target_path, given);
|
|
||||||
}
|
|
||||||
|
|
||||||
test "Dir.Iterator" {
|
test "Dir.Iterator" {
|
||||||
var tmp_dir = tmpDir(.{ .iterate = true });
|
var tmp_dir = tmpDir(.{ .iterate = true });
|
||||||
defer tmp_dir.cleanup();
|
defer tmp_dir.cleanup();
|
||||||
@ -1005,11 +992,7 @@ test "deleteTree does not follow symlinks" {
|
|||||||
var a = try tmp.dir.makeOpenPath("a", .{});
|
var a = try tmp.dir.makeOpenPath("a", .{});
|
||||||
defer a.close();
|
defer a.close();
|
||||||
|
|
||||||
a.symLink("../b", "b", .{ .is_directory = true }) catch |err| switch (err) {
|
try setupSymlink(a, "../b", "b", .{ .is_directory = true });
|
||||||
// Symlink requires admin privileges on windows, so this test can legitimately fail.
|
|
||||||
error.AccessDenied => return error.SkipZigTest,
|
|
||||||
else => return err,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try tmp.dir.deleteTree("a");
|
try tmp.dir.deleteTree("a");
|
||||||
@ -1024,11 +1007,7 @@ test "deleteTree on a symlink" {
|
|||||||
|
|
||||||
// Symlink to a file
|
// Symlink to a file
|
||||||
try tmp.dir.writeFile("file", "");
|
try tmp.dir.writeFile("file", "");
|
||||||
tmp.dir.symLink("file", "filelink", .{}) catch |err| switch (err) {
|
try setupSymlink(tmp.dir, "file", "filelink", .{});
|
||||||
// Symlink requires admin privileges on windows, so this test can legitimately fail.
|
|
||||||
error.AccessDenied => return error.SkipZigTest,
|
|
||||||
else => return err,
|
|
||||||
};
|
|
||||||
|
|
||||||
try tmp.dir.deleteTree("filelink");
|
try tmp.dir.deleteTree("filelink");
|
||||||
try testing.expectError(error.FileNotFound, tmp.dir.access("filelink", .{}));
|
try testing.expectError(error.FileNotFound, tmp.dir.access("filelink", .{}));
|
||||||
@ -1036,11 +1015,7 @@ test "deleteTree on a symlink" {
|
|||||||
|
|
||||||
// Symlink to a directory
|
// Symlink to a directory
|
||||||
try tmp.dir.makePath("dir");
|
try tmp.dir.makePath("dir");
|
||||||
tmp.dir.symLink("dir", "dirlink", .{ .is_directory = true }) catch |err| switch (err) {
|
try setupSymlink(tmp.dir, "dir", "dirlink", .{ .is_directory = true });
|
||||||
// Symlink requires admin privileges on windows, so this test can legitimately fail.
|
|
||||||
error.AccessDenied => return error.SkipZigTest,
|
|
||||||
else => return err,
|
|
||||||
};
|
|
||||||
|
|
||||||
try tmp.dir.deleteTree("dirlink");
|
try tmp.dir.deleteTree("dirlink");
|
||||||
try testing.expectError(error.FileNotFound, tmp.dir.access("dirlink", .{}));
|
try testing.expectError(error.FileNotFound, tmp.dir.access("dirlink", .{}));
|
||||||
@ -1123,7 +1098,7 @@ test "makepath through existing valid symlink" {
|
|||||||
defer tmp.cleanup();
|
defer tmp.cleanup();
|
||||||
|
|
||||||
try tmp.dir.makeDir("realfolder");
|
try tmp.dir.makeDir("realfolder");
|
||||||
try tmp.dir.symLink("." ++ fs.path.sep_str ++ "realfolder", "working-symlink", .{});
|
try setupSymlink(tmp.dir, "." ++ fs.path.sep_str ++ "realfolder", "working-symlink", .{});
|
||||||
|
|
||||||
try tmp.dir.makePath("working-symlink" ++ fs.path.sep_str ++ "in-realfolder");
|
try tmp.dir.makePath("working-symlink" ++ fs.path.sep_str ++ "in-realfolder");
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user