neon-sprawl/server/NeonSprawl.Server.Tests/Game/Skills/MissionRewardSkillXpGrantTe...

109 lines
4.4 KiB
C#

using System.Linq;
using System.Net;
using System.Net.Http.Json;
using Microsoft.Extensions.DependencyInjection;
using NeonSprawl.Server.Game.Mastery;
using NeonSprawl.Server.Game.PositionState;
using NeonSprawl.Server.Game.Skills;
using Xunit;
namespace NeonSprawl.Server.Tests.Game.Skills;
/// <summary>NEO-43: mission/quest reward hook → skill XP via shared NEO-38 grant path (<c>sourceKind: mission_reward</c>).</summary>
public sealed class MissionRewardSkillXpGrantTests
{
private const int TestMissionRewardXp = 25;
[Fact]
public async Task GrantFromMissionReward_WhenCatalogAllowsMissionReward_ShouldIncreaseSalvageXp()
{
// Arrange — dev player is seeded on the in-memory progression store (NEO-38).
await using var factory = new InMemoryWebApplicationFactory();
_ = factory.CreateClient();
using var scope = factory.Services.CreateScope();
var registry = scope.ServiceProvider.GetRequiredService<ISkillDefinitionRegistry>();
var xpStore = scope.ServiceProvider.GetRequiredService<IPlayerSkillProgressionStore>();
var levelCurve = scope.ServiceProvider.GetRequiredService<ISkillLevelCurve>();
var perkEngine = scope.ServiceProvider.GetRequiredService<PerkUnlockEngine>();
// Act
MissionRewardSkillXpGrant.GrantFromMissionReward(
"dev-local-1",
"salvage",
TestMissionRewardXp,
registry,
xpStore,
levelCurve,
perkEngine);
// Assert
var totals = xpStore.GetXpTotals("dev-local-1");
Assert.True(totals.TryGetValue("salvage", out var xp));
Assert.Equal(TestMissionRewardXp, xp);
}
[Fact]
public async Task GrantFromMissionReward_WhenCatalogAllowsMissionReward_ShouldMatchSkillProgressionGet()
{
// Arrange
await using var factory = new InMemoryWebApplicationFactory();
var client = factory.CreateClient();
var move = new MoveCommandRequest
{
SchemaVersion = MoveCommandRequest.CurrentSchemaVersion,
Target = new PositionVector { X = 0.5, Y = 0.9, Z = 0.5 },
};
await client.PostAsJsonAsync("/game/players/dev-local-1/move", move);
using var scope = factory.Services.CreateScope();
var registry = scope.ServiceProvider.GetRequiredService<ISkillDefinitionRegistry>();
var xpStore = scope.ServiceProvider.GetRequiredService<IPlayerSkillProgressionStore>();
var levelCurve = scope.ServiceProvider.GetRequiredService<ISkillLevelCurve>();
var perkEngine = scope.ServiceProvider.GetRequiredService<PerkUnlockEngine>();
// Act
MissionRewardSkillXpGrant.GrantFromMissionReward(
"dev-local-1",
"salvage",
TestMissionRewardXp,
registry,
xpStore,
levelCurve,
perkEngine);
var snapshot = await client.GetAsync("/game/players/dev-local-1/skill-progression");
// Assert
Assert.Equal(HttpStatusCode.OK, snapshot.StatusCode);
var body = await snapshot.Content.ReadFromJsonAsync<SkillProgressionSnapshotResponse>();
Assert.NotNull(body);
var salvage = body!.Skills!.Single(static s => s.Id == "salvage");
Assert.Equal(TestMissionRewardXp, salvage.Xp);
}
[Fact]
public async Task GrantFromMissionReward_WhenSalvageDisallowsMissionReward_ShouldLeaveSalvageXpZero()
{
// Arrange
await using var factory = new MissionRewardDeniedRegistryWebApplicationFactory();
_ = factory.CreateClient();
using var scope = factory.Services.CreateScope();
var registry = scope.ServiceProvider.GetRequiredService<ISkillDefinitionRegistry>();
var xpStore = scope.ServiceProvider.GetRequiredService<IPlayerSkillProgressionStore>();
var levelCurve = scope.ServiceProvider.GetRequiredService<ISkillLevelCurve>();
var perkEngine = scope.ServiceProvider.GetRequiredService<PerkUnlockEngine>();
// Act
MissionRewardSkillXpGrant.GrantFromMissionReward(
"dev-local-1",
"salvage",
TestMissionRewardXp,
registry,
xpStore,
levelCurve,
perkEngine);
// Assert — deny returns before TryApplyXpDelta; salvage row must not appear in stored XP map.
var totals = xpStore.GetXpTotals("dev-local-1");
Assert.False(totals.ContainsKey("salvage"));
}
}