first commit

This commit is contained in:
Vitalii Litvinchuk
2026-06-13 23:23:50 +03:00
commit 23958e8e2c
72 changed files with 6142 additions and 0 deletions
@@ -0,0 +1,88 @@
using FluentAssertions;
using Moq;
using SequenceAuth.Lib;
using System.Threading.Tasks;
using Xunit;
namespace SequenceAuth.Lib.Tests;
public class SequenceManagerTests
{
private readonly Mock<ISequenceStore> _mockStore;
private readonly SequenceManager _manager;
public SequenceManagerTests()
{
_mockStore = new Mock<ISequenceStore>();
_manager = new SequenceManager(_mockStore.Object);
}
[Fact]
public async Task ValidateAndRotateAsync_ValidToken_ReturnsSuccessAndGeneratesNewToken()
{
// Arrange
var token = "valid-token";
var nextToken = "pre-generated-next-token";
var sequenceData = new SequenceData("user123", 100, SequenceState.Active, nextToken);
_mockStore.Setup(s => s.GetSequenceAsync(token))
.ReturnsAsync(Option<SequenceData>.Some(sequenceData));
_mockStore.Setup(s => s.SaveSequenceAsync(It.IsAny<string>(), It.IsAny<SequenceData>()))
.ReturnsAsync(StoreOutcome.Success);
// Act
var result = await _manager.ValidateAndRotateAsync(token);
// Assert
result.Outcome.Should().Be(ValidationOutcome.Success);
result.NextSequence.State.Should().Be(OptionState.Some);
result.NextSequence.Value.Should().Be(nextToken);
// Ensure the old sequence was marked as Rotated
_mockStore.Verify(s => s.SaveSequenceAsync(token, It.Is<SequenceData>(d =>
d.State == SequenceState.Rotated)), Times.Once);
// Ensure the new sequence was saved
_mockStore.Verify(s => s.SaveSequenceAsync(nextToken, It.Is<SequenceData>(d =>
d.State == SequenceState.Active)), Times.Once);
}
[Fact]
public async Task ValidateAndRotateAsync_RotatedToken_ReturnsCompromisedAndDestroysSession()
{
// Arrange
var token = "compromised-token";
var sequenceData = new SequenceData("user123", 100, SequenceState.Rotated, "some-next-token");
_mockStore.Setup(s => s.GetSequenceAsync(token))
.ReturnsAsync(Option<SequenceData>.Some(sequenceData));
// Act
var result = await _manager.ValidateAndRotateAsync(token);
// Assert
result.Outcome.Should().Be(ValidationOutcome.CompromisedSequenceDetected);
result.NextSequence.State.Should().Be(OptionState.None);
// Ensure InvalidateUserSessionsAsync was called for the user
_mockStore.Verify(s => s.InvalidateUserSessionsAsync("user123"), Times.Once);
}
[Fact]
public async Task ValidateAndRotateAsync_MissingToken_ReturnsNotFound()
{
// Arrange
var token = "invalid-token";
_mockStore.Setup(s => s.GetSequenceAsync(token))
.ReturnsAsync(Option<SequenceData>.None());
// Act
var result = await _manager.ValidateAndRotateAsync(token);
// Assert
result.Outcome.Should().Be(ValidationOutcome.SequenceNotFound);
result.NextSequence.State.Should().Be(OptionState.None);
}
}