Skip to content

Commit fb27d6f

Browse files
authored
tests: add more in-game tests (#1152)
1 parent acdceb7 commit fb27d6f

File tree

12 files changed

+1064
-10
lines changed

12 files changed

+1064
-10
lines changed

managed/CounterStrikeSharp.Tests.Native/CommandTests.cs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,11 +53,6 @@ public async Task CanTriggerCommandsWithPublicChatTrigger()
5353
NativeAPI.IssueServerCommand("css_test_public_chat 1 2 3");
5454
await WaitOneFrame();
5555
mock.Verify(s => s(It.IsAny<int>(), It.IsAny<IntPtr>()), Times.Once);
56-
57-
NativeAPI.IssueServerCommand("say \"!test_public_chat 1 2 3\"");
58-
await WaitOneFrame();
59-
mock.Verify(s => s(It.IsAny<int>(), It.IsAny<IntPtr>()), Times.Exactly(2));
60-
NativeAPI.RemoveCommand("css_test_public_chat", methodCallback);
6156
}
6257

6358
[Fact]
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
using System.Threading.Tasks;
2+
using CounterStrikeSharp.API;
3+
using CounterStrikeSharp.API.Core;
4+
using Xunit;
5+
6+
namespace NativeTestsPlugin;
7+
8+
public class EngineTests
9+
{
10+
[Fact]
11+
public void GetMapName_ReturnsValidMapName()
12+
{
13+
var mapName = Server.MapName;
14+
15+
Assert.NotNull(mapName);
16+
Assert.NotEmpty(mapName);
17+
}
18+
19+
[Fact]
20+
public void GetGameDirectory_ReturnsValidPath()
21+
{
22+
var gameDir = Server.GameDirectory;
23+
24+
Assert.NotNull(gameDir);
25+
Assert.NotEmpty(gameDir);
26+
}
27+
28+
[Fact]
29+
public void IsMapValid_ReturnsTrueForCurrentMap()
30+
{
31+
var mapName = Server.MapName;
32+
var isValid = Server.IsMapValid(mapName);
33+
34+
Assert.True(isValid, $"Current map '{mapName}' should be valid");
35+
}
36+
37+
[Fact]
38+
public void IsMapValid_ReturnsFalseForInvalidMap()
39+
{
40+
var isValid = Server.IsMapValid("nonexistent_map_xyz_12345");
41+
42+
Assert.False(isValid, "Nonexistent map should be invalid");
43+
}
44+
45+
[Fact]
46+
public void GetTickCount_ReturnsPositiveValue()
47+
{
48+
var tickCount = Server.TickCount;
49+
50+
Assert.True(tickCount > 0, $"TickCount should be positive, got {tickCount}");
51+
}
52+
53+
[Fact]
54+
public async Task GetTickCount_IncrementsOverTime()
55+
{
56+
var tickCount1 = Server.TickCount;
57+
await WaitOneFrame();
58+
var tickCount2 = Server.TickCount;
59+
60+
Assert.True(tickCount2 > tickCount1, $"TickCount should increment: {tickCount1} -> {tickCount2}");
61+
}
62+
63+
[Fact]
64+
public void GetEngineTime_ReturnsPositiveValue()
65+
{
66+
var engineTime = Server.EngineTime;
67+
68+
Assert.True(engineTime > 0, $"EngineTime should be positive, got {engineTime}");
69+
}
70+
71+
[Fact]
72+
public async Task GetEngineTime_IncrementsOverTime()
73+
{
74+
var time1 = Server.EngineTime;
75+
await WaitOneFrame();
76+
var time2 = Server.EngineTime;
77+
78+
Assert.True(time2 > time1, $"EngineTime should increment: {time1} -> {time2}");
79+
}
80+
81+
[Fact]
82+
public void GetCurrentTime_ReturnsPositiveValue()
83+
{
84+
var currentTime = Server.CurrentTime;
85+
86+
Assert.True(currentTime > 0, $"CurrentTime should be positive, got {currentTime}");
87+
}
88+
89+
[Fact]
90+
public async Task GetCurrentTime_IncrementsOverTime()
91+
{
92+
var time1 = Server.CurrentTime;
93+
await WaitOneFrame();
94+
var time2 = Server.CurrentTime;
95+
96+
Assert.True(time2 > time1, $"CurrentTime should increment: {time1} -> {time2}");
97+
}
98+
99+
[Fact]
100+
public void GetMaxClients_ReturnsExpectedValue()
101+
{
102+
var maxPlayers = Server.MaxPlayers;
103+
104+
Assert.True(maxPlayers > 0, $"MaxPlayers should be positive, got {maxPlayers}");
105+
Assert.True(maxPlayers <= 64, $"MaxPlayers should be <= 64 for CS2, got {maxPlayers}");
106+
}
107+
108+
[Fact]
109+
public void GetTickInterval_ReturnsCorrectValue()
110+
{
111+
var tickInterval = NativeAPI.GetTickInterval();
112+
113+
// CS2 is a 64 tick server, so tick interval should be 1/64 = 0.015625
114+
Assert.True(tickInterval > 0, $"TickInterval should be positive, got {tickInterval}");
115+
Assert.Equal(0.015625f, tickInterval, 6);
116+
}
117+
118+
[Fact]
119+
public void GetGameFrameTime_ReturnsPositiveValue()
120+
{
121+
var frameTime = Server.FrameTime;
122+
123+
Assert.True(frameTime > 0, $"FrameTime should be positive, got {frameTime}");
124+
}
125+
126+
[Fact]
127+
public void GetTickedTime_ReturnsNonNegativeValue()
128+
{
129+
var tickedTime = Server.TickedTime;
130+
131+
Assert.True(tickedTime >= 0, $"TickedTime should be non-negative, got {tickedTime}");
132+
}
133+
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
using System.Linq;
2+
using System.Threading.Tasks;
3+
using CounterStrikeSharp.API;
4+
using CounterStrikeSharp.API.Core;
5+
using Moq;
6+
using Xunit;
7+
8+
namespace NativeTestsPlugin;
9+
10+
public class EntityIOTests
11+
{
12+
[Fact]
13+
public void GetDesignerName_ReturnsCorrectName()
14+
{
15+
var world = Utilities.FindAllEntitiesByDesignerName<CWorld>("worldent").FirstOrDefault();
16+
17+
Assert.NotNull(world);
18+
Assert.Equal("worldent", world.DesignerName);
19+
}
20+
21+
[Fact]
22+
public void GetEntityFromIndex_ReturnsValidPointer()
23+
{
24+
var world = Utilities.GetEntityFromIndex<CWorld>(0);
25+
Assert.NotNull(world);
26+
27+
Assert.NotNull(world);
28+
Assert.Equal("worldent", world.DesignerName);
29+
}
30+
31+
[Fact]
32+
public void GetEntityFromHandle_Works()
33+
{
34+
var world = Utilities.FindAllEntitiesByDesignerName<CWorld>("worldent").FirstOrDefault();
35+
36+
Assert.NotNull(world);
37+
38+
var worldFromHandle = world.EntityHandle.Get().As<CWorld>();
39+
40+
Assert.Equal(world.Handle, worldFromHandle.Handle);
41+
}
42+
43+
[Fact]
44+
public async Task AcceptInput_DoesNotThrow()
45+
{
46+
var entity = Utilities.CreateEntityByName<CBaseModelEntity>("prop_dynamic");
47+
48+
Assert.NotNull(entity);
49+
50+
var mock = new Mock<Action>();
51+
var callback = FunctionReference.Create(mock.Object);
52+
53+
try
54+
{
55+
NativeAPI.HookEntityOutput("prop_dynamic", "OnUser1", callback, HookMode.Pre);
56+
NativeAPI.AcceptInput(entity.Handle, "FireUser1", IntPtr.Zero, IntPtr.Zero, "", 0);
57+
await WaitOneFrame();
58+
59+
Assert.Single(mock.Invocations);
60+
61+
// Test unhook
62+
NativeAPI.UnhookEntityOutput("prop_dynamic", "OnUser1", callback, HookMode.Pre);
63+
NativeAPI.AcceptInput(entity.Handle, "FireUser1", IntPtr.Zero, IntPtr.Zero, "", 0);
64+
65+
await WaitOneFrame();
66+
Assert.Single(mock.Invocations);
67+
}
68+
finally
69+
{
70+
entity.Remove();
71+
}
72+
}
73+
}
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
using System.Threading.Tasks;
2+
using CounterStrikeSharp.API;
3+
using CounterStrikeSharp.API.Core;
4+
using Moq;
5+
using Xunit;
6+
7+
namespace NativeTestsPlugin;
8+
9+
public class FrameSchedulingTests
10+
{
11+
[Fact]
12+
public async Task QueueTaskForNextFrame_ExecutesCallback()
13+
{
14+
var mock = new Mock<Action>();
15+
var callback = FunctionReference.Create(mock.Object);
16+
17+
NativeAPI.QueueTaskForNextFrame(callback);
18+
await WaitOneFrame();
19+
20+
mock.Verify(s => s(), Times.Once);
21+
}
22+
23+
[Fact]
24+
public async Task QueueTaskForFrame_ExecutesAtSpecifiedTick()
25+
{
26+
var mock = new Mock<Action>();
27+
var callback = FunctionReference.Create(mock.Object);
28+
var targetTick = Server.TickCount + 5;
29+
30+
NativeAPI.QueueTaskForFrame(targetTick, callback);
31+
32+
mock.Verify(s => s(), Times.Never);
33+
34+
// Wait for the tick to pass
35+
await Server.RunOnTickAsync(targetTick + 1, () => { });
36+
37+
mock.Verify(s => s(), Times.Once);
38+
}
39+
40+
[Fact]
41+
public async Task QueueTaskForNextWorldUpdate_ExecutesCallback()
42+
{
43+
var mock = new Mock<Action>();
44+
var callback = FunctionReference.Create(mock.Object);
45+
46+
NativeAPI.QueueTaskForNextWorldUpdate(callback);
47+
await WaitOneFrame();
48+
49+
mock.Verify(s => s(), Times.Once);
50+
}
51+
52+
[Fact]
53+
public async Task NextFrame_HighLevelApi_ExecutesCallback()
54+
{
55+
bool called = false;
56+
Server.NextFrame(() => { called = true; });
57+
58+
await WaitOneFrame();
59+
60+
Assert.True(called, "NextFrame callback should have been called");
61+
}
62+
63+
[Fact]
64+
public async Task NextFrameAsync_ReturnsCompletedTask()
65+
{
66+
bool called = false;
67+
var task = Server.NextFrameAsync(() => { called = true; });
68+
69+
await task;
70+
71+
Assert.True(called, "NextFrameAsync callback should have been called");
72+
Assert.True(task.IsCompleted, "Task should be completed");
73+
}
74+
75+
[Fact]
76+
public async Task RunOnTickAsync_ReturnsCompletedTask()
77+
{
78+
bool called = false;
79+
var targetTick = Server.TickCount + 3;
80+
var task = Server.RunOnTickAsync(targetTick, () => { called = true; });
81+
82+
await task;
83+
84+
Assert.True(called, "RunOnTickAsync callback should have been called");
85+
Assert.True(task.IsCompleted, "Task should be completed");
86+
}
87+
88+
[Fact]
89+
public async Task NextWorldUpdate_HighLevelApi_ExecutesCallback()
90+
{
91+
bool called = false;
92+
Server.NextWorldUpdate(() => { called = true; });
93+
94+
await WaitOneFrame();
95+
96+
Assert.True(called, "NextWorldUpdate callback should have been called");
97+
}
98+
}

0 commit comments

Comments
 (0)