mirror of
https://github.com/gui-cs/Terminal.Gui.git
synced 2025-12-27 00:07:58 +01:00
* Refactored test namespaces. Moved some tests that were in wrong project. Code cleanup * Parrallel -> Parallel
236 lines
7.9 KiB
C#
236 lines
7.9 KiB
C#
using Moq;
|
|
|
|
namespace UnitTests.DriverTests;
|
|
|
|
|
|
public class AnsiRequestSchedulerTests
|
|
{
|
|
private readonly Mock<IAnsiResponseParser> _parserMock;
|
|
private readonly AnsiRequestScheduler _scheduler;
|
|
|
|
private static DateTime _staticNow; // Static value to hold the current time
|
|
|
|
public AnsiRequestSchedulerTests ()
|
|
{
|
|
_parserMock = new Mock<IAnsiResponseParser> (MockBehavior.Strict);
|
|
_staticNow = DateTime.UtcNow; // Initialize static time
|
|
_scheduler = new AnsiRequestScheduler (_parserMock.Object, () => _staticNow);
|
|
}
|
|
|
|
[Fact]
|
|
public void SendOrSchedule_SendsDeviceAttributeRequest_WhenNoOutstandingRequests ()
|
|
{
|
|
// Arrange
|
|
var request = new AnsiEscapeSequenceRequest
|
|
{
|
|
Request = "\u001b[0c", // ESC [ c
|
|
Terminator = "c",
|
|
ResponseReceived = r => { }
|
|
};
|
|
|
|
// we have no outstanding for c already
|
|
_parserMock.Setup (p => p.IsExpecting ("c")).Returns (false).Verifiable(Times.Once);
|
|
|
|
// then we should execute our request
|
|
_parserMock.Setup (p => p.ExpectResponse ("c", It.IsAny<Action<string>> (), null, false)).Verifiable (Times.Once);
|
|
|
|
// Act
|
|
bool result = _scheduler.SendOrSchedule (request);
|
|
|
|
|
|
// Assert
|
|
Assert.Empty (_scheduler.QueuedRequests); // We sent it i.e. we did not queue it for later
|
|
Assert.True (result); // Should send immediately
|
|
_parserMock.Verify ();
|
|
}
|
|
[Fact]
|
|
public void SendOrSchedule_QueuesRequest_WhenOutstandingRequestExists ()
|
|
{
|
|
// Arrange
|
|
var request1 = new AnsiEscapeSequenceRequest
|
|
{
|
|
Request = "\u001b[0c", // ESC [ 0 c
|
|
Terminator = "c",
|
|
ResponseReceived = r => { }
|
|
};
|
|
|
|
// Parser already has an ongoing request for "c"
|
|
_parserMock.Setup (p => p.IsExpecting ("c")).Returns (true).Verifiable (Times.Once);
|
|
|
|
// Act
|
|
var result = _scheduler.SendOrSchedule (request1);
|
|
|
|
// Assert
|
|
Assert.Single (_scheduler.QueuedRequests); // Ensure only one request is in the queue
|
|
Assert.False (result); // Should be queued
|
|
_parserMock.Verify ();
|
|
}
|
|
|
|
|
|
[Fact]
|
|
public void RunSchedule_ThrottleNotExceeded_AllowSend ()
|
|
{
|
|
// Arrange
|
|
var request = new AnsiEscapeSequenceRequest
|
|
{
|
|
Request = "\u001b[0c", // ESC [ 0 c
|
|
Terminator = "c",
|
|
ResponseReceived = r => { }
|
|
};
|
|
|
|
// Set up to expect no outstanding request for "c" i.e. parser instantly gets response and resolves it
|
|
_parserMock.Setup (p => p.IsExpecting ("c")).Returns (false).Verifiable(Times.Exactly (2));
|
|
_parserMock.Setup (p => p.ExpectResponse ("c", It.IsAny<Action<string>> (), null, false)).Verifiable (Times.Exactly (2));
|
|
|
|
_scheduler.SendOrSchedule (request);
|
|
|
|
// Simulate time passing beyond throttle
|
|
SetTime (101); // Exceed throttle limit
|
|
|
|
|
|
// Act
|
|
|
|
// Send another request after the throttled time limit
|
|
var result = _scheduler.SendOrSchedule (request);
|
|
|
|
// Assert
|
|
Assert.Empty (_scheduler.QueuedRequests); // Should send and clear the request
|
|
Assert.True (result); // Should have found and sent the request
|
|
_parserMock.Verify ();
|
|
}
|
|
|
|
[Fact]
|
|
public void RunSchedule_ThrottleExceeded_QueueRequest ()
|
|
{
|
|
// Arrange
|
|
var request = new AnsiEscapeSequenceRequest
|
|
{
|
|
Request = "\u001b[0c", // ESC [ 0 c
|
|
Terminator = "c",
|
|
ResponseReceived = r => { }
|
|
};
|
|
|
|
// Set up to expect no outstanding request for "c" i.e. parser instantly gets response and resolves it
|
|
_parserMock.Setup (p => p.IsExpecting ("c")).Returns (false).Verifiable (Times.Exactly (2));
|
|
_parserMock.Setup (p => p.ExpectResponse ("c", It.IsAny<Action<string>> (), null, false)).Verifiable (Times.Exactly (2));
|
|
|
|
_scheduler.SendOrSchedule (request);
|
|
|
|
// Simulate time passing
|
|
SetTime (55); // Does not exceed throttle limit
|
|
|
|
|
|
// Act
|
|
|
|
// Send another request after the throttled time limit
|
|
var result = _scheduler.SendOrSchedule (request);
|
|
|
|
// Assert
|
|
Assert.Single (_scheduler.QueuedRequests); // Should have been queued
|
|
Assert.False(result); // Should have been queued
|
|
|
|
// Throttle still not exceeded
|
|
Assert.False(_scheduler.RunSchedule ());
|
|
|
|
SetTime (90);
|
|
|
|
// Throttle still not exceeded
|
|
Assert.False (_scheduler.RunSchedule ());
|
|
|
|
SetTime (105);
|
|
|
|
// Throttle exceeded - so send the request
|
|
Assert.True (_scheduler.RunSchedule ());
|
|
|
|
_parserMock.Verify ();
|
|
}
|
|
|
|
[Fact]
|
|
public void EvictStaleRequests_RemovesStaleRequest_AfterTimeout ()
|
|
{
|
|
// Arrange
|
|
var request1 = new AnsiEscapeSequenceRequest
|
|
{
|
|
Request = "\u001b[0c",
|
|
Terminator = "c",
|
|
ResponseReceived = r => { }
|
|
};
|
|
|
|
// Send
|
|
_parserMock.Setup (p => p.IsExpecting ("c")).Returns (false).Verifiable (Times.Once);
|
|
_parserMock.Setup (p => p.ExpectResponse ("c", It.IsAny<Action<string>> (), null, false)).Verifiable (Times.Exactly (2));
|
|
|
|
Assert.True (_scheduler.SendOrSchedule (request1));
|
|
|
|
// Parser already has an ongoing request for "c"
|
|
_parserMock.Setup (p => p.IsExpecting ("c")).Returns (true).Verifiable (Times.Exactly (2));
|
|
|
|
// Cannot send because there is already outstanding request
|
|
Assert.False(_scheduler.SendOrSchedule (request1));
|
|
Assert.Single (_scheduler.QueuedRequests);
|
|
|
|
// Simulate request going stale
|
|
SetTime (5001); // Exceeds stale timeout
|
|
|
|
// Parser should be told to give up on this one (evicted)
|
|
_parserMock.Setup (p => p.StopExpecting ("c", false))
|
|
.Callback (() =>
|
|
{
|
|
// When we tell parser to evict - it should now tell us it is no longer expecting
|
|
_parserMock.Setup (p => p.IsExpecting ("c")).Returns (false).Verifiable (Times.Once);
|
|
}).Verifiable ();
|
|
|
|
// When we send again the evicted one should be
|
|
var evicted = _scheduler.RunSchedule ();
|
|
|
|
Assert.True (evicted); // Stale request should be evicted
|
|
Assert.Empty (_scheduler.QueuedRequests);
|
|
|
|
// Assert
|
|
_parserMock.Verify ();
|
|
}
|
|
|
|
[Fact]
|
|
public void RunSchedule_DoesNothing_WhenQueueIsEmpty ()
|
|
{
|
|
// Act
|
|
var result = _scheduler.RunSchedule ();
|
|
|
|
// Assert
|
|
Assert.False (result); // No requests to process
|
|
Assert.Empty (_scheduler.QueuedRequests);
|
|
}
|
|
|
|
[Fact]
|
|
public void SendOrSchedule_ManagesIndependentTerminatorsCorrectly ()
|
|
{
|
|
// Arrange
|
|
var request1 = new AnsiEscapeSequenceRequest { Request = "\u001b[0c", Terminator = "c", ResponseReceived = r => { } };
|
|
var request2 = new AnsiEscapeSequenceRequest { Request = "\u001b[0x", Terminator = "x", ResponseReceived = r => { } };
|
|
|
|
// Already have a 'c' ongoing
|
|
_parserMock.Setup (p => p.IsExpecting ("c")).Returns (true).Verifiable (Times.Once);
|
|
|
|
// 'x' is free
|
|
_parserMock.Setup (p => p.IsExpecting ("x")).Returns (false).Verifiable (Times.Once);
|
|
_parserMock.Setup (p => p.ExpectResponse ("x", It.IsAny<Action<string>> (), null, false)).Verifiable (Times.Once);
|
|
|
|
// Act
|
|
var a = _scheduler.SendOrSchedule (request1);
|
|
var b = _scheduler.SendOrSchedule (request2);
|
|
|
|
// Assert
|
|
Assert.False (a);
|
|
Assert.True (b);
|
|
Assert.Equal(request1, Assert.Single (_scheduler.QueuedRequests));
|
|
_parserMock.Verify ();
|
|
}
|
|
|
|
|
|
private void SetTime (int milliseconds)
|
|
{
|
|
// This simulates the passing of time by setting the Now function to return a specific time.
|
|
var newNow = _staticNow.AddMilliseconds (milliseconds);
|
|
_scheduler.Now = () => newNow;
|
|
}
|
|
} |