Initial commit: Client Doc docs Server Tools
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,150 @@
|
||||
using System.Collections.Generic;
|
||||
using Xunit;
|
||||
using XWorld.Framework;
|
||||
using XWorld.Framework.Protocol;
|
||||
|
||||
namespace XWorld.Framework.Tests
|
||||
{
|
||||
public class FrameworkMessagesTests
|
||||
{
|
||||
[Fact]
|
||||
public void Heartbeat_RoundTrips()
|
||||
{
|
||||
var m = new HeartbeatMsg { ClientTimeMs = 1_725_000_000_123L };
|
||||
var d = HeartbeatMsg.Decode(m.Encode());
|
||||
Assert.Equal(m.ClientTimeMs, d.ClientTimeMs);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MatchRequest_RoundTrips()
|
||||
{
|
||||
var m = new MatchRequestMsg { GameId = "rock_paper_scissors", Version = 3 };
|
||||
var d = MatchRequestMsg.Decode(m.Encode());
|
||||
Assert.Equal(m.GameId, d.GameId);
|
||||
Assert.Equal(m.Version, d.Version);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MatchFound_RoundTrips_WithPlayers()
|
||||
{
|
||||
var m = new MatchFoundMsg
|
||||
{
|
||||
RoomId = "room-42",
|
||||
Version = 3,
|
||||
SelfPlayerId = 1001,
|
||||
Players =
|
||||
{
|
||||
new PlayerInfo { PlayerId = 1001, Name = "Alice", IsAI = false },
|
||||
new PlayerInfo { PlayerId = -1, Name = "AI", IsAI = true },
|
||||
},
|
||||
};
|
||||
var d = MatchFoundMsg.Decode(m.Encode());
|
||||
Assert.Equal("room-42", d.RoomId);
|
||||
Assert.Equal(3, d.Version);
|
||||
Assert.Equal(1001, d.SelfPlayerId);
|
||||
Assert.Equal(2, d.Players.Count);
|
||||
Assert.Equal(1001, d.Players[0].PlayerId);
|
||||
Assert.Equal("Alice", d.Players[0].Name);
|
||||
Assert.False(d.Players[0].IsAI);
|
||||
Assert.Equal(-1, d.Players[1].PlayerId);
|
||||
Assert.True(d.Players[1].IsAI);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GameInput_RoundTrips()
|
||||
{
|
||||
var m = new GameInputMsg { GameOpcode = 12, Payload = new byte[] { 9, 8, 7 } };
|
||||
var d = GameInputMsg.Decode(m.Encode());
|
||||
Assert.Equal((ushort)12, d.GameOpcode);
|
||||
Assert.Equal(new byte[] { 9, 8, 7 }, d.Payload);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Snapshot_RoundTrips()
|
||||
{
|
||||
var m = new SnapshotMsg { Tick = 250, StateBlob = new byte[] { 0xDE, 0xAD } };
|
||||
var d = SnapshotMsg.Decode(m.Encode());
|
||||
Assert.Equal(250, d.Tick);
|
||||
Assert.Equal(new byte[] { 0xDE, 0xAD }, d.StateBlob);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RoomEnd_RoundTrips()
|
||||
{
|
||||
var m = new RoomEndMsg { WinnerPlayerId = 1001, ResultBlob = new byte[] { 1 } };
|
||||
var d = RoomEndMsg.Decode(m.Encode());
|
||||
Assert.Equal(1001, d.WinnerPlayerId);
|
||||
Assert.Equal(new byte[] { 1 }, d.ResultBlob);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Error_RoundTrips()
|
||||
{
|
||||
var m = new ErrorMsg { Code = 404, Message = "version mismatch" };
|
||||
var d = ErrorMsg.Decode(m.Encode());
|
||||
Assert.Equal(404, d.Code);
|
||||
Assert.Equal("version mismatch", d.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Opcodes_AreStableValues()
|
||||
{
|
||||
// 线网兼容性:opcode 数值固定,改动等于破坏协议
|
||||
Assert.Equal((ushort)1, (ushort)FrameworkOpcode.Heartbeat);
|
||||
Assert.Equal((ushort)2, (ushort)FrameworkOpcode.MatchRequest);
|
||||
Assert.Equal((ushort)3, (ushort)FrameworkOpcode.MatchFound);
|
||||
Assert.Equal((ushort)4, (ushort)FrameworkOpcode.GameInput);
|
||||
Assert.Equal((ushort)5, (ushort)FrameworkOpcode.Snapshot);
|
||||
Assert.Equal((ushort)6, (ushort)FrameworkOpcode.RoomEnd);
|
||||
Assert.Equal((ushort)7, (ushort)FrameworkOpcode.Error);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Message_TravelsInsideFrame()
|
||||
{
|
||||
// 端到端:DTO -> payload -> Frame -> wire -> Frame -> DTO
|
||||
var req = new MatchRequestMsg { GameId = "rps", Version = 1 };
|
||||
var frame = new Frame(Channel.Framework, (ushort)FrameworkOpcode.MatchRequest, req.Encode());
|
||||
byte[] wire = FrameCodec.Encode(frame);
|
||||
|
||||
Frame back = FrameCodec.Decode(wire);
|
||||
Assert.Equal(Channel.Framework, back.Channel);
|
||||
Assert.Equal((ushort)FrameworkOpcode.MatchRequest, back.Opcode);
|
||||
var d = MatchRequestMsg.Decode(back.Payload);
|
||||
Assert.Equal("rps", d.GameId);
|
||||
Assert.Equal(1, d.Version);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GameInput_NullPayload_RoundTrips_AsEmpty()
|
||||
{
|
||||
var m = new GameInputMsg { GameOpcode = 5, Payload = null };
|
||||
var d = GameInputMsg.Decode(m.Encode());
|
||||
Assert.Equal((ushort)5, d.GameOpcode);
|
||||
Assert.NotNull(d.Payload);
|
||||
Assert.Empty(d.Payload);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Error_NullMessage_RoundTrips_AsEmpty()
|
||||
{
|
||||
var m = new ErrorMsg { Code = 7, Message = null };
|
||||
var d = ErrorMsg.Decode(m.Encode());
|
||||
Assert.Equal(7, d.Code);
|
||||
Assert.Equal(string.Empty, d.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MatchFound_EmptyPlayerList_RoundTrips()
|
||||
{
|
||||
var m = new MatchFoundMsg { RoomId = "r0", Version = 1, SelfPlayerId = 0 };
|
||||
// Players 默认空列表,不添加任何玩家
|
||||
var d = MatchFoundMsg.Decode(m.Encode());
|
||||
Assert.Equal("r0", d.RoomId);
|
||||
Assert.Equal(1, d.Version);
|
||||
Assert.Equal(0, d.SelfPlayerId);
|
||||
Assert.NotNull(d.Players);
|
||||
Assert.Empty(d.Players);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user