using FluentAssertions; namespace StellaOps.Audit.ReplayToken.Tests; public sealed partial class ReplayTokenSecurityTests { [Fact] public void TokenWithExpiration_CanonicalFormat_IncludesExpiryTimestamp() { var fixedTime = new DateTimeOffset(2025, 6, 15, 12, 0, 0, TimeSpan.Zero); var expiresAt = fixedTime.AddHours(1); var token = new ReplayToken("abc123", fixedTime, expiresAt, ReplayToken.DefaultAlgorithm, ReplayToken.VersionWithExpiration); var canonical = token.Canonical; canonical.Should().Contain(expiresAt.ToUnixTimeSeconds().ToString()); canonical.Split(':').Should().HaveCount(5, "v2.0 format should have 5 parts including expiry"); } [Fact] public void ParseToken_WithExpiration_RoundTrip_PreservesExpiration() { var fixedTime = new DateTimeOffset(2025, 6, 15, 12, 0, 0, TimeSpan.Zero); var generator = CreateGenerator(fixedTime); var request = CreateRequest(); var originalToken = generator.GenerateWithExpiration(request, TimeSpan.FromHours(2)); var parsed = ReplayToken.Parse(originalToken.Canonical); parsed.Value.Should().Be(originalToken.Value); parsed.Version.Should().Be(ReplayToken.VersionWithExpiration); parsed.ExpiresAt.Should().Be(originalToken.ExpiresAt); } }