mirror of
https://github.com/nsnail/spectre.console.git
synced 2025-04-16 08:52:50 +08:00

When running on .NET Framework, the `Should_Report_Max_Remaining_Time_For_Extremely_Small_Progress` would intermittently fail with the following error: ``` task.RemainingTime should be 10675199.02:48:05.4775807 but was null ``` This is because it's possible that the two increment share the same timestamp thus making the `RemainingTime` null. To ensure the two increments don't share the same timestamp, we sleep for one millisecond. Although I have only observed this issue on .NET Framework it would be possible that it occasionally also occur on .NET Core.
276 lines
8.2 KiB
C#
276 lines
8.2 KiB
C#
using System;
|
||
using System.Threading;
|
||
using System.Threading.Tasks;
|
||
using Shouldly;
|
||
using Spectre.Console.Testing;
|
||
using Spectre.Verify.Extensions;
|
||
using VerifyXunit;
|
||
using Xunit;
|
||
|
||
namespace Spectre.Console.Tests.Unit
|
||
{
|
||
[UsesVerify]
|
||
[ExpectationPath("Live/Progress")]
|
||
public sealed class ProgressTests
|
||
{
|
||
[Fact]
|
||
public void Should_Render_Task_Correctly()
|
||
{
|
||
// Given
|
||
var console = new TestConsole()
|
||
.Width(10)
|
||
.Interactive()
|
||
.EmitAnsiSequences();
|
||
|
||
var progress = new Progress(console)
|
||
.Columns(new[] { new ProgressBarColumn() })
|
||
.AutoRefresh(false)
|
||
.AutoClear(true);
|
||
|
||
// When
|
||
progress.Start(ctx => ctx.AddTask("foo"));
|
||
|
||
// Then
|
||
console.Output
|
||
.NormalizeLineEndings()
|
||
.ShouldBe(
|
||
"[?25l" + // Hide cursor
|
||
" \n" + // Top padding
|
||
"[38;5;8m━━━━━━━━━━[0m\n" + // Task
|
||
" " + // Bottom padding
|
||
"[2K[1A[2K[1A[2K[?25h"); // Clear + show cursor
|
||
}
|
||
|
||
[Fact]
|
||
public void Should_Not_Auto_Clear_If_Specified()
|
||
{
|
||
// Given
|
||
var console = new TestConsole()
|
||
.Width(10)
|
||
.Interactive()
|
||
.EmitAnsiSequences();
|
||
|
||
var progress = new Progress(console)
|
||
.Columns(new[] { new ProgressBarColumn() })
|
||
.AutoRefresh(false)
|
||
.AutoClear(false);
|
||
|
||
// When
|
||
progress.Start(ctx => ctx.AddTask("foo"));
|
||
|
||
// Then
|
||
console.Output
|
||
.NormalizeLineEndings()
|
||
.ShouldBe(
|
||
"[?25l" + // Hide cursor
|
||
" \n" + // Top padding
|
||
"[38;5;8m━━━━━━━━━━[0m\n" + // Task
|
||
" \n" + // Bottom padding
|
||
"[?25h"); // show cursor
|
||
}
|
||
|
||
[Fact]
|
||
[Expectation("Render_ReduceWidth")]
|
||
public Task Should_Reduce_Width_If_Needed()
|
||
{
|
||
// Given
|
||
var console = new TestConsole()
|
||
.Width(20)
|
||
.Interactive();
|
||
|
||
var progress = new Progress(console)
|
||
.Columns(new ProgressColumn[]
|
||
{
|
||
new TaskDescriptionColumn(),
|
||
new ProgressBarColumn(),
|
||
new PercentageColumn(),
|
||
new RemainingTimeColumn(),
|
||
new SpinnerColumn(),
|
||
})
|
||
.AutoRefresh(false)
|
||
.AutoClear(false);
|
||
|
||
// When
|
||
progress.Start(ctx =>
|
||
{
|
||
ctx.AddTask("foo");
|
||
ctx.AddTask("bar");
|
||
ctx.AddTask("baz");
|
||
});
|
||
|
||
// Then
|
||
return Verifier.Verify(console.Output);
|
||
}
|
||
|
||
[Fact]
|
||
public void Setting_Max_Value_Should_Set_The_MaxValue_And_Cap_Value()
|
||
{
|
||
// Given
|
||
var console = new TestConsole()
|
||
.Interactive();
|
||
|
||
var task = default(ProgressTask);
|
||
var progress = new Progress(console)
|
||
.Columns(new[] { new ProgressBarColumn() })
|
||
.AutoRefresh(false)
|
||
.AutoClear(false);
|
||
|
||
// When
|
||
progress.Start(ctx =>
|
||
{
|
||
task = ctx.AddTask("foo");
|
||
task.Increment(100);
|
||
task.MaxValue = 20;
|
||
});
|
||
|
||
// Then
|
||
task.MaxValue.ShouldBe(20);
|
||
task.Value.ShouldBe(20);
|
||
}
|
||
|
||
[Fact]
|
||
public void Setting_Value_Should_Override_Incremented_Value()
|
||
{
|
||
// Given
|
||
var console = new TestConsole()
|
||
.Interactive();
|
||
|
||
var task = default(ProgressTask);
|
||
var progress = new Progress(console)
|
||
.Columns(new[] { new ProgressBarColumn() })
|
||
.AutoRefresh(false)
|
||
.AutoClear(false);
|
||
|
||
// When
|
||
progress.Start(ctx =>
|
||
{
|
||
task = ctx.AddTask("foo");
|
||
task.Increment(50);
|
||
task.Value = 20;
|
||
});
|
||
|
||
// Then
|
||
task.MaxValue.ShouldBe(100);
|
||
task.Value.ShouldBe(20);
|
||
}
|
||
|
||
[Fact]
|
||
public void Setting_Value_To_MaxValue_Should_Finish_Task()
|
||
{
|
||
// Given
|
||
var console = new TestConsole()
|
||
.Interactive();
|
||
|
||
var task = default(ProgressTask);
|
||
var progress = new Progress(console)
|
||
.Columns(new[] { new ProgressBarColumn() })
|
||
.AutoRefresh(false)
|
||
.AutoClear(false);
|
||
|
||
// When
|
||
progress.Start(ctx =>
|
||
{
|
||
task = ctx.AddTask("foo");
|
||
task.Value = task.MaxValue;
|
||
});
|
||
|
||
// Then
|
||
task.IsFinished.ShouldBe(true);
|
||
}
|
||
|
||
[Fact]
|
||
public void Should_Increment_Manually_Set_Value()
|
||
{
|
||
// Given
|
||
var console = new TestConsole()
|
||
.Interactive();
|
||
|
||
var task = default(ProgressTask);
|
||
var progress = new Progress(console)
|
||
.Columns(new[] { new ProgressBarColumn() })
|
||
.AutoRefresh(false)
|
||
.AutoClear(false);
|
||
|
||
// When
|
||
progress.Start(ctx =>
|
||
{
|
||
task = ctx.AddTask("foo");
|
||
task.Value = 50;
|
||
task.Increment(10);
|
||
});
|
||
|
||
// Then
|
||
task.Value.ShouldBe(60);
|
||
}
|
||
|
||
[Fact]
|
||
public void Should_Hide_Completed_Tasks()
|
||
{
|
||
// Given
|
||
var console = new TestConsole()
|
||
.Width(10)
|
||
.Interactive()
|
||
.EmitAnsiSequences();
|
||
|
||
var taskFinished = default(ProgressTask);
|
||
var taskInProgress1 = default(ProgressTask);
|
||
var taskInProgress2 = default(ProgressTask);
|
||
|
||
var progress = new Progress(console)
|
||
.Columns(new[] { new ProgressBarColumn() })
|
||
.AutoRefresh(false)
|
||
.AutoClear(false)
|
||
.HideCompleted(true);
|
||
|
||
// When
|
||
progress.Start(ctx =>
|
||
{
|
||
taskInProgress1 = ctx.AddTask("foo");
|
||
taskFinished = ctx.AddTask("bar");
|
||
taskInProgress2 = ctx.AddTask("baz");
|
||
taskInProgress2.Increment(20);
|
||
taskFinished.Value = taskFinished.MaxValue;
|
||
});
|
||
|
||
// Then
|
||
console.Output
|
||
.NormalizeLineEndings()
|
||
.ShouldBe(
|
||
"[?25l" + // Hide cursor
|
||
" \n" + // top padding
|
||
"[38;5;8m━━━━━━━━━━[0m\n" + // taskInProgress1
|
||
"[38;5;11m━━[0m[38;5;8m━━━━━━━━[0m\n" + // taskInProgress2
|
||
" \n" + // bottom padding
|
||
"[?25h"); // show cursor
|
||
}
|
||
|
||
[Fact]
|
||
public void Should_Report_Max_Remaining_Time_For_Extremely_Small_Progress()
|
||
{
|
||
// Given
|
||
var console = new TestConsole()
|
||
.Interactive();
|
||
|
||
var task = default(ProgressTask);
|
||
var progress = new Progress(console)
|
||
.Columns(new[] { new RemainingTimeColumn() })
|
||
.AutoRefresh(false)
|
||
.AutoClear(false);
|
||
|
||
// When
|
||
progress.Start(ctx =>
|
||
{
|
||
task = ctx.AddTask("foo");
|
||
task.Increment(double.Epsilon);
|
||
// Make sure that at least one millisecond has elapsed between the increments else the RemainingTime is null
|
||
// when the last timestamp is equal to the first timestamp of the samples.
|
||
Thread.Sleep(1);
|
||
task.Increment(double.Epsilon);
|
||
});
|
||
|
||
// Then
|
||
task.RemainingTime.ShouldBe(TimeSpan.MaxValue);
|
||
}
|
||
}
|
||
}
|