namespace DodoSSH.Client.Transfer.Tests;
///
/// LocalDirectory.ChildPath: where a name another machine chose may land on this one.
///
///
/// The assertion that matters is the same in every row — the result's parent is the directory asked about,
/// or there is no result — because that is the property a download relies on, and it is checked against the
/// resolved path rather than the string so that what the file system does to a name counts too.
///
public sealed class LocalDirectoryTests
{
private static readonly string Directory = Path.Combine(Path.GetTempPath(), "dodossh-child-path");
[Theory]
[InlineData("notes.txt")]
[InlineData("backup:2026-10-02")]
[InlineData(@"..\..\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\x.bat")]
[InlineData(@"C:\Windows\evil.dll")]
[InlineData("../../escaped.txt")]
[InlineData("/etc/passwd")]
[InlineData("...")]
[InlineData(".hidden")]
public void ANameThatCanBeAFileHere_LandsDirectlyInsideTheDirectory(string name)
{
var child = LocalDirectory.ChildPath(Directory, name);
if (child is null)
{
// Only acceptable for "...", which Windows reduces to nothing; everywhere else it is a name.
OperatingSystem.IsWindows().ShouldBeTrue($"'{name}' was refused");
name.ShouldBe("...");
return;
}
Path.GetDirectoryName(child).ShouldBe(Path.GetFullPath(Directory));
}
[Theory]
[InlineData("")]
[InlineData(" ")]
[InlineData(".")]
[InlineData("..")]
public void ANameThatIsOnlyHereOrAbove_IsRefused(string name) =>
LocalDirectory.ChildPath(Directory, name).ShouldBeNull();
///
/// Windows drops a trailing dot or space from a path component, so .. is .. by the time
/// it reaches the disk — which a check of the string alone would have let through.
///
[Fact]
public void ATrailingSpaceOrDot_DoesNotSmuggleAParentReferencePastTheCheck()
{
foreach (var name in new[] { ".. ", "...", ".. .", ". " })
{
var child = LocalDirectory.ChildPath(Directory, name);
if (child is not null)
{
Path.GetDirectoryName(child).ShouldBe(Path.GetFullPath(Directory), name);
}
}
}
[Fact]
public void AnOrdinaryName_IsKeptAsItIs() =>
Path.GetFileName(LocalDirectory.ChildPath(Directory, "nginx.conf")).ShouldBe("nginx.conf");
}