mirror of
https://github.com/Tyrrrz/CliFx.git
synced 2025-10-25 15:19:17 +00:00
57
CliFx.Tests/Utilities/ProgressReporterTests.cs
Normal file
57
CliFx.Tests/Utilities/ProgressReporterTests.cs
Normal file
@@ -0,0 +1,57 @@
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using CliFx.Services;
|
||||
using CliFx.Utilities;
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace CliFx.Tests.Utilities
|
||||
{
|
||||
[TestFixture]
|
||||
public class ProgressReporterTests
|
||||
{
|
||||
[Test]
|
||||
public void Report_Test()
|
||||
{
|
||||
// Arrange
|
||||
var formatProvider = CultureInfo.InvariantCulture;
|
||||
|
||||
using (var stdout = new StringWriter(formatProvider))
|
||||
{
|
||||
var console = new VirtualConsole(TextReader.Null, false, stdout, false, TextWriter.Null, false);
|
||||
var reporter = console.CreateProgressReporter();
|
||||
|
||||
var progressValues = Enumerable.Range(0, 100).Select(p => p / 100.0).ToArray();
|
||||
var progressStringValues = progressValues.Select(p => p.ToString("P2", formatProvider)).ToArray();
|
||||
|
||||
// Act
|
||||
foreach (var progress in progressValues)
|
||||
reporter.Report(progress);
|
||||
|
||||
// Assert
|
||||
stdout.ToString().Should().ContainAll(progressStringValues);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Report_Redirected_Test()
|
||||
{
|
||||
// Arrange
|
||||
using (var stdout = new StringWriter())
|
||||
{
|
||||
var console = new VirtualConsole(stdout);
|
||||
var reporter = console.CreateProgressReporter();
|
||||
|
||||
var progressValues = Enumerable.Range(0, 100).Select(p => p / 100.0).ToArray();
|
||||
|
||||
// Act
|
||||
foreach (var progress in progressValues)
|
||||
reporter.Report(progress);
|
||||
|
||||
// Assert
|
||||
stdout.ToString().Should().BeEmpty();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,19 +15,19 @@ namespace CliFx.Services
|
||||
public TextReader Input { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsInputRedirected => true;
|
||||
public bool IsInputRedirected { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public TextWriter Output { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsOutputRedirected => true;
|
||||
public bool IsOutputRedirected { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public TextWriter Error { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsErrorRedirected => true;
|
||||
public bool IsErrorRedirected { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public ConsoleColor ForegroundColor { get; set; } = ConsoleColor.Gray;
|
||||
@@ -38,11 +38,24 @@ namespace CliFx.Services
|
||||
/// <summary>
|
||||
/// Initializes an instance of <see cref="VirtualConsole"/>.
|
||||
/// </summary>
|
||||
public VirtualConsole(TextReader input, TextWriter output, TextWriter error)
|
||||
public VirtualConsole(TextReader input, bool isInputRedirected,
|
||||
TextWriter output, bool isOutputRedirected,
|
||||
TextWriter error, bool isErrorRedirected)
|
||||
{
|
||||
Input = input.GuardNotNull(nameof(input));
|
||||
IsInputRedirected = isInputRedirected;
|
||||
Output = output.GuardNotNull(nameof(output));
|
||||
IsOutputRedirected = isOutputRedirected;
|
||||
Error = error.GuardNotNull(nameof(error));
|
||||
IsErrorRedirected = isErrorRedirected;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes an instance of <see cref="VirtualConsole"/>.
|
||||
/// </summary>
|
||||
public VirtualConsole(TextReader input, TextWriter output, TextWriter error)
|
||||
: this(input, true, output, true, error, true)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
15
CliFx/Utilities/Extensions.cs
Normal file
15
CliFx/Utilities/Extensions.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using CliFx.Services;
|
||||
|
||||
namespace CliFx.Utilities
|
||||
{
|
||||
/// <summary>
|
||||
/// Extensions for <see cref="Utilities"/>.
|
||||
/// </summary>
|
||||
public static class Extensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a progress reporter for this console.
|
||||
/// </summary>
|
||||
public static ProgressReporter CreateProgressReporter(this IConsole console) => new ProgressReporter(console);
|
||||
}
|
||||
}
|
||||
50
CliFx/Utilities/ProgressReporter.cs
Normal file
50
CliFx/Utilities/ProgressReporter.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
using System;
|
||||
using CliFx.Services;
|
||||
|
||||
namespace CliFx.Utilities
|
||||
{
|
||||
/// <summary>
|
||||
/// Utility that provides continuous progress reporting to the console.
|
||||
/// </summary>
|
||||
public class ProgressReporter : IProgress<double>
|
||||
{
|
||||
private readonly IConsole _console;
|
||||
|
||||
private string _lastOutput = "";
|
||||
|
||||
/// <summary>
|
||||
/// Initializes an instance of <see cref="ProgressReporter"/>.
|
||||
/// </summary>
|
||||
public ProgressReporter(IConsole console)
|
||||
{
|
||||
_console = console;
|
||||
}
|
||||
|
||||
private void EraseLastOutput()
|
||||
{
|
||||
for (var i = 0; i < _lastOutput.Length; i++)
|
||||
_console.Output.Write('\b');
|
||||
}
|
||||
|
||||
private void RenderProgress(double progress)
|
||||
{
|
||||
_lastOutput = progress.ToString("P2", _console.Output.FormatProvider);
|
||||
_console.Output.Write(_lastOutput);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reports progress and renders it to console.
|
||||
/// If console's stdout is redirected, this method returns without doing anything.
|
||||
/// </summary>
|
||||
public void Report(double progress)
|
||||
{
|
||||
// We don't do anything if stdout is redirected to avoid polluting output
|
||||
//...when there's no active console window.
|
||||
if (!_console.IsOutputRedirected)
|
||||
{
|
||||
EraseLastOutput();
|
||||
RenderProgress(progress);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
14
Readme.md
14
Readme.md
@@ -27,6 +27,7 @@ _CliFx is to command line interfaces what ASP.NET Core is to web applications._
|
||||
- Generates contextual help text
|
||||
- Prints errors and routes exit codes on exceptions
|
||||
- Highly testable and easy to customize
|
||||
- Contains utilties such as progress reporting
|
||||
- Targets .NET Framework 4.5+ and .NET Standard 2.0+
|
||||
- No external dependencies
|
||||
|
||||
@@ -262,6 +263,19 @@ var app = new CliApplicationBuilder()
|
||||
.Build();
|
||||
```
|
||||
|
||||
### Report progress
|
||||
|
||||
CliFx comes with a simple utility for rendering progress to the console, `ProgressReporter`. It implements a well-known `IProgress<double>` interface so you can pass it to methods that are aware of this abstraction.
|
||||
|
||||
To avoid polluting output when it's not bound to a console, `ProgressReporter` will simply no-op if stdout is redirected.
|
||||
|
||||
```c#
|
||||
var progressReporter = console.CreateProgressReporter();
|
||||
|
||||
for (var i = 0.0; i <= 1; i += 0.01)
|
||||
progressReporter.Report(i);
|
||||
```
|
||||
|
||||
### Testing
|
||||
|
||||
CliFx makes it really easy to test your commands thanks to the `IConsole` interface.
|
||||
|
||||
Reference in New Issue
Block a user