namespace DodoSSH.Client.Session.Tests;
///
/// Where the profile goes.
///
///
/// A short suite for something that looks trivial and is not. The cache is a SQLite file written by one
/// process, and the design assumes each machine has its own — the outbox holds changes only this machine
/// has made. Two machines sharing one file through a cloud sync client corrupts it, so a roaming or
/// synced directory is a correctness problem rather than a matter of taste.
///
public sealed class ClientPathsTests
{
[Fact]
public void TheCacheLivesInsideTheProfileDirectory()
{
var paths = new ClientPaths(Path.Combine("C:", "somewhere", "DodoSSH"));
Path.GetDirectoryName(paths.CacheFile).ShouldBe(paths.DataDirectory);
Path.GetFileName(paths.CacheFile).ShouldBe("cache.db");
}
[Fact]
public void TheDefaultDirectoryIsAbsoluteAndNamed()
{
var paths = ClientPaths.Default;
Path.IsPathFullyQualified(paths.DataDirectory).ShouldBeTrue(paths.DataDirectory);
// OrdinalIgnoreCase, and the casing is the point rather than an oversight. ClientPaths spells the
// folder DodoSSH on Windows and dodossh on Unix on purpose — one follows the platform's title-cased
// convention, the other the lower-case dotfile one. The Ordinal "odoSSH" this used to look for was
// clever enough to survive either spelling of the leading D and still only ever matched Windows,
// which went unnoticed for exactly as long as nothing ran the suite anywhere else.
paths.DataDirectory.Contains("dodossh", StringComparison.OrdinalIgnoreCase)
.ShouldBeTrue($"'{paths.DataDirectory}' should be identifiable as ours");
}
[Fact]
public void ResolvingTheDefault_CreatesNothing()
{
// Read during startup diagnostics and by tests. A side effect here would mean merely asking where
// the cache would go creates a directory.
var paths = new ClientPaths(
Path.Combine(Path.GetTempPath(), $"dodossh-paths-{Guid.CreateVersion7():N}"));
Directory.Exists(paths.DataDirectory).ShouldBeFalse();
paths.EnsureCreated();
try
{
Directory.Exists(paths.DataDirectory).ShouldBeTrue();
// Idempotent, because startup runs it every launch.
paths.EnsureCreated();
}
finally
{
Directory.Delete(paths.DataDirectory, recursive: true);
}
}
[Fact]
public void OnWindowsItIsTheLocalProfileAndNotTheRoamingOne()
{
// %APPDATA% roams in a domain environment, which would sync one machine's SQLite cache to another
// and corrupt it. %LOCALAPPDATA% does not.
if (!OperatingSystem.IsWindows())
{
Assert.Skip("Windows-only path convention.");
}
var local = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
var roaming = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
ClientPaths.Default.DataDirectory.ShouldStartWith(local);
// Guard against the two happening to be equal on some configuration, which would make the
// assertion above meaningless.
if (!string.Equals(local, roaming, StringComparison.OrdinalIgnoreCase))
{
ClientPaths.Default.DataDirectory.ShouldNotStartWith(roaming);
}
}
}