Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
2ce7f4e
Fixes #4804. InjectKey Tests with Pipeline Mode hangs forever in the …
BDisp Mar 6, 2026
be016ca
Code cleanup
BDisp Mar 6, 2026
86f567a
Forced to use Console.KeyAvailable due a not reliable GetNumberOfCons…
BDisp Mar 7, 2026
f348350
Call ProcessQueue while _testSource IsAvailable is true
BDisp Mar 7, 2026
9028e4e
Check AnsiPlatform in CI pipelines
BDisp Mar 7, 2026
399370e
Add AnsiPlatform check to all pipeline mode
BDisp Mar 7, 2026
c92d71d
Add IsRunningInTest method
BDisp Mar 7, 2026
e79fcc7
Move static IsRunningInTest method to the internal DriverImpl class
BDisp Mar 7, 2026
2a9c015
Merge branch 'v2_develop' into v2_4804_readfile-hang-fix
BDisp Mar 7, 2026
30a4a3d
Increasing delay time
BDisp Mar 7, 2026
bbd4067
Merge branch 'v2_develop' into v2_4804_readfile-hang-fix
BDisp Mar 7, 2026
5b2b46c
Put delay after call ProcessQueue
BDisp Mar 7, 2026
762d304
Delay before and after call ProcessQueue
BDisp Mar 7, 2026
a906657
Remove faulty code not needed now because the options.AutoProcess is …
BDisp Mar 7, 2026
bd9da52
Increase the delay in the longer test
BDisp Mar 7, 2026
a35a38e
Delay after ProcessQueue
BDisp Mar 7, 2026
a388ac0
Add WaitUntilAsync helper method
BDisp Mar 7, 2026
ed091dc
Testing without delay
BDisp Mar 7, 2026
7657a6a
Change AutoProcess = true
BDisp Mar 7, 2026
4d97378
Rename to DisableDriverRealIO per @tig
BDisp Mar 8, 2026
ffcad71
Fix erroneous information
BDisp Mar 8, 2026
0711d00
Fix erroneous information
BDisp Mar 8, 2026
2e74d52
Revert changes
BDisp Mar 8, 2026
a1f2318
Skip tests
BDisp Mar 8, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Terminal.Gui/App/Clipboard/ClipboardProcessRunner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public static (int exitCode, string result) Process (
{
var output = string.Empty;

if (Console.IsInputRedirected || Console.IsOutputRedirected)
if (DriverImpl.DisableDriverRealIO)
{
return (-1, output);
}
Expand Down
4 changes: 2 additions & 2 deletions Terminal.Gui/Drivers/AnsiDriver/AnsiInput.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,9 @@ public AnsiInput ()
try
{
// Check if we have a real console first
if (!AnsiTerminalHelper.IsAttachedToTerminal (out bool inputAttached, out bool outputAttached))
if (DriverImpl.DisableDriverRealIO)
{
Trace.Lifecycle (nameof (AnsiInput), "Init", $"Console redirected (Output: {outputAttached}, Input: {inputAttached}). Running in degraded mode.");
Trace.Lifecycle (nameof (AnsiInput), "Init", "Console is running unit tests. Running in degraded mode.");

return;
}
Expand Down
6 changes: 3 additions & 3 deletions Terminal.Gui/Drivers/AnsiDriver/AnsiOutput.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ namespace Terminal.Gui.Drivers;
public class AnsiOutput : OutputBase, IOutput
{
// Tracks which underlying platform APIs are in use
private readonly AnsiPlatform _platform;
internal readonly AnsiPlatform _platform;

private Size _consoleSize = new (80, 25);
private IOutputBuffer? _lastBuffer;
Expand All @@ -61,9 +61,9 @@ public AnsiOutput ()
try
{
// Check if we have a real console first
if (!AnsiTerminalHelper.IsAttachedToTerminal (out bool inputAttached, out bool outputAttached))
if (DriverImpl.DisableDriverRealIO)
{
Trace.Lifecycle (nameof (AnsiOutput), "Init", $"Console redirected (Output: {outputAttached}, Input: {inputAttached}). Running in degraded mode.");
Trace.Lifecycle (nameof (AnsiOutput), "Init", "Console is running unit tests. Running in degraded mode.");

return;
}
Expand Down
4 changes: 2 additions & 2 deletions Terminal.Gui/Drivers/DotNetDriver/NetOutput.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public Size GetSize ()
{
try
{
if (Console.IsInputRedirected || Console.IsOutputRedirected)
if (DriverImpl.DisableDriverRealIO)
{
return new Size (80, 25);
}
Expand Down Expand Up @@ -176,7 +176,7 @@ public void Suspend ()
Write (EscSeqUtils.CSI_DisableMouseEvents);

// Check if we have a real console first
if (Console.IsInputRedirected || Console.IsOutputRedirected)
if (DriverImpl.DisableDriverRealIO)
{
Logging.Information ($"Console redirected (Output: {Console.IsOutputRedirected}, Input: {Console.IsInputRedirected}). Running in degraded mode.");

Expand Down
21 changes: 21 additions & 0 deletions Terminal.Gui/Drivers/DriverImpl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,27 @@ public DriverImpl (IComponentFactory componentFactory,

#region Driver Lifecycle

/// <summary>
/// Determines whether the current execution context is within a unit test project.
/// </summary>
/// <remarks>
/// This method leverages <see cref="AppContext"/> switches to ensure compatibility with
/// <b>Native AOT</b> and avoids trimming-related issues associated with reflection.
/// <para>
/// For this to return <c>true</c>, the test project (e.g., xUnit v3) must define the
/// switch in its <c>.csproj</c> file:
/// <code>
/// &lt;ItemGroup&gt;
/// &lt;RuntimeHostConfigurationOption Include="Runtime.IsTestProject" Value="true" Trim="false" /&gt;
/// &lt;/ItemGroup&gt;
/// </code>
/// </para>
/// </remarks>
/// <returns>
/// <see langword="true"/> if the test execution flag is set; otherwise, <see langword="false"/>.
/// </returns>
public static bool DisableDriverRealIO => AppContext.TryGetSwitch ("Runtime.IsTestProject", out bool isTest) && isTest;

/// <inheritdoc/>
public void Init () => throw new NotSupportedException ();

Expand Down
2 changes: 1 addition & 1 deletion Terminal.Gui/Drivers/Input/TestInputSource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public class TestInputSource : IInputSource
/// Initializes a new instance of the <see cref="TestInputSource"/> class.
/// </summary>
/// <param name="timeProvider">The time provider for timestamps.</param>
public TestInputSource (ITimeProvider timeProvider) { TimeProvider = timeProvider; }
public TestInputSource (ITimeProvider timeProvider) => TimeProvider = timeProvider;

/// <inheritdoc/>
public ITimeProvider TimeProvider { get; }
Expand Down
4 changes: 2 additions & 2 deletions Terminal.Gui/Drivers/UnixDriver/UnixTerminalHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,9 @@ public static void Suspend (IOutput output)
output.Write (EscSeqUtils.CSI_DisableMouseEvents);

// Check if we have a real console first
if (!AnsiTerminalHelper.IsAttachedToTerminal (out bool inputAttached, out bool outputAttached))
if (DriverImpl.DisableDriverRealIO)
{
Trace.Lifecycle (nameof (UnixTerminalHelper), "Suspend", $"Console redirected (Output: {outputAttached}, Input: {inputAttached}). Running in degraded mode.");
Trace.Lifecycle (nameof (UnixTerminalHelper), "Suspend", "Console is running unit tests. Running in degraded mode.");

return;
}
Expand Down
9 changes: 8 additions & 1 deletion Tests/IntegrationTests/IntegrationTests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,14 @@
<Optimize>true</Optimize>
</PropertyGroup>

<ItemGroup>
<ItemGroup>
<RuntimeHostConfigurationOption
Include="Runtime.IsTestProject"
Value="true"
Trim="false" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="coverlet.collector">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
Expand Down
9 changes: 8 additions & 1 deletion Tests/StressTests/StressTests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,15 @@
<ImplicitUsings>enable</ImplicitUsings>
<NoLogo>true</NoLogo>
<SuppressNETCoreSdkPreviewMessage>true</SuppressNETCoreSdkPreviewMessage>

</PropertyGroup>

<ItemGroup>
<RuntimeHostConfigurationOption
Include="Runtime.IsTestProject"
Value="true"
Trim="false" />
</ItemGroup>

<PropertyGroup Condition="'$(Configuration)'=='Debug'">
<DefineDebug>true</DefineDebug>
<DefineConstants>$(DefineConstants);DEBUG_IDISPOSABLE</DefineConstants>
Expand Down
8 changes: 8 additions & 0 deletions Tests/UnitTests/UnitTests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,15 @@
<PropertyGroup Condition="'$(Configuration)'=='Release'">
<Optimize>true</Optimize>
</PropertyGroup>

<ItemGroup>
<RuntimeHostConfigurationOption
Include="Runtime.IsTestProject"
Value="true"
Trim="false" />
</ItemGroup>

<ItemGroup>
<Compile Remove="Application\Keyboard\**" />
<Compile Remove="Drivers\**" />
<EmbeddedResource Remove="Application\Keyboard\**" />
Expand Down
10 changes: 7 additions & 3 deletions Tests/UnitTestsParallelizable/Input/InputInjectorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ public void InjectKey_DefaultOptions_UsesDirectMode ()
// BUGBUG: see https://github.com/gui-cs/Terminal.Gui/pull/4583#issuecomment-3769142085

[Fact (Skip = "Using Task.Delay (50) will cause failures in slow CI/CD runners")]
public async Task InjectKey_Pipeline_AccentedKeys_RaisesAllEvents ()
public async Task InjectKey_Pipeline_AutoProcess_False_AccentedKeys_RaisesAllEvents ()
{
// Arrange
VirtualTimeProvider timeProvider = new ();
Expand Down Expand Up @@ -185,7 +185,9 @@ public async Task InjectKey_Pipeline_AccentedKeys_RaisesAllEvents ()
await Task.Delay (50, TestContext.Current.CancellationToken); // Allow some time for processing
injector.ProcessQueue ();

// Assert - Should raise exactly 3 KeyDown events
Assert.Equal (AnsiPlatform.Degraded, ((AnsiOutput)app.Driver?.GetOutput ()!)._platform);

// Assert - Should raise exactly 34 KeyDown events
Assert.Equal (34, receivedKeys.Count);
Assert.Equal (new Key ('á'), receivedKeys [0]);
Assert.Equal (new Key ('é'), receivedKeys [1]);
Expand Down Expand Up @@ -227,7 +229,7 @@ public async Task InjectKey_Pipeline_AccentedKeys_RaisesAllEvents ()
// BUGBUG: when an accented char comes into the actual stdIn stream, only.
// BUGBUG: see https://github.com/gui-cs/Terminal.Gui/pull/4583#issuecomment-3769142085
[Fact (Skip = "Using Task.Delay (50) will cause failures in slow CI/CD runners")]
public async Task InjectKey_PipelineMode_MultipleKeys_RaisesAllEvents ()
public async Task InjectKey_PipelineMode_AutoProcess_True_MultipleKeys_RaisesAllEvents ()
{
// Arrange
VirtualTimeProvider timeProvider = new ();
Expand All @@ -254,6 +256,8 @@ public async Task InjectKey_PipelineMode_MultipleKeys_RaisesAllEvents ()
await Task.Delay (50, TestContext.Current.CancellationToken); // Allow some time for processing
injector.ProcessQueue ();

Assert.Equal (AnsiPlatform.Degraded, ((AnsiOutput)app.Driver?.GetOutput ()!)._platform);

// Assert - Should raise exactly 3 KeyDown events
Assert.Equal (3, receivedKeys.Count);
Assert.Equal (Key.A, receivedKeys [0]);
Expand Down
7 changes: 7 additions & 0 deletions Tests/UnitTestsParallelizable/UnitTests.Parallelizable.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@
<SuppressNETCoreSdkPreviewMessage>true</SuppressNETCoreSdkPreviewMessage>
</PropertyGroup>

<ItemGroup>
<RuntimeHostConfigurationOption
Include="Runtime.IsTestProject"
Value="true"
Trim="false" />
</ItemGroup>

<PropertyGroup Condition="'$(Configuration)'=='Debug'">
<DefineDebug>true</DefineDebug>
<DefineConstants>$(DefineConstants);DEBUG_IDISPOSABLE</DefineConstants>
Expand Down
Loading