198 lines
8.9 KiB
C#
198 lines
8.9 KiB
C#
using Microsoft.Extensions.DependencyInjection;
|
|
using NeonSprawl.Server.Game.Encounters;
|
|
using Xunit;
|
|
|
|
namespace NeonSprawl.Server.Tests.Game.Encounters;
|
|
|
|
public sealed class EncounterProgressOperationsTests
|
|
{
|
|
private const string PlayerId = "dev-local-1";
|
|
private const string EncounterId = "prototype_combat_pocket";
|
|
private const string MeleeNpc = "prototype_npc_melee";
|
|
private const string RangedNpc = "prototype_npc_ranged";
|
|
private const string EliteNpc = "prototype_npc_elite";
|
|
|
|
[Fact]
|
|
public async Task TryActivateOnFirstEngagement_ShouldStartEncounter_WhenNpcIsRequired()
|
|
{
|
|
// Arrange
|
|
await using var factory = new InMemoryWebApplicationFactory();
|
|
var registry = factory.Services.GetRequiredService<IEncounterDefinitionRegistry>();
|
|
var progress = factory.Services.GetRequiredService<IEncounterProgressStore>();
|
|
var completion = factory.Services.GetRequiredService<IEncounterCompletionStore>();
|
|
// Act
|
|
var activated = EncounterProgressOperations.TryActivateOnFirstEngagement(
|
|
PlayerId,
|
|
MeleeNpc,
|
|
registry,
|
|
progress,
|
|
completion);
|
|
// Assert
|
|
Assert.True(activated);
|
|
Assert.True(progress.TryGetProgress(PlayerId, EncounterId, out var snapshot));
|
|
Assert.True(snapshot.Started);
|
|
Assert.Empty(snapshot.DefeatedNpcInstanceIds);
|
|
Assert.False(EncounterProgressOperations.IsAllRequiredTargetsDefeated(PlayerId, EncounterId, registry, progress));
|
|
}
|
|
|
|
[Fact]
|
|
public async Task TryMarkTargetDefeated_ShouldReturnFalse_WhenNotActivated()
|
|
{
|
|
// Arrange
|
|
await using var factory = new InMemoryWebApplicationFactory();
|
|
var registry = factory.Services.GetRequiredService<IEncounterDefinitionRegistry>();
|
|
var progress = factory.Services.GetRequiredService<IEncounterProgressStore>();
|
|
var completion = factory.Services.GetRequiredService<IEncounterCompletionStore>();
|
|
// Act
|
|
var marked = EncounterProgressOperations.TryMarkTargetDefeated(
|
|
PlayerId,
|
|
MeleeNpc,
|
|
registry,
|
|
progress,
|
|
completion);
|
|
// Assert
|
|
Assert.False(marked);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task IsAllRequiredTargetsDefeated_ShouldBecomeTrue_AfterThirdDefeatInAnyOrder()
|
|
{
|
|
// Arrange
|
|
await using var factory = new InMemoryWebApplicationFactory();
|
|
var registry = factory.Services.GetRequiredService<IEncounterDefinitionRegistry>();
|
|
var progress = factory.Services.GetRequiredService<IEncounterProgressStore>();
|
|
var completion = factory.Services.GetRequiredService<IEncounterCompletionStore>();
|
|
_ = EncounterProgressOperations.TryActivateOnFirstEngagement(PlayerId, EliteNpc, registry, progress, completion);
|
|
// Act
|
|
_ = EncounterProgressOperations.TryMarkTargetDefeated(PlayerId, EliteNpc, registry, progress, completion);
|
|
_ = EncounterProgressOperations.TryMarkTargetDefeated(PlayerId, MeleeNpc, registry, progress, completion);
|
|
var afterTwo = EncounterProgressOperations.IsAllRequiredTargetsDefeated(PlayerId, EncounterId, registry, progress);
|
|
_ = EncounterProgressOperations.TryMarkTargetDefeated(PlayerId, RangedNpc, registry, progress, completion);
|
|
var afterThree = EncounterProgressOperations.IsAllRequiredTargetsDefeated(PlayerId, EncounterId, registry, progress);
|
|
// Assert
|
|
Assert.False(afterTwo);
|
|
Assert.True(afterThree);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task TryMarkTargetDefeated_ShouldBeIdempotent_WhenNpcAlreadyDefeated()
|
|
{
|
|
// Arrange
|
|
await using var factory = new InMemoryWebApplicationFactory();
|
|
var registry = factory.Services.GetRequiredService<IEncounterDefinitionRegistry>();
|
|
var progress = factory.Services.GetRequiredService<IEncounterProgressStore>();
|
|
var completion = factory.Services.GetRequiredService<IEncounterCompletionStore>();
|
|
_ = EncounterProgressOperations.TryActivateOnFirstEngagement(PlayerId, MeleeNpc, registry, progress, completion);
|
|
_ = EncounterProgressOperations.TryMarkTargetDefeated(PlayerId, MeleeNpc, registry, progress, completion);
|
|
// Act
|
|
var secondMark = EncounterProgressOperations.TryMarkTargetDefeated(
|
|
PlayerId,
|
|
MeleeNpc,
|
|
registry,
|
|
progress,
|
|
completion);
|
|
// Assert
|
|
Assert.True(secondMark);
|
|
Assert.True(progress.TryGetProgress(PlayerId, EncounterId, out var snapshot));
|
|
Assert.Single(snapshot.DefeatedNpcInstanceIds);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task TryMarkTargetDefeated_ShouldReturnFalse_WhenEncounterAlreadyCompleted()
|
|
{
|
|
// Arrange
|
|
await using var factory = new InMemoryWebApplicationFactory();
|
|
var registry = factory.Services.GetRequiredService<IEncounterDefinitionRegistry>();
|
|
var progress = factory.Services.GetRequiredService<IEncounterProgressStore>();
|
|
var completion = factory.Services.GetRequiredService<IEncounterCompletionStore>();
|
|
_ = EncounterProgressOperations.TryActivateOnFirstEngagement(PlayerId, MeleeNpc, registry, progress, completion);
|
|
_ = completion.TryMarkCompleted(PlayerId, EncounterId, DateTimeOffset.UtcNow);
|
|
// Act
|
|
var marked = EncounterProgressOperations.TryMarkTargetDefeated(
|
|
PlayerId,
|
|
MeleeNpc,
|
|
registry,
|
|
progress,
|
|
completion);
|
|
// Assert
|
|
Assert.False(marked);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task TryActivateOnFirstEngagement_ShouldReturnFalse_WhenEncounterAlreadyCompleted()
|
|
{
|
|
// Arrange
|
|
await using var factory = new InMemoryWebApplicationFactory();
|
|
var registry = factory.Services.GetRequiredService<IEncounterDefinitionRegistry>();
|
|
var progress = factory.Services.GetRequiredService<IEncounterProgressStore>();
|
|
var completion = factory.Services.GetRequiredService<IEncounterCompletionStore>();
|
|
_ = completion.TryMarkCompleted(PlayerId, EncounterId, DateTimeOffset.UtcNow);
|
|
// Act
|
|
var activated = EncounterProgressOperations.TryActivateOnFirstEngagement(
|
|
PlayerId,
|
|
MeleeNpc,
|
|
registry,
|
|
progress,
|
|
completion);
|
|
// Assert
|
|
Assert.False(activated);
|
|
Assert.False(progress.TryGetProgress(PlayerId, EncounterId, out _));
|
|
}
|
|
|
|
[Fact]
|
|
public async Task TryActivateOnFirstEngagement_ShouldReturnFalse_WhenNpcNotInAnyEncounter()
|
|
{
|
|
// Arrange
|
|
await using var factory = new InMemoryWebApplicationFactory();
|
|
var registry = factory.Services.GetRequiredService<IEncounterDefinitionRegistry>();
|
|
var progress = factory.Services.GetRequiredService<IEncounterProgressStore>();
|
|
var completion = factory.Services.GetRequiredService<IEncounterCompletionStore>();
|
|
// Act
|
|
var activated = EncounterProgressOperations.TryActivateOnFirstEngagement(
|
|
PlayerId,
|
|
"prototype_npc_unknown",
|
|
registry,
|
|
progress,
|
|
completion);
|
|
// Assert
|
|
Assert.False(activated);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task IsAllRequiredTargetsDefeated_ShouldReturnTrue_WhenEncounterIdHasMixedCase()
|
|
{
|
|
// Arrange
|
|
await using var factory = new InMemoryWebApplicationFactory();
|
|
var registry = factory.Services.GetRequiredService<IEncounterDefinitionRegistry>();
|
|
var progress = factory.Services.GetRequiredService<IEncounterProgressStore>();
|
|
var completion = factory.Services.GetRequiredService<IEncounterCompletionStore>();
|
|
_ = EncounterProgressOperations.TryActivateOnFirstEngagement(PlayerId, MeleeNpc, registry, progress, completion);
|
|
_ = EncounterProgressOperations.TryMarkTargetDefeated(PlayerId, MeleeNpc, registry, progress, completion);
|
|
_ = EncounterProgressOperations.TryMarkTargetDefeated(PlayerId, RangedNpc, registry, progress, completion);
|
|
_ = EncounterProgressOperations.TryMarkTargetDefeated(PlayerId, EliteNpc, registry, progress, completion);
|
|
// Act
|
|
var allDefeated = EncounterProgressOperations.IsAllRequiredTargetsDefeated(
|
|
PlayerId,
|
|
" Prototype_Combat_Pocket ",
|
|
registry,
|
|
progress);
|
|
// Assert
|
|
Assert.True(allDefeated);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task TryMarkCompleted_ShouldReturnFalseOnSecondAttempt_WhenUsingCompletionStoreDirectly()
|
|
{
|
|
// Arrange
|
|
await using var factory = new InMemoryWebApplicationFactory();
|
|
var completion = factory.Services.GetRequiredService<IEncounterCompletionStore>();
|
|
var completedAt = new DateTimeOffset(2026, 5, 31, 12, 0, 0, TimeSpan.Zero);
|
|
// Act
|
|
var first = completion.TryMarkCompleted(PlayerId, EncounterId, completedAt);
|
|
var second = completion.TryMarkCompleted(PlayerId, EncounterId, completedAt);
|
|
// Assert
|
|
Assert.True(first);
|
|
Assert.False(second);
|
|
}
|
|
}
|