134 lines
5.5 KiB
C#
134 lines
5.5 KiB
C#
using Microsoft.Extensions.DependencyInjection;
|
|
using Microsoft.Extensions.Options;
|
|
using NeonSprawl.Server.Game.Factions;
|
|
using NeonSprawl.Server.Game.PositionState;
|
|
using NeonSprawl.Server.Game.Quests;
|
|
using NeonSprawl.Server.Tests;
|
|
using Xunit;
|
|
|
|
namespace NeonSprawl.Server.Tests.Game.Factions;
|
|
|
|
public sealed class FactionGateOperationsTests
|
|
{
|
|
private const string PlayerId = "dev-local-1";
|
|
private const string GridFactionId = PrototypeE7M3QuestFactionRules.GridContractGateFactionId;
|
|
private const int GridMinStanding = PrototypeE7M3QuestFactionRules.GridContractMinStanding;
|
|
|
|
[Fact]
|
|
public void TryEvaluate_ShouldPass_WhenRulesEmpty()
|
|
{
|
|
// Arrange
|
|
var standingStore = CreateStandingStore();
|
|
// Act
|
|
var outcome = FactionGateOperations.TryEvaluate(PlayerId, [], standingStore);
|
|
// Assert
|
|
Assert.True(outcome.Success);
|
|
Assert.Null(outcome.ReasonCode);
|
|
Assert.Null(outcome.FailingFactionId);
|
|
}
|
|
|
|
[Fact]
|
|
public void TryEvaluate_ShouldPass_WhenStandingAtMin()
|
|
{
|
|
// Arrange
|
|
var standingStore = CreateStandingStore();
|
|
Assert.True(standingStore.TryApplyStandingDelta(PlayerId, GridFactionId, GridMinStanding).Success);
|
|
var rules = new[] { new FactionGateRuleRow(GridFactionId, GridMinStanding) };
|
|
// Act
|
|
var outcome = FactionGateOperations.TryEvaluate(PlayerId, rules, standingStore);
|
|
// Assert
|
|
Assert.True(outcome.Success);
|
|
Assert.Null(outcome.ReasonCode);
|
|
}
|
|
|
|
[Fact]
|
|
public void TryEvaluate_ShouldDeny_WhenStandingBelowMin()
|
|
{
|
|
// Arrange
|
|
var standingStore = CreateStandingStore();
|
|
Assert.True(standingStore.TryApplyStandingDelta(PlayerId, GridFactionId, GridMinStanding - 1).Success);
|
|
var rules = new[] { new FactionGateRuleRow(GridFactionId, GridMinStanding) };
|
|
// Act
|
|
var outcome = FactionGateOperations.TryEvaluate(PlayerId, rules, standingStore);
|
|
// Assert
|
|
Assert.False(outcome.Success);
|
|
Assert.Equal(FactionGateEvaluateReasonCodes.GateBlocked, outcome.ReasonCode);
|
|
Assert.Equal(GridFactionId, outcome.FailingFactionId);
|
|
Assert.Equal(GridMinStanding, outcome.RequiredMinStanding);
|
|
Assert.Equal(GridMinStanding - 1, outcome.CurrentStanding);
|
|
}
|
|
|
|
[Fact]
|
|
public void TryEvaluate_ShouldDeny_WhenSecondRuleFailsInAndList()
|
|
{
|
|
// Arrange
|
|
var standingStore = CreateStandingStore();
|
|
const string rustFactionId = "prototype_faction_rust_collective";
|
|
Assert.True(standingStore.TryApplyStandingDelta(PlayerId, GridFactionId, GridMinStanding).Success);
|
|
var rules = new[]
|
|
{
|
|
new FactionGateRuleRow(GridFactionId, GridMinStanding),
|
|
new FactionGateRuleRow(rustFactionId, 1),
|
|
};
|
|
// Act
|
|
var outcome = FactionGateOperations.TryEvaluate(PlayerId, rules, standingStore);
|
|
// Assert
|
|
Assert.False(outcome.Success);
|
|
Assert.Equal(FactionGateEvaluateReasonCodes.GateBlocked, outcome.ReasonCode);
|
|
Assert.Equal(rustFactionId, outcome.FailingFactionId);
|
|
Assert.Equal(1, outcome.RequiredMinStanding);
|
|
Assert.Equal(0, outcome.CurrentStanding);
|
|
}
|
|
|
|
[Fact]
|
|
public void TryEvaluate_ShouldDenyUnknownFaction_WhenStoreDenies()
|
|
{
|
|
// Arrange
|
|
var standingStore = CreateStandingStore();
|
|
const string unknownFactionId = "prototype_faction_missing";
|
|
var rules = new[] { new FactionGateRuleRow(unknownFactionId, 0) };
|
|
// Act
|
|
var outcome = FactionGateOperations.TryEvaluate(PlayerId, rules, standingStore);
|
|
// Assert
|
|
Assert.False(outcome.Success);
|
|
Assert.Equal(FactionStandingReasonCodes.UnknownFaction, outcome.ReasonCode);
|
|
Assert.Equal(unknownFactionId, outcome.FailingFactionId);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Host_ShouldResolveStandingStoreForGateEval_WhenStartupSucceeds()
|
|
{
|
|
// Arrange — missing standing row reads as 0 (neutral), below grid contract minStanding 15.
|
|
await using var factory = new InMemoryWebApplicationFactory();
|
|
using var client = factory.CreateClient();
|
|
_ = await client.GetAsync("/health");
|
|
var standingStore = factory.Services.GetRequiredService<IFactionStandingStore>();
|
|
var rules = new[] { new FactionGateRuleRow(GridFactionId, GridMinStanding) };
|
|
// Act
|
|
var outcome = FactionGateOperations.TryEvaluate(PlayerId, rules, standingStore);
|
|
// Assert
|
|
Assert.False(outcome.Success);
|
|
Assert.Equal(FactionGateEvaluateReasonCodes.GateBlocked, outcome.ReasonCode);
|
|
}
|
|
|
|
private static InMemoryFactionStandingStore CreateStandingStore()
|
|
{
|
|
var registry = CreatePrototypeRegistry();
|
|
var options = Options.Create(new GamePositionOptions { DevPlayerId = PlayerId });
|
|
return new InMemoryFactionStandingStore(options, registry);
|
|
}
|
|
|
|
private static FactionDefinitionRegistry CreatePrototypeRegistry()
|
|
{
|
|
var gridFactionId = PrototypeE7M3QuestFactionRules.GridContractGateFactionId;
|
|
var rustFactionId = "prototype_faction_rust_collective";
|
|
var byId = new Dictionary<string, FactionDefRow>(StringComparer.Ordinal)
|
|
{
|
|
[gridFactionId] = PrototypeE7M3FactionCatalogRules.ExpectedFactionFreeze[gridFactionId],
|
|
[rustFactionId] = PrototypeE7M3FactionCatalogRules.ExpectedFactionFreeze[rustFactionId],
|
|
};
|
|
var catalog = new FactionDefinitionCatalog("/tmp/catalog", byId, catalogJsonFileCount: 1);
|
|
return new FactionDefinitionRegistry(catalog);
|
|
}
|
|
}
|