using NeonSprawl.Server.Game.Gathering; namespace NeonSprawl.Server.Tests.Game.Gathering; public sealed class ResourceNodeInstanceOperationsTests { private const string AlphaId = "prototype_resource_node_alpha"; private const string DeltaId = "prototype_urban_bulk_delta"; [Fact] public void TryCommitSuccessfulGatherDecrement_OnFreshNode_ShouldLazyInitAndDecrementToNine() { // Arrange using var factory = new InMemoryWebApplicationFactory(); var registry = factory.Services.GetRequiredService(); var store = factory.Services.GetRequiredService(); // Act var outcome = ResourceNodeInstanceOperations.TryCommitSuccessfulGatherDecrement(AlphaId, registry, store); // Assert Assert.Equal(ResourceNodeInstanceMutationKind.Applied, outcome.Kind); Assert.Null(outcome.ReasonCode); Assert.NotNull(outcome.Snapshot); Assert.Equal(AlphaId, outcome.Snapshot!.Value.InteractableId); Assert.Equal(9, outcome.Snapshot.Value.RemainingGathers); } [Fact] public void TryCommitSuccessfulGatherDecrement_RepeatedUntilCapacity_ShouldReturnNodeDepletedWithoutGoingNegative() { // Arrange using var factory = new InMemoryWebApplicationFactory(); var registry = factory.Services.GetRequiredService(); var store = factory.Services.GetRequiredService(); // Act — ten successful gathers (10 → 0), then one depletion attempt var appliedOutcomes = new ResourceNodeInstanceMutationOutcome[10]; for (var i = 0; i < appliedOutcomes.Length; i++) { appliedOutcomes[i] = ResourceNodeInstanceOperations.TryCommitSuccessfulGatherDecrement(AlphaId, registry, store); } var depleted = ResourceNodeInstanceOperations.TryCommitSuccessfulGatherDecrement(AlphaId, registry, store); store.TryGetRemainingGathers(AlphaId, out var persisted); // Assert Assert.All(appliedOutcomes, static o => { Assert.Equal(ResourceNodeInstanceMutationKind.Applied, o.Kind); Assert.True(o.Snapshot!.Value.RemainingGathers >= 0); }); var lastApplied = appliedOutcomes[^1]; Assert.Equal(0, lastApplied.Snapshot!.Value.RemainingGathers); Assert.Equal(ResourceNodeInstanceMutationKind.Denied, depleted.Kind); Assert.Equal(ResourceNodeInstanceReasonCodes.NodeDepleted, depleted.ReasonCode); Assert.NotNull(depleted.Snapshot); Assert.Equal(0, depleted.Snapshot!.Value.RemainingGathers); Assert.Equal(0, persisted.RemainingGathers); } [Fact] public void TryCommitSuccessfulGatherDecrement_ForUnknownNode_ShouldDenyWithoutCreatingRow() { // Arrange using var factory = new InMemoryWebApplicationFactory(); var registry = factory.Services.GetRequiredService(); var store = factory.Services.GetRequiredService(); const string unknownId = "not_a_real_node_def"; // Act var outcome = ResourceNodeInstanceOperations.TryCommitSuccessfulGatherDecrement(unknownId, registry, store); var rowExists = store.TryGetRemainingGathers(unknownId, out _); // Assert Assert.Equal(ResourceNodeInstanceMutationKind.Denied, outcome.Kind); Assert.Equal(ResourceNodeInstanceReasonCodes.UnknownNode, outcome.ReasonCode); Assert.Null(outcome.Snapshot); Assert.False(rowExists); } [Fact] public void TryCommitSuccessfulGatherDecrement_ForDeltaNode_ShouldLazyInitAtTen() { // Arrange using var factory = new InMemoryWebApplicationFactory(); var registry = factory.Services.GetRequiredService(); var store = factory.Services.GetRequiredService(); // Act var outcome = ResourceNodeInstanceOperations.TryCommitSuccessfulGatherDecrement(DeltaId, registry, store); // Assert Assert.Equal(ResourceNodeInstanceMutationKind.Applied, outcome.Kind); Assert.Equal(9, outcome.Snapshot!.Value.RemainingGathers); } }