Files
SVSimServer/SVSim.UnitTests/BattleNode/Hosting/WaitingRoomTests.cs
gamer147 1007cf24d2 refactor(battlenode): type MatchContext.ClassId as CardClass enum (§C)
Behavior-preserving; full solution builds, 1013 tests green.

ClassId is the one genuinely-closed set of the three flagged stringly fields, so it
becomes a CardClass enum (1..8). Wire stays "1".."8": producer casts
(CardClass)run.ClassId, ServerBattleFrames renders via CardClassWire.ToWireValue().
RankBattleController's AI-start path drops a fragile int.TryParse(...)?:-1 for (int)cast.

CharaId (free-form leader/skin id, e.g. "5000123") and CountryCode (open-ended account
data) stay string with proper XML docs; CountryCodes.Korea/Japan name the captured values.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 08:04:49 -04:00

79 lines
2.7 KiB
C#

using Microsoft.Extensions.Logging.Abstractions;
using NUnit.Framework;
using SVSim.BattleNode.Bridge;
using SVSim.BattleNode.Hosting;
using SVSim.BattleNode.Sessions.Participants;
using SVSim.UnitTests.BattleNode.Infrastructure;
namespace SVSim.UnitTests.BattleNode.Hosting;
[TestFixture]
public class WaitingRoomTests
{
[Test]
public void Pair_on_empty_slot_returns_null()
{
var room = new WaitingRoom();
var participant = NewParticipant(viewerId: 1);
var paired = room.Pair("bid-1", participant);
Assert.That(paired, Is.Null);
}
[Test]
public async Task Park_then_Pair_resolves_with_each_arriver_seeing_the_other()
{
var room = new WaitingRoom();
var first = NewParticipant(viewerId: 1);
var second = NewParticipant(viewerId: 2);
var parkTask = room.ParkAsync("bid-1", first, TimeSpan.FromSeconds(5), CancellationToken.None);
// Yield so Park's TryAdd lands first.
await Task.Yield();
var firstReturnedToSecond = room.Pair("bid-1", second);
var secondReturnedToFirst = await parkTask;
Assert.That(firstReturnedToSecond, Is.SameAs(first),
"Pair must return the first arriver to the second.");
Assert.That(secondReturnedToFirst, Is.SameAs(second),
"Park must return the second arriver to the first.");
}
[Test]
public async Task Park_times_out_returns_null_and_evicts_slot()
{
var room = new WaitingRoom();
var first = NewParticipant(viewerId: 1);
var second = await room.ParkAsync("bid-1", first, TimeSpan.FromMilliseconds(50), CancellationToken.None);
Assert.That(second, Is.Null);
// Slot should be evicted; a subsequent Pair returns null (no first arriver).
var paired = room.Pair("bid-1", NewParticipant(viewerId: 2));
Assert.That(paired, Is.Null);
}
[Test]
public void Evict_is_idempotent()
{
var room = new WaitingRoom();
Assert.DoesNotThrow(() => room.Evict("bid-1"));
Assert.DoesNotThrow(() => room.Evict("bid-1"));
}
private static RealParticipant NewParticipant(long viewerId)
{
var ws = new TestWebSocket();
var ctx = new MatchContext(
SelfDeckCardIds: Array.Empty<long>(),
ClassId: CardClass.Forestcraft, CharaId: "1", CardMasterName: "card_master_node_10015",
CountryCode: CountryCodes.Korea, UserName: "Player", SleeveId: "0",
EmblemId: "0", DegreeId: "0", FieldId: 0, IsOfficial: 0,
BattleModeId: BattleModes.TakeTwo);
return new RealParticipant(ws, viewerId, ctx, NullLogger<RealParticipant>.Instance);
}
}