using NeonSprawl.Server.Game.Factions; using NeonSprawl.Server.Game.Items; using NeonSprawl.Server.Game.Mastery; using NeonSprawl.Server.Game.Quests; using NeonSprawl.Server.Game.Rewards; namespace NeonSprawl.Server.Tests.Game.Factions; public sealed class FactionStandingApiTests { private const string PlayerId = "dev-local-1"; private const string OperatorChainQuestId = "prototype_quest_operator_chain"; private const string GridOperatorsFactionId = PrototypeE7M3QuestFactionRules.GridContractGateFactionId; private const string RustCollectiveFactionId = "prototype_faction_rust_collective"; [Fact] public async Task GetFactionStanding_ShouldReturnNotFound_WhenPlayerUnknown() { // Arrange await using var factory = new InMemoryWebApplicationFactory(); var client = factory.CreateClient(); // Act var response = await client.GetAsync("/game/players/missing-player/faction-standing"); // Assert Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); } [Fact] public async Task GetFactionStanding_ShouldReturnNotFound_WhenPathIdIsWhitespaceOnly() { // Arrange await using var factory = new InMemoryWebApplicationFactory(); var client = factory.CreateClient(); // Act var response = await client.GetAsync("/game/players/%20%20/faction-standing"); // Assert Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); } [Fact] public async Task GetFactionStanding_ShouldReturnOk_WhenPathIdHasLeadingAndTrailingWhitespace() { // Arrange await using var factory = new InMemoryWebApplicationFactory(); var client = factory.CreateClient(); // Act var response = await client.GetAsync("/game/players/%20dev-local-1%20/faction-standing"); // Assert Assert.Equal(HttpStatusCode.OK, response.StatusCode); var body = await response.Content.ReadFromJsonAsync(); Assert.NotNull(body); Assert.Equal("dev-local-1", body!.PlayerId); Assert.Equal(FactionStandingSnapshotResponse.CurrentSchemaVersion, body.SchemaVersion); } [Fact] public async Task GetFactionStanding_ShouldReturnSchemaV1_WithNeutralStanding_ForPrototypeFactions() { // Arrange await using var factory = new InMemoryWebApplicationFactory(); var client = factory.CreateClient(); // Act var response = await client.GetAsync("/game/players/dev-local-1/faction-standing"); // Assert Assert.Equal(HttpStatusCode.OK, response.StatusCode); var body = await response.Content.ReadFromJsonAsync(); Assert.NotNull(body); Assert.Equal(FactionStandingSnapshotResponse.CurrentSchemaVersion, body!.SchemaVersion); Assert.Equal("dev-local-1", body.PlayerId); Assert.NotNull(body.Factions); Assert.Equal(PrototypeE7M3FactionCatalogRules.ExpectedFactionIds.Count, body.Factions!.Count); var byId = body.Factions.ToDictionary(static row => row.Id, StringComparer.Ordinal); foreach (var factionId in PrototypeE7M3FactionCatalogRules.ExpectedFactionIds) { Assert.True(byId.TryGetValue(factionId, out var row)); Assert.Equal(0, row!.Standing); } } [Fact] public async Task GetFactionStanding_ShouldReturnGridOperatorsStanding15_AfterOperatorChainRepGrant() { // Arrange await using var factory = new InMemoryWebApplicationFactory(); var deps = ResolveRewardRouterDependencies(factory); var bundle = PrototypeE7M3QuestFactionRules.ExpectedCompletionBundles[OperatorChainQuestId]; var deliver = RewardRouterOperations.TryDeliverQuestCompletion( PlayerId, OperatorChainQuestId, bundle, deps.ItemRegistry, deps.InventoryStore, deps.SkillRegistry, deps.SkillProgressionStore, deps.LevelCurve, deps.PerkUnlockEngine, deps.PerkStore, deps.DeliveryStore, deps.StandingStore, deps.AuditStore, TimeProvider.System); Assert.True(deliver.Success); var client = factory.CreateClient(); // Act var response = await client.GetAsync("/game/players/dev-local-1/faction-standing"); // Assert Assert.Equal(HttpStatusCode.OK, response.StatusCode); var body = await response.Content.ReadFromJsonAsync(); Assert.NotNull(body); var byId = body!.Factions!.ToDictionary(static row => row.Id, StringComparer.Ordinal); Assert.Equal( PrototypeE7M3QuestFactionRules.GridContractMinStanding, byId[GridOperatorsFactionId].Standing); Assert.Equal(0, byId[RustCollectiveFactionId].Standing); } private static RewardRouterTestDependencies ResolveRewardRouterDependencies(InMemoryWebApplicationFactory factory) { var services = factory.Services; return new RewardRouterTestDependencies( services.GetRequiredService(), services.GetRequiredService(), services.GetRequiredService(), services.GetRequiredService(), services.GetRequiredService(), services.GetRequiredService(), services.GetRequiredService(), services.GetRequiredService(), services.GetRequiredService(), services.GetRequiredService()); } private sealed record RewardRouterTestDependencies( IItemDefinitionRegistry ItemRegistry, IPlayerInventoryStore InventoryStore, ISkillDefinitionRegistry SkillRegistry, IPlayerSkillProgressionStore SkillProgressionStore, ISkillLevelCurve LevelCurve, PerkUnlockEngine PerkUnlockEngine, IPlayerPerkStateStore PerkStore, IRewardDeliveryStore DeliveryStore, IFactionStandingStore StandingStore, IReputationDeltaStore AuditStore); }