using Microsoft.Extensions.Logging;
namespace ZB.MOM.WW.OtOpcUa.Driver.MTConnect.Tests;
///
/// Captures what the driver logs, so that "and it says so" can be asserted rather than assumed.
///
///
/// Used where the log line is the behaviour: a browse scope that matches nothing, and a
/// subscription the driver silently refuses to serve. Both are cases whose only other symptom is
/// an operator staring at an empty panel, so a fix that emits nothing is not a fix.
///
internal sealed class RecordingDriverLogger : ILogger
{
/// Formatted lines, in order.
public List Warnings { get; } = [];
/// Formatted lines, in order.
public List Errors { get; } = [];
/// Formatted lines, in order.
public List Infos { get; } = [];
/// Every recorded line at Information and above, with its exception's message appended.
public IReadOnlyList AllSnapshot()
{
var all = new List();
foreach (var sink in new[] { Infos, Warnings, Errors })
{
lock (sink)
{
all.AddRange(sink);
}
}
return all;
}
///
public IDisposable? BeginScope(TState state)
where TState : notnull => null;
///
public bool IsEnabled(LogLevel logLevel) => true;
///
public void Log(
LogLevel logLevel,
EventId eventId,
TState state,
Exception? exception,
Func formatter)
{
ArgumentNullException.ThrowIfNull(formatter);
var sink = logLevel switch
{
LogLevel.Warning => Warnings,
LogLevel.Error => Errors,
LogLevel.Information => Infos,
_ => null,
};
// Locked: the /sample pump logs from its own task while the test thread reads.
if (sink is null)
{
return;
}
lock (sink)
{
sink.Add(exception is null ? formatter(state, exception) : $"{formatter(state, exception)} | {exception.Message}");
}
}
/// A snapshot copy of , safe to enumerate while the pump runs.
public IReadOnlyList WarningsSnapshot()
{
lock (Warnings)
{
return [.. Warnings];
}
}
}