using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace LibationFileManager.Tests;
///
/// Issue #2001: startup ran long before Serilog was configured, so its log calls wrote nowhere, and on a
/// broken install they threw and ended startup instead.
///
[TestClass]
[DoNotParallelize]
public class StartupLogTests
{
[TestInitialize]
public void Initialize() => StartupLog.ResetForTests();
[TestCleanup]
public void Cleanup() => StartupLog.ResetForTests();
[TestMethod]
public void Entries_recorded_before_a_sink_exists_are_kept_in_order()
{
StartupLog.Information("first");
StartupLog.Warning("second");
StartupLog.Error(new InvalidOperationException("boom"), "third");
var buffered = StartupLog.BufferedEntries;
Assert.AreEqual(3, buffered.Count);
CollectionAssert.AreEqual(new[] { "first", "second", "third" }, buffered.Select(e => e.Message).ToArray());
CollectionAssert.AreEqual(
new[] { StartupLogLevel.Information, StartupLogLevel.Warning, StartupLogLevel.Error },
buffered.Select(e => e.Level).ToArray());
Assert.AreEqual("boom", buffered[2].Exception?.Message);
}
// The point of buffering: these messages used to be dropped even on a healthy install, because
// Serilog.Log.Logger is still Serilog's silent logger until logging is configured.
[TestMethod]
public void Everything_buffered_reaches_the_sink_once_logging_exists()
{
StartupLog.Information("before");
var delivered = new List();
StartupLog.ReplayTo(delivered.Add);
StartupLog.Information("after");
CollectionAssert.AreEqual(new[] { "before", "after" }, delivered.Select(e => e.Message).ToArray());
Assert.AreEqual(0, StartupLog.BufferedEntries.Count, "a replayed entry should not also stay buffered");
}
[TestMethod]
public void A_sink_that_throws_is_contained()
{
StartupLog.ReplayTo(_ => throw new FileNotFoundException(
"Could not load file or assembly 'Serilog, Version=4.3.0.0, Culture=neutral, PublicKeyToken=24c2f752a8e58a10'."));
// The caller is mid-recovery on a broken install. Logging must not be what ends it.
StartupLog.Error("this must not throw");
StartupLog.Warning(new Exception("nor this"), "still fine");
}
[TestMethod]
public void A_sink_that_throws_while_draining_the_buffer_is_contained_too()
{
StartupLog.Information("buffered before the bad sink arrived");
StartupLog.ReplayTo(_ => throw new InvalidOperationException("sink is broken"));
}
[TestMethod]
public void The_buffer_is_bounded_so_it_cannot_grow_without_a_sink()
{
for (var i = 0; i < 5_000; i++)
StartupLog.Information($"message {i}");
Assert.IsTrue(StartupLog.BufferedEntries.Count < 5_000, "the buffer should stop growing");
Assert.IsTrue(StartupLog.BufferedEntries.Count > 0);
}
}