Files
StarterNG/StarterNG.Tests/FileDiagnosticsLogTests.cs
maj00r 07987a60a9 Write settings, presets and favourites whole or not at all
A failed write leaves the old file in place. Settings that could not be read
are not saved over. UI exceptions reach the log. Started from a shortcut set
up elsewhere, the starter moves to its own folder when only that one holds a
game.
2026-11-01 16:06:15 +01:00

170 lines
5.3 KiB
C#

using StarterNG.Infrastructure.Adapters;
using StarterNG.Tests.Fakes;
namespace StarterNG.Tests;
public class FileDiagnosticsLogTests
{
private static FileDiagnosticsLog Build(out InMemoryFileSystem files)
{
files = new InMemoryFileSystem();
return new FileDiagnosticsLog(files, new FixedClock(new DateTime(2026, 3, 7, 14, 5, 0)),
new GamePaths("game"));
}
[Fact]
public void Log_timestamps_each_line_from_the_clock()
{
var log = Build(out _);
log.Log("scenery loaded");
Assert.Equal("2026-03-07 14:05:00 scenery loaded", log.Text);
}
[Fact]
public void Exceptions_are_logged_with_their_context_and_type()
{
var log = Build(out _);
log.Log("scenery/foo.scn", new InvalidOperationException("bad node"));
Assert.Contains("scenery/foo.scn: InvalidOperationException: bad node", log.Text);
}
[Fact]
public void Clear_drops_everything_logged_so_far()
{
var log = Build(out _);
log.Log("first");
log.Clear();
Assert.Equal(string.Empty, log.Text);
}
private static string Written(string path)
{
// The writer holds it open for as long as the session lasts.
using var stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
using var reader = new StreamReader(stream);
return reader.ReadToEnd();
}
[Fact]
public void The_first_entry_of_a_session_keeps_the_log_of_the_one_before()
{
string root = Directory.CreateTempSubdirectory("starterng-log-").FullName;
try
{
var paths = new GamePaths(root);
Directory.CreateDirectory(paths.StarterConfig);
File.WriteAllText(paths.DiagnosticsLog, "the crash\n");
var log = new FileDiagnosticsLog(new PhysicalFileSystem(), new FixedClock(new DateTime(2026, 3, 7)), paths);
log.Log("after the restart");
log.Log("and on");
Assert.Equal("the crash\n", Written(paths.DiagnosticsLog + ".1"));
string now = Written(paths.DiagnosticsLog);
Assert.DoesNotContain("the crash", now);
Assert.Contains("after the restart", now);
Assert.Contains("and on", now);
log.Clear();
}
finally
{
Directory.Delete(root, recursive: true);
}
}
[Fact]
public void Only_the_session_before_is_kept()
{
string root = Directory.CreateTempSubdirectory("starterng-log-").FullName;
try
{
var paths = new GamePaths(root);
Directory.CreateDirectory(paths.StarterConfig);
File.WriteAllText(paths.DiagnosticsLog, "the last one\n");
File.WriteAllText(paths.DiagnosticsLog + ".1", "the one before it\n");
var log = new FileDiagnosticsLog(new PhysicalFileSystem(), new FixedClock(new DateTime(2026, 3, 7)), paths);
log.Log("now");
Assert.Equal("the last one\n", Written(paths.DiagnosticsLog + ".1"));
log.Clear();
}
finally
{
Directory.Delete(root, recursive: true);
}
}
[Fact]
public void Clearing_the_log_does_not_touch_the_session_kept()
{
var log = Build(out var files);
string path = new GamePaths("game").DiagnosticsLog;
files.WithFile(path, "the crash\n");
log.Log("after the restart");
log.Clear();
log.Log("cleared");
Assert.Equal("the crash\n", files.ReadAllText(path + ".1"));
}
[Fact]
public void A_log_that_cannot_be_copied_is_added_to_and_not_wiped()
{
string root = Directory.CreateTempSubdirectory("starterng-log-").FullName;
try
{
var paths = new GamePaths(root);
Directory.CreateDirectory(paths.StarterConfig);
File.WriteAllText(paths.DiagnosticsLog, "the crash\n");
// A folder where the copy would go: nothing can be written in its place.
Directory.CreateDirectory(paths.DiagnosticsLog + ".1");
var log = new FileDiagnosticsLog(new PhysicalFileSystem(), new FixedClock(new DateTime(2026, 3, 7)), paths);
log.Log("after the restart");
string now = Written(paths.DiagnosticsLog);
Assert.Contains("the crash", now);
Assert.Contains("after the restart", now);
log.Clear();
}
finally
{
Directory.Delete(root, recursive: true);
}
}
[Fact]
public void A_folder_it_cannot_write_in_does_not_stop_the_program()
{
string root = Directory.CreateTempSubdirectory("starterng-log-").FullName;
try
{
var paths = new GamePaths(root);
// A file where the log's folder should be, as unwritable as read-only gets
// on every platform and for every user.
File.WriteAllText(paths.StarterConfig, "");
var log = new FileDiagnosticsLog(new PhysicalFileSystem(), new FixedClock(new DateTime(2026, 3, 7)), paths);
log.Log("first");
log.Log("second");
log.Flush();
log.Clear();
log.Log("third");
Assert.Contains("third", log.Text);
}
finally
{
Directory.Delete(root, recursive: true);
}
}
}