using Api.SeaHavenIndustries.Helper; using FluentAssertions; using Microsoft.Extensions.Logging; using Moq; using Xunit; namespace Api.SeaHavenIndustries.Tests; public class SanitizedErrorsTests { [Fact] public void Sanitize_ReturnsStableMessageAndNeverExposesExceptionText() { var logger = new Mock(); logger.Setup(x => x.IsEnabled(It.IsAny())).Returns(true); var message = logger.Object.Sanitize(new InvalidOperationException("SUPER-SECRET-internal-detail")); message.Should().NotContain("SUPER-SECRET"); message.Should().NotContain("internal-detail"); message.Should().StartWith("An unexpected error occurred"); message.Should().Contain("reference"); } [Fact] public void Sanitize_UsesProvidedPublicMessageInsteadOfExceptionText() { var logger = new Mock(); logger.Setup(x => x.IsEnabled(It.IsAny())).Returns(true); var message = logger.Object.Sanitize( new InvalidOperationException("SUPER-SECRET-internal-detail"), "Vendor not found"); message.Should().Contain("Vendor not found"); message.Should().NotContain("SUPER-SECRET"); message.Should().Contain("reference"); } [Fact] public void Sanitize_LogsOriginalExceptionAtErrorLevel() { var logger = new Mock(); logger.Setup(x => x.IsEnabled(It.IsAny())).Returns(true); var exception = new InvalidOperationException("SUPER-SECRET-internal-detail"); logger.Object.Sanitize(exception); logger.Verify( x => x.Log( LogLevel.Error, It.IsAny(), It.IsAny(), It.Is(ex => ex == exception), It.IsAny>()), Times.Once); } [Fact] public void Sanitize_ProducesUniqueCorrelationReferencesAcrossCalls() { var logger = new Mock(); logger.Setup(x => x.IsEnabled(It.IsAny())).Returns(true); var exception = new InvalidOperationException("detail"); var first = logger.Object.Sanitize(exception); var second = logger.Object.Sanitize(exception); first.Should().NotBe(second); } }