yavsc/src/Yavsc.Org.Tests/Fakes/RecordingSmtpClient.cs
Paul Schneider 2dec799d71 Introduce Yavsc.Interfaces.ISmtpClient and a recording test fake
Narrow ISmtpClient to the four operations MailSender actually uses,
behind a Yavsc.Interfaces.ISmtpClientFactory. Production wires
MailKitSmtpClient (SmtpClientFactory); tests wire a recording fake
(RecordingSmtpClientFactory). The fake is pre-registered in
WebServerFixture so SMTP calls are short-circuited; the EMailling
test now asserts the Connect -> Authenticate -> Send -> Disconnect
sequence. Yavsc.Abstract stays free of MailKit/MimeKit.
2026-06-22 02:09:02 +01:00

71 lines
2.3 KiB
C#

using MailKit.Security;
using MimeKit;
using Yavsc.Interfaces;
namespace Yavsc.Org.Tests.Fakes
{
/// <summary>
/// In-memory test double for <see cref="ISmtpClient"/>. Records
/// every call for assertion and short-circuits the SMTP
/// roundtrip.
/// </summary>
public sealed class RecordingSmtpClient : ISmtpClient
{
public List<RecordingSmtpCall> Calls { get; } = new();
public int Timeout { get; set; }
public string? LastConnectedHost { get; private set; }
public int LastConnectedPort { get; private set; }
public SecureSocketOptions LastConnectedOptions { get; private set; }
public string? LastAuthenticatedUser { get; private set; }
public MimeMessage? LastSentMessage { get; private set; }
public bool WasDisconnected { get; private set; }
public bool Disposed { get; private set; }
public void Connect(string host, int port, SecureSocketOptions options)
{
LastConnectedHost = host;
LastConnectedPort = port;
LastConnectedOptions = options;
Calls.Add(new RecordingSmtpCall(RecordingSmtpCallKind.Connect, host, port, options));
}
public void Authenticate(string userName, string password)
{
LastAuthenticatedUser = userName;
Calls.Add(new RecordingSmtpCall(RecordingSmtpCallKind.Authenticate, userName, null, null));
}
public Task SendAsync(MimeMessage message, CancellationToken cancellationToken = default)
{
LastSentMessage = message;
Calls.Add(new RecordingSmtpCall(RecordingSmtpCallKind.Send, message.Subject, null, null));
return Task.CompletedTask;
}
public void Disconnect(bool quit)
{
WasDisconnected = quit;
Calls.Add(new RecordingSmtpCall(RecordingSmtpCallKind.Disconnect, null, null, null));
}
public void Dispose()
{
Disposed = true;
}
}
public enum RecordingSmtpCallKind
{
Connect,
Authenticate,
Send,
Disconnect,
}
public readonly record struct RecordingSmtpCall(
RecordingSmtpCallKind Kind,
string? HostOrSubjectOrUser,
int? Port,
SecureSocketOptions? Options);
}