Initial commit: Client Doc docs Server Tools
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
using Xunit;
|
||||
using XWorld.Server.Gateway;
|
||||
|
||||
namespace XWorld.Server.Gateway.Tests
|
||||
{
|
||||
public class MatchmakerTests
|
||||
{
|
||||
[Fact]
|
||||
public void TwoEnqueues_SameBucket_PlayerCount2_Poll_ReturnsTwoHumanMatch()
|
||||
{
|
||||
var mm = new Matchmaker(timeoutTicks: 100);
|
||||
mm.Enqueue(pid: 1, gameId: "rps", version: 1, playerCount: 2, tick: 0);
|
||||
mm.Enqueue(pid: 2, gameId: "rps", version: 1, playerCount: 2, tick: 0);
|
||||
|
||||
var matches = mm.Poll(currentTick: 0);
|
||||
|
||||
Assert.Single(matches);
|
||||
var m = matches[0];
|
||||
Assert.Equal("rps", m.GameId);
|
||||
Assert.Equal(1, m.Version);
|
||||
Assert.Equal(2, m.Seats.Count);
|
||||
Assert.False(m.Seats[0].IsAi);
|
||||
Assert.False(m.Seats[1].IsAi);
|
||||
Assert.Equal(1, m.Seats[0].PlayerId);
|
||||
Assert.Equal(2, m.Seats[1].PlayerId);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SingleEnqueue_PollAfterTimeout_Returns1Human1AiMatch()
|
||||
{
|
||||
var mm = new Matchmaker(timeoutTicks: 10);
|
||||
mm.Enqueue(pid: 7, gameId: "rps", version: 1, playerCount: 2, tick: 0);
|
||||
|
||||
// Not timed out yet
|
||||
var early = mm.Poll(currentTick: 9);
|
||||
Assert.Empty(early);
|
||||
|
||||
// Now timed out (currentTick - enqueuedTick > timeoutTicks → 11 - 0 = 11 > 10)
|
||||
var matches = mm.Poll(currentTick: 10);
|
||||
|
||||
Assert.Single(matches);
|
||||
var m = matches[0];
|
||||
Assert.Equal(2, m.Seats.Count);
|
||||
// First seat is the real player
|
||||
Assert.False(m.Seats[0].IsAi);
|
||||
Assert.Equal(7, m.Seats[0].PlayerId);
|
||||
// Second seat is AI with negative pid
|
||||
Assert.True(m.Seats[1].IsAi);
|
||||
Assert.True(m.Seats[1].PlayerId < 0);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NotFull_NotTimedOut_Poll_ReturnsEmpty()
|
||||
{
|
||||
var mm = new Matchmaker(timeoutTicks: 100);
|
||||
mm.Enqueue(pid: 3, gameId: "rps", version: 1, playerCount: 2, tick: 5);
|
||||
|
||||
var matches = mm.Poll(currentTick: 50); // 50-5=45 <= 100, not timed out, not full
|
||||
|
||||
Assert.Empty(matches);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PlayerCount1_SingleEnqueue_PollImmediately_ReturnsMatch()
|
||||
{
|
||||
// playerCount=1 应立即成团(Matchmaker 仅按 playerCount 分桶,不加载具体游戏)
|
||||
var mm = new Matchmaker(timeoutTicks: 100);
|
||||
mm.Enqueue(pid: 5, gameId: "solo1p", version: 1, playerCount: 1, tick: 0);
|
||||
|
||||
var matches = mm.Poll(currentTick: 0);
|
||||
|
||||
Assert.Single(matches);
|
||||
Assert.Single(matches[0].Seats);
|
||||
Assert.False(matches[0].Seats[0].IsAi);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Remove_DequeuesWaiter_SoNoMatchForms()
|
||||
{
|
||||
var mm = new Matchmaker(timeoutTicks: 100);
|
||||
mm.Enqueue(1, "rps", 1, 2, tick: 0);
|
||||
Assert.True(mm.Remove(1));
|
||||
mm.Enqueue(2, "rps", 1, 2, tick: 0); // 只剩玩家2,凑不齐2人
|
||||
Assert.Empty(mm.Poll(1)); // 未满未超时 → 无对局
|
||||
Assert.False(mm.Remove(999)); // 不存在的 pid
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user