using Baya.Application.Contracts.Common; using Baya.Domain.Common; using Baya.Infrastructure.Persistence.Interceptors; using Microsoft.Data.Sqlite; using Microsoft.EntityFrameworkCore; using NSubstitute; namespace Baya.Test.Foundation; public class AuditFieldInterceptorTests { // A throwaway auditable entity + context so the interceptor is tested in isolation, without the // full Identity schema. private sealed class Widget : BaseEntity { public string Name { get; set; } = string.Empty; } private sealed class AuditTestDbContext(DbContextOptions options) : DbContext(options) { public DbSet Widgets => Set(); } private static AuditTestDbContext CreateContext(AuditFieldInterceptor interceptor) { var connection = new SqliteConnection("DataSource=:memory:"); connection.Open(); var options = new DbContextOptionsBuilder() .UseSqlite(connection) .AddInterceptors(interceptor) .Options; var context = new AuditTestDbContext(options); context.Database.EnsureCreated(); return context; } [Fact] public async Task SavingChanges_OnAdd_StampsCreatedAtAndCreatedById() { // Arrange var fixedNow = new DateTimeOffset(2026, 6, 28, 10, 0, 0, TimeSpan.Zero); var clock = Substitute.For(); clock.UtcNow.Returns(fixedNow); var currentUser = Substitute.For(); currentUser.UserId.Returns(42); await using var context = CreateContext(new AuditFieldInterceptor(currentUser, clock)); var widget = new Widget { Name = "test" }; context.Widgets.Add(widget); // Act await context.SaveChangesAsync(); // Assert Assert.Equal(fixedNow, widget.CreatedAt); Assert.Equal(fixedNow, widget.ModifiedAt); Assert.Equal(42, widget.CreatedById); Assert.Equal(42, widget.ModifiedById); } [Fact] public async Task SavingChanges_OnUpdate_StampsModifiedButNotCreatedBy() { // Arrange var createNow = new DateTimeOffset(2026, 6, 28, 10, 0, 0, TimeSpan.Zero); var updateNow = new DateTimeOffset(2026, 6, 28, 12, 0, 0, TimeSpan.Zero); var clock = Substitute.For(); var currentUser = Substitute.For(); clock.UtcNow.Returns(createNow); currentUser.UserId.Returns(7); await using var context = CreateContext(new AuditFieldInterceptor(currentUser, clock)); var widget = new Widget { Name = "before" }; context.Widgets.Add(widget); await context.SaveChangesAsync(); // Act — a different user edits the row later. clock.UtcNow.Returns(updateNow); currentUser.UserId.Returns(9); widget.Name = "after"; await context.SaveChangesAsync(); // Assert Assert.Equal(createNow, widget.CreatedAt); Assert.Equal(7, widget.CreatedById); Assert.Equal(updateNow, widget.ModifiedAt); Assert.Equal(9, widget.ModifiedById); } }