mirror of
https://github.com/MaSzyna-EU07/StarterNG.git
synced 2026-11-01 20:34:57 +01:00
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.
170 lines
5.3 KiB
C#
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);
|
|
}
|
|
}
|
|
}
|