using GitConverter.Lib.Models;
namespace GitConverter.TestsApp.Models
{
///
/// Unit tests for .
///
///
/// - Verifies factory helpers, timestamp behavior and logical equality semantics (IEquatable).
/// - Equality is defined by Status + Message only; TimestampUtc is diagnostic metadata and excluded.
/// - Timestamp assertions use a small tolerant window to avoid flakes on slow CI agents.
///
public class ConversionResultTests
{
[Fact(DisplayName = "Success factory creates success result")]
public void Success_CreatesSuccessResult()
{
var msg = "Converted successfully";
var result = ConversionResult.Success(msg);
Assert.True(result.IsSuccess);
Assert.Equal(ConversionStatus.Success, result.Status);
Assert.Equal(msg, result.Message);
Assert.Equal(DateTimeKind.Utc, result.TimestampUtc.Kind);
}
[Fact(DisplayName = "Failure factory creates failure result")]
public void Failure_CreatesFailureResult()
{
var msg = "Something went wrong";
var result = ConversionResult.Failure(msg);
Assert.False(result.IsSuccess);
Assert.Equal(ConversionStatus.Failure, result.Status);
Assert.Equal(msg, result.Message);
Assert.Equal(DateTimeKind.Utc, result.TimestampUtc.Kind);
}
[Fact(DisplayName = "Null message is converted to empty string")]
public void NullMessage_BecomesEmptyString()
{
var r1 = ConversionResult.Success(null);
var r2 = ConversionResult.Failure(null);
Assert.NotNull(r1.Message);
Assert.Equal(string.Empty, r1.Message);
Assert.NotNull(r2.Message);
Assert.Equal(string.Empty, r2.Message);
}
[Fact(DisplayName = "TimestampUtc is recent and UTC")]
public void TimestampUtc_IsRecentAndUtc()
{
var before = DateTime.UtcNow;
var result = ConversionResult.Success("x");
var after = DateTime.UtcNow;
Assert.Equal(DateTimeKind.Utc, result.TimestampUtc.Kind);
// Allow a small tolerance window to avoid CI flakiness
Assert.True(result.TimestampUtc >= before.AddSeconds(-1), $"Timestamp {result.TimestampUtc:o} is earlier than expected (before={before:o})");
Assert.True(result.TimestampUtc <= after.AddSeconds(1), $"Timestamp {result.TimestampUtc:o} is later than expected (after={after:o})");
}
[Fact(DisplayName = "Multiple creations produce non-decreasing timestamps")]
public void MultipleCreations_TimestampsNonDecreasing()
{
var a = ConversionResult.Success("a");
Thread.Sleep(5);
var b = ConversionResult.Success("b");
Assert.True(b.TimestampUtc >= a.TimestampUtc, $"Expected second timestamp >= first timestamp ({b.TimestampUtc:o} >= {a.TimestampUtc:o})");
}
[Fact(DisplayName = "ToString returns 'Status: Message'")]
public void ToString_FormatsStatusAndMessage()
{
var success = ConversionResult.Success("ok");
var failure = ConversionResult.Failure("bad");
Assert.Equal($"{ConversionStatus.Success}: ok", success.ToString());
Assert.Equal($"{ConversionStatus.Failure}: bad", failure.ToString());
}
[Fact(DisplayName = "Equality: same status and message are equal despite different timestamps")]
public void Equality_SameStatusAndMessage_AreEqual()
{
var a = ConversionResult.Success("same");
Thread.Sleep(10);
var b = ConversionResult.Success("same");
Assert.Equal(a, b); // Equals
Assert.True(a == b); // operator ==
Assert.False(a != b);
Assert.Equal(a.GetHashCode(), b.GetHashCode());
}
[Fact(DisplayName = "Equality: different messages are not equal")]
public void Equality_DifferentMessage_NotEqual()
{
var a = ConversionResult.Success("one");
var b = ConversionResult.Success("two");
Assert.NotEqual(a, b);
Assert.False(a == b);
Assert.True(a != b);
}
[Fact(DisplayName = "Equality: different status with same message are not equal")]
public void Equality_DifferentStatus_NotEqual()
{
var a = ConversionResult.Success("m");
var b = ConversionResult.Failure("m");
Assert.NotEqual(a, b);
Assert.False(a == b);
Assert.True(a != b);
}
[Fact(DisplayName = "Equals handles null and other types safely")]
public void Equals_NullAndOtherType()
{
var a = ConversionResult.Success("x");
Assert.False(a.Equals(null));
Assert.False(a.Equals((object)"not a conversion result"));
}
}
}