feat(battle-xp): wire rank + AI-rank /finish through IBattleXpService
- RankBattleController.Finish (covers all 4 URLs: rotation, unlimited, ai_rotation, ai_unlimited) now grants win/loss XP via IBattleXpService with BattleXpMode.Rank. Uses req.ClassId from wire. - Tests updated: AI-variant win asserts new XP values; consistency-loss asserts loss XP. Added persistence test on /unlimited_rank_battle/finish. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -1,9 +1,11 @@
|
||||
using System.Net.Http.Json;
|
||||
using System.Text.Json;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using NUnit.Framework;
|
||||
using SVSim.BattleNode.Bridge;
|
||||
using SVSim.BattleNode.Sessions;
|
||||
using SVSim.Database;
|
||||
using SVSim.Database.Enums;
|
||||
using SVSim.EmulatedEntrypoint.Services;
|
||||
using SVSim.UnitTests.Infrastructure;
|
||||
@@ -231,13 +233,14 @@ public class RankBattleControllerTests
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Finish_emits_stubbed_zeros_with_battle_result_echo()
|
||||
public async Task Finish_grants_win_xp_via_ai_variant()
|
||||
{
|
||||
await using var factory = new SVSimTestFactory();
|
||||
var viewerId = await factory.SeedViewerAsync();
|
||||
var client = factory.CreateAuthenticatedClient(viewerId);
|
||||
|
||||
var resp = await client.PostAsJsonAsync("/ai_rotation_rank_battle/finish", FinishBody(battleResult: 1));
|
||||
var resp = await client.PostAsJsonAsync(
|
||||
"/ai_rotation_rank_battle/finish", FinishBody(battleResult: 1, classId: 1));
|
||||
|
||||
Assert.That(resp.IsSuccessStatusCode, Is.True);
|
||||
using var doc = JsonDocument.Parse(await resp.Content.ReadAsStringAsync());
|
||||
@@ -245,7 +248,10 @@ public class RankBattleControllerTests
|
||||
Assert.That(data.GetProperty("battle_result").GetInt32(), Is.EqualTo(1));
|
||||
Assert.That(data.GetProperty("rank").GetInt32(), Is.EqualTo(0));
|
||||
Assert.That(data.GetProperty("after_battle_point").GetInt32(), Is.EqualTo(0));
|
||||
Assert.That(data.GetProperty("class_level").GetInt32(), Is.EqualTo(1));
|
||||
// BattleXpConfig.XpPerWin=100, classexp.csv L1=50 → land at L2 with 50 carry.
|
||||
Assert.That(data.GetProperty("get_class_experience").GetInt32(), Is.EqualTo(100));
|
||||
Assert.That(data.GetProperty("class_experience").GetInt32(), Is.EqualTo(50));
|
||||
Assert.That(data.GetProperty("class_level").GetInt32(), Is.EqualTo(2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -255,9 +261,32 @@ public class RankBattleControllerTests
|
||||
var viewerId = await factory.SeedViewerAsync();
|
||||
var client = factory.CreateAuthenticatedClient(viewerId);
|
||||
|
||||
var resp = await client.PostAsJsonAsync("/rotation_rank_battle/finish", FinishBody(battleResult: 2));
|
||||
var resp = await client.PostAsJsonAsync("/rotation_rank_battle/finish", FinishBody(battleResult: 2, classId: 1));
|
||||
|
||||
using var doc = JsonDocument.Parse(await resp.Content.ReadAsStringAsync());
|
||||
Assert.That(doc.RootElement.GetProperty("battle_result").GetInt32(), Is.EqualTo(2));
|
||||
// battle_result==2 is loss-shaped: XpPerLoss=25 (< L1 threshold=50).
|
||||
Assert.That(doc.RootElement.GetProperty("get_class_experience").GetInt32(), Is.EqualTo(25));
|
||||
Assert.That(doc.RootElement.GetProperty("class_experience").GetInt32(), Is.EqualTo(25));
|
||||
Assert.That(doc.RootElement.GetProperty("class_level").GetInt32(), Is.EqualTo(1));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Finish_persists_class_xp_to_viewer()
|
||||
{
|
||||
await using var factory = new SVSimTestFactory();
|
||||
var viewerId = await factory.SeedViewerAsync();
|
||||
var client = factory.CreateAuthenticatedClient(viewerId);
|
||||
|
||||
await client.PostAsJsonAsync(
|
||||
"/unlimited_rank_battle/finish", FinishBody(battleResult: 1, classId: 3));
|
||||
|
||||
using var scope = factory.Services.CreateScope();
|
||||
var db = scope.ServiceProvider.GetRequiredService<SVSimDbContext>();
|
||||
var v = await db.Viewers.Include(x => x.Classes).ThenInclude(c => c.Class)
|
||||
.FirstAsync(x => x.Id == viewerId);
|
||||
var cls3 = v.Classes.Single(c => c.Class.Id == 3);
|
||||
Assert.That(cls3.Level, Is.EqualTo(2));
|
||||
Assert.That(cls3.Exp, Is.EqualTo(50));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user