Files
sbox-public/engine/Sandbox.Test/Game/FixedUpdate.cs
s&box team 71f266059a Open source release
This commit imports the C# engine code and game files, excluding C++ source code.

[Source-Commit: ceb3d758046e50faa6258bc3b658a30c97743268]
2025-11-24 09:05:18 +00:00

175 lines
4.6 KiB
C#

using System;
[TestClass]
public class FixedUpdateTests
{
[TestMethod]
[DataRow( 1, 5, 11 )] // Very low frequency
[DataRow( 5, 5, 59 )] // Standard case
[DataRow( 30, 5, 359 )] // Higher frequency
[DataRow( 60, 5, 719 )] // Same as frame rate
[DataRow( 120, 5, 1439 )] // Higher than frame rate
[DataRow( 1, 1, 11 )] // maxSteps = 1, low frequency
[DataRow( 10, 1, 119 )] // maxSteps = 1, medium frequency
[DataRow( 60, 2, 719 )] // maxSteps = 2, high frequency (maxSteps doesn't limit here)
public void TestFixedUpdateFrequency( int frequency, int maxSteps, int expectedCalls )
{
var fu = new FixedUpdate();
fu.Frequency = frequency;
var fixedDelta = fu.Delta;
int callTimes = 0;
Action action = () =>
{
callTimes++;
Assert.AreEqual( Time.Delta, fixedDelta, "Fixed delta doesn't match!" );
// Get the remainder as a number around 0
float remainder = (Time.Now % fixedDelta);
if ( remainder > fixedDelta / 2 ) remainder = fixedDelta - remainder;
Assert.AreEqual( 0, remainder, 0.00001f, "Time.Now doesn't align with step!" );
};
float time = 0;
float fps = 60;
float frameDelta = 1.0f / fps;
int loops = 0;
// Simulate 12 seconds (shorter time for faster test execution)
while ( time < 12.0f )
{
loops++;
fu.Run( action, time, maxSteps );
time += frameDelta;
}
Console.WriteLine( $"{loops} loops at {fps:N0} FPS with maxSteps={maxSteps} gave {callTimes} fixed updates at {frequency} Hz" );
// Allow small tolerance for floating point differences at very low frequencies
if ( frequency <= 1 )
{
Assert.IsTrue( Math.Abs( expectedCalls - callTimes ) <= 1,
$"Expected approximately {expectedCalls} calls, got {callTimes}" );
}
else
{
Assert.AreEqual( expectedCalls, callTimes );
}
}
[TestMethod]
public void TestDeltaCalculation()
{
var fu = new FixedUpdate();
// Test various frequencies
fu.Frequency = 10;
Assert.AreEqual( 0.1f, fu.Delta, 0.00001f );
fu.Frequency = 60;
Assert.AreEqual( 1.0f / 60, fu.Delta, 0.00001f );
fu.Frequency = 1;
Assert.AreEqual( 1.0f, fu.Delta, 0.00001f );
// Test non-integer frequency
fu.Frequency = 16.7f; // Approx 60fps / 1000 * 16.7ms
Assert.AreEqual( 1.0f / 16.7f, fu.Delta, 0.00001f );
}
[TestMethod]
public void TestMaxSteps()
{
var fu = new FixedUpdate();
fu.Frequency = 10; // 10Hz = 0.1s per update
int callCount = 0;
Action action = () => callCount++;
// Start at time 0
fu.Run( action, 0, 5 );
Assert.AreEqual( 0, callCount, "No updates should occur at start" );
// Jump ahead by 1 second (10 steps)
fu.Run( action, 1.0f, 5 );
Assert.AreEqual( 5, callCount, "Should be limited by maxSteps" );
// Small increment should continue from where we left off
fu.Run( action, 1.1f, 5 );
Assert.AreEqual( 6, callCount, "Should get 1 more update" );
}
[TestMethod]
public void TestTimeNotAdvancing()
{
var fu = new FixedUpdate();
fu.Frequency = 10;
int callCount = 0;
Action action = () => callCount++;
// First call
fu.Run( action, 1.0f, 5 );
int firstCallCount = callCount;
// Call again with same time
fu.Run( action, 1.0f, 5 );
Assert.AreEqual( firstCallCount, callCount, "No updates should occur when time doesn't advance" );
}
[TestMethod]
public void TestNegativeTime()
{
var fu = new FixedUpdate();
fu.Frequency = 10;
int callCount = 0;
Action action = () => callCount++;
// First call with negative time
fu.Run( action, -1.0f, 5 );
// Then positive time
fu.Run( action, 0.5f, 5 );
// We expect calls because we're moving forward in time
Assert.IsTrue( callCount > 0, "Should get updates when moving from negative to positive time" );
}
[TestMethod]
public void TestNonIntegerFrequency()
{
var fu = new FixedUpdate();
fu.Frequency = 2.5f; // 2.5Hz = 0.4s per update
int callCount = 0;
Action action = () => callCount++;
float time = 0;
float fps = 60;
float frameDelta = 1.0f / fps;
// Simulate 1 second
while ( time < 1.0f )
{
fu.Run( action, time, 5 );
time += frameDelta;
}
// At 2.5Hz, we expect 2 or 3 calls in 1 second
// (Depends on floating point precision and exact timing)
Assert.IsTrue( callCount >= 2 && callCount <= 3,
$"Expected 2-3 updates with 2.5Hz in 1 second, got {callCount}" );
}
[TestMethod]
public void TestLargeTimeJump()
{
var fu = new FixedUpdate();
fu.Frequency = 10; // 10Hz
int callCount = 0;
Action action = () => callCount++;
// Jump ahead by a large amount (20 seconds = 200 updates at 10Hz)
fu.Run( action, 20.0f, 10 );
// Should be limited by maxSteps
Assert.AreEqual( 10, callCount );
}
}