From 0d32876bad1f4cf4172b65ab52f22bf20dbfc7f7 Mon Sep 17 00:00:00 2001 From: Alexey Golub Date: Thu, 20 Aug 2020 16:27:23 +0300 Subject: [PATCH] Add VirtualConsole.CreateBuffered() for easier testing --- CliFx.Tests/ApplicationSpecs.cs | 128 ++++------ CliFx.Tests/ArgumentBindingSpecs.cs | 81 ++---- CliFx.Tests/ArgumentConversionSpecs.cs | 303 ++++++++--------------- CliFx.Tests/CancellationSpecs.cs | 8 +- CliFx.Tests/Commands/DefaultCommand.cs | 2 +- CliFx.Tests/Commands/NamedCommand.cs | 2 +- CliFx.Tests/Commands/NamedSubCommand.cs | 2 +- CliFx.Tests/DirectivesSpecs.cs | 11 +- CliFx.Tests/EnvironmentVariablesSpecs.cs | 24 +- CliFx.Tests/ErrorReportingSpecs.cs | 83 ++----- CliFx.Tests/HelpTextSpecs.cs | 43 ++-- CliFx.Tests/Internal/JsonExtensions.cs | 10 + CliFx.Tests/RoutingSpecs.cs | 79 +++--- CliFx/Utilities/MemoryStreamWriter.cs | 43 ++++ CliFx/VirtualConsole.cs | 21 ++ 15 files changed, 341 insertions(+), 499 deletions(-) create mode 100644 CliFx.Tests/Internal/JsonExtensions.cs create mode 100644 CliFx/Utilities/MemoryStreamWriter.cs diff --git a/CliFx.Tests/ApplicationSpecs.cs b/CliFx.Tests/ApplicationSpecs.cs index b5360fa..eec5c96 100644 --- a/CliFx.Tests/ApplicationSpecs.cs +++ b/CliFx.Tests/ApplicationSpecs.cs @@ -54,8 +54,7 @@ namespace CliFx.Tests [Fact] public async Task At_least_one_command_must_be_defined_in_an_application() { - await using var stdErr = new MemoryStream(); - var console = new VirtualConsole(error: stdErr); + var (console, _, stdErr) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .UseConsole(console) @@ -63,20 +62,18 @@ namespace CliFx.Tests // Act var exitCode = await application.RunAsync(Array.Empty()); - var stdErrData = console.Error.Encoding.GetString(stdErr.ToArray()).TrimEnd(); // Assert exitCode.Should().NotBe(0); - stdErrData.Should().NotBeEmpty(); + stdErr.GetString().Should().NotBeNullOrWhiteSpace(); - _output.WriteLine(stdErrData); + _output.WriteLine(stdErr.GetString()); } [Fact] public async Task Commands_must_implement_the_corresponding_interface() { - await using var stdErr = new MemoryStream(); - var console = new VirtualConsole(error: stdErr); + var (console, _, stdErr) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand(typeof(NonImplementedCommand)) @@ -85,20 +82,18 @@ namespace CliFx.Tests // Act var exitCode = await application.RunAsync(Array.Empty()); - var stdErrData = console.Error.Encoding.GetString(stdErr.ToArray()).TrimEnd(); // Assert exitCode.Should().NotBe(0); - stdErrData.Should().NotBeEmpty(); + stdErr.GetString().Should().NotBeNullOrWhiteSpace(); - _output.WriteLine(stdErrData); + _output.WriteLine(stdErr.GetString()); } [Fact] public async Task Commands_must_be_annotated_by_an_attribute() { - await using var stdErr = new MemoryStream(); - var console = new VirtualConsole(error: stdErr); + var (console, _, stdErr) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -107,20 +102,18 @@ namespace CliFx.Tests // Act var exitCode = await application.RunAsync(Array.Empty()); - var stdErrData = console.Error.Encoding.GetString(stdErr.ToArray()).TrimEnd(); // Assert exitCode.Should().NotBe(0); - stdErrData.Should().NotBeEmpty(); + stdErr.GetString().Should().NotBeNullOrWhiteSpace(); - _output.WriteLine(stdErrData); + _output.WriteLine(stdErr.GetString()); } [Fact] public async Task Commands_must_have_unique_names() { - await using var stdErr = new MemoryStream(); - var console = new VirtualConsole(error: stdErr); + var (console, _, stdErr) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -130,20 +123,18 @@ namespace CliFx.Tests // Act var exitCode = await application.RunAsync(Array.Empty()); - var stdErrData = console.Error.Encoding.GetString(stdErr.ToArray()).TrimEnd(); // Assert exitCode.Should().NotBe(0); - stdErrData.Should().NotBeEmpty(); + stdErr.GetString().Should().NotBeNullOrWhiteSpace(); - _output.WriteLine(stdErrData); + _output.WriteLine(stdErr.GetString()); } [Fact] public async Task Command_can_be_default_but_only_if_it_is_the_only_such_command() { - await using var stdErr = new MemoryStream(); - var console = new VirtualConsole(error: stdErr); + var (console, _, stdErr) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -153,20 +144,18 @@ namespace CliFx.Tests // Act var exitCode = await application.RunAsync(Array.Empty()); - var stdErrData = console.Error.Encoding.GetString(stdErr.ToArray()).TrimEnd(); // Assert exitCode.Should().NotBe(0); - stdErrData.Should().NotBeEmpty(); + stdErr.GetString().Should().NotBeNullOrWhiteSpace(); - _output.WriteLine(stdErrData); + _output.WriteLine(stdErr.GetString()); } [Fact] public async Task Command_parameters_must_have_unique_order() { - await using var stdErr = new MemoryStream(); - var console = new VirtualConsole(error: stdErr); + var (console, _, stdErr) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -175,20 +164,18 @@ namespace CliFx.Tests // Act var exitCode = await application.RunAsync(Array.Empty()); - var stdErrData = console.Error.Encoding.GetString(stdErr.ToArray()).TrimEnd(); // Assert exitCode.Should().NotBe(0); - stdErrData.Should().NotBeEmpty(); + stdErr.GetString().Should().NotBeNullOrWhiteSpace(); - _output.WriteLine(stdErrData); + _output.WriteLine(stdErr.GetString()); } [Fact] public async Task Command_parameters_must_have_unique_names() { - await using var stdErr = new MemoryStream(); - var console = new VirtualConsole(error: stdErr); + var (console, _, stdErr) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -197,20 +184,18 @@ namespace CliFx.Tests // Act var exitCode = await application.RunAsync(Array.Empty()); - var stdErrData = console.Error.Encoding.GetString(stdErr.ToArray()).TrimEnd(); // Assert exitCode.Should().NotBe(0); - stdErrData.Should().NotBeEmpty(); + stdErr.GetString().Should().NotBeNullOrWhiteSpace(); - _output.WriteLine(stdErrData); + _output.WriteLine(stdErr.GetString()); } [Fact] public async Task Command_parameter_can_be_non_scalar_only_if_no_other_such_parameter_is_present() { - await using var stdErr = new MemoryStream(); - var console = new VirtualConsole(error: stdErr); + var (console, _, stdErr) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -219,20 +204,18 @@ namespace CliFx.Tests // Act var exitCode = await application.RunAsync(Array.Empty()); - var stdErrData = console.Error.Encoding.GetString(stdErr.ToArray()).TrimEnd(); // Assert exitCode.Should().NotBe(0); - stdErrData.Should().NotBeEmpty(); + stdErr.GetString().Should().NotBeNullOrWhiteSpace(); - _output.WriteLine(stdErrData); + _output.WriteLine(stdErr.GetString()); } [Fact] public async Task Command_parameter_can_be_non_scalar_only_if_it_is_the_last_in_order() { - await using var stdErr = new MemoryStream(); - var console = new VirtualConsole(error: stdErr); + var (console, _, stdErr) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -241,20 +224,18 @@ namespace CliFx.Tests // Act var exitCode = await application.RunAsync(Array.Empty()); - var stdErrData = console.Error.Encoding.GetString(stdErr.ToArray()).TrimEnd(); // Assert exitCode.Should().NotBe(0); - stdErrData.Should().NotBeEmpty(); + stdErr.GetString().Should().NotBeNullOrWhiteSpace(); - _output.WriteLine(stdErrData); + _output.WriteLine(stdErr.GetString()); } [Fact] public async Task Command_options_must_have_names_that_are_not_empty() { - await using var stdErr = new MemoryStream(); - var console = new VirtualConsole(error: stdErr); + var (console, _, stdErr) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -263,20 +244,18 @@ namespace CliFx.Tests // Act var exitCode = await application.RunAsync(Array.Empty()); - var stdErrData = console.Error.Encoding.GetString(stdErr.ToArray()).TrimEnd(); // Assert exitCode.Should().NotBe(0); - stdErrData.Should().NotBeEmpty(); + stdErr.GetString().Should().NotBeNullOrWhiteSpace(); - _output.WriteLine(stdErrData); + _output.WriteLine(stdErr.GetString()); } [Fact] public async Task Command_options_must_have_names_that_are_longer_than_one_character() { - await using var stdErr = new MemoryStream(); - var console = new VirtualConsole(error: stdErr); + var (console, _, stdErr) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -285,20 +264,18 @@ namespace CliFx.Tests // Act var exitCode = await application.RunAsync(Array.Empty()); - var stdErrData = console.Error.Encoding.GetString(stdErr.ToArray()).TrimEnd(); // Assert exitCode.Should().NotBe(0); - stdErrData.Should().NotBeEmpty(); + stdErr.GetString().Should().NotBeNullOrWhiteSpace(); - _output.WriteLine(stdErrData); + _output.WriteLine(stdErr.GetString()); } [Fact] public async Task Command_options_must_have_unique_names() { - await using var stdErr = new MemoryStream(); - var console = new VirtualConsole(error: stdErr); + var (console, _, stdErr) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -307,20 +284,18 @@ namespace CliFx.Tests // Act var exitCode = await application.RunAsync(Array.Empty()); - var stdErrData = console.Error.Encoding.GetString(stdErr.ToArray()).TrimEnd(); // Assert exitCode.Should().NotBe(0); - stdErrData.Should().NotBeEmpty(); + stdErr.GetString().Should().NotBeNullOrWhiteSpace(); - _output.WriteLine(stdErrData); + _output.WriteLine(stdErr.GetString()); } [Fact] public async Task Command_options_must_have_unique_short_names() { - await using var stdErr = new MemoryStream(); - var console = new VirtualConsole(error: stdErr); + var (console, _, stdErr) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -329,20 +304,18 @@ namespace CliFx.Tests // Act var exitCode = await application.RunAsync(Array.Empty()); - var stdErrData = console.Error.Encoding.GetString(stdErr.ToArray()).TrimEnd(); // Assert exitCode.Should().NotBe(0); - stdErrData.Should().NotBeEmpty(); + stdErr.GetString().Should().NotBeNullOrWhiteSpace(); - _output.WriteLine(stdErrData); + _output.WriteLine(stdErr.GetString()); } [Fact] public async Task Command_options_must_have_unique_environment_variable_names() { - await using var stdErr = new MemoryStream(); - var console = new VirtualConsole(error: stdErr); + var (console, _, stdErr) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -351,20 +324,18 @@ namespace CliFx.Tests // Act var exitCode = await application.RunAsync(Array.Empty()); - var stdErrData = console.Error.Encoding.GetString(stdErr.ToArray()).TrimEnd(); // Assert exitCode.Should().NotBe(0); - stdErrData.Should().NotBeEmpty(); + stdErr.GetString().Should().NotBeNullOrWhiteSpace(); - _output.WriteLine(stdErrData); + _output.WriteLine(stdErr.GetString()); } [Fact] public async Task Command_options_must_not_have_conflicts_with_the_implicit_help_option() { - await using var stdErr = new MemoryStream(); - var console = new VirtualConsole(error: stdErr); + var (console, _, stdErr) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -373,20 +344,18 @@ namespace CliFx.Tests // Act var exitCode = await application.RunAsync(Array.Empty()); - var stdErrData = console.Error.Encoding.GetString(stdErr.ToArray()).TrimEnd(); // Assert exitCode.Should().NotBe(0); - stdErrData.Should().NotBeEmpty(); + stdErr.GetString().Should().NotBeNullOrWhiteSpace(); - _output.WriteLine(stdErrData); + _output.WriteLine(stdErr.GetString()); } [Fact] public async Task Command_options_must_not_have_conflicts_with_the_implicit_version_option() { - await using var stdErr = new MemoryStream(); - var console = new VirtualConsole(error: stdErr); + var (console, _, stdErr) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -395,13 +364,12 @@ namespace CliFx.Tests // Act var exitCode = await application.RunAsync(Array.Empty()); - var stdErrData = console.Error.Encoding.GetString(stdErr.ToArray()).TrimEnd(); // Assert exitCode.Should().NotBe(0); - stdErrData.Should().NotBeEmpty(); + stdErr.GetString().Should().NotBeNullOrWhiteSpace(); - _output.WriteLine(stdErrData); + _output.WriteLine(stdErr.GetString()); } } } \ No newline at end of file diff --git a/CliFx.Tests/ArgumentBindingSpecs.cs b/CliFx.Tests/ArgumentBindingSpecs.cs index 503f868..875195a 100644 --- a/CliFx.Tests/ArgumentBindingSpecs.cs +++ b/CliFx.Tests/ArgumentBindingSpecs.cs @@ -1,9 +1,7 @@ -using System.IO; -using System.Threading.Tasks; -using CliFx.Exceptions; +using System.Threading.Tasks; using CliFx.Tests.Commands; +using CliFx.Tests.Internal; using FluentAssertions; -using Newtonsoft.Json; using Xunit; using Xunit.Abstractions; @@ -19,8 +17,7 @@ namespace CliFx.Tests public async Task Property_annotated_as_an_option_can_be_bound_from_multiple_values_even_if_the_inputs_use_mixed_naming() { // Arrange - await using var stdOut = new MemoryStream(); - var console = new VirtualConsole(output: stdOut); + var (console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -33,8 +30,7 @@ namespace CliFx.Tests "cmd", "--opt", "foo", "-o", "bar", "--opt", "baz" }); - var stdOutData = console.Output.Encoding.GetString(stdOut.ToArray()).TrimEnd(); - var commandInstance = JsonConvert.DeserializeObject(stdOutData); + var commandInstance = stdOut.GetString().DeserializeJson(); // Assert exitCode.Should().Be(0); @@ -49,8 +45,7 @@ namespace CliFx.Tests public async Task Property_annotated_as_a_required_option_must_always_be_set() { // Arrange - await using var stdErr = new MemoryStream(); - var console = new VirtualConsole(error: stdErr); + var (console, _, stdErr) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -63,21 +58,18 @@ namespace CliFx.Tests "cmd", "--opt-a", "foo" }); - var stdErrData = console.Error.Encoding.GetString(stdErr.ToArray()).TrimEnd(); - // Assert exitCode.Should().NotBe(0); - stdErrData.Should().NotBeEmpty(); + stdErr.GetString().Should().NotBeNullOrWhiteSpace(); - _output.WriteLine(stdErrData); + _output.WriteLine(stdErr.GetString()); } [Fact] public async Task Property_annotated_as_a_required_option_must_always_be_bound_to_some_value() { // Arrange - await using var stdErr = new MemoryStream(); - var console = new VirtualConsole(error: stdErr); + var (console, _, stdErr) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -90,21 +82,18 @@ namespace CliFx.Tests "cmd", "--opt-a" }); - var stdErrData = console.Error.Encoding.GetString(stdErr.ToArray()).TrimEnd(); - // Assert exitCode.Should().NotBe(0); - stdErrData.Should().NotBeEmpty(); + stdErr.GetString().Should().NotBeNullOrWhiteSpace(); - _output.WriteLine(stdErrData); + _output.WriteLine(stdErr.GetString()); } [Fact] public async Task Property_annotated_as_a_required_option_must_always_be_bound_to_at_least_one_value_if_it_expects_multiple_values() { // Arrange - await using var stdErr = new MemoryStream(); - var console = new VirtualConsole(error: stdErr); + var (console, _, stdErr) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -117,21 +106,18 @@ namespace CliFx.Tests "cmd", "--opt-a", "foo" }); - var stdErrData = console.Error.Encoding.GetString(stdErr.ToArray()).TrimEnd(); - // Assert exitCode.Should().NotBe(0); - stdErrData.Should().NotBeEmpty(); + stdErr.GetString().Should().NotBeNullOrWhiteSpace(); - _output.WriteLine(stdErrData); + _output.WriteLine(stdErr.GetString()); } [Fact] public async Task Property_annotated_as_parameter_is_bound_directly_from_argument_value_according_to_the_order() { // Arrange - await using var stdOut = new MemoryStream(); - var console = new VirtualConsole(output: stdOut); + var (console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -144,8 +130,7 @@ namespace CliFx.Tests "cmd", "foo", "13", "bar", "baz" }); - var stdOutData = console.Output.Encoding.GetString(stdOut.ToArray()).TrimEnd(); - var commandInstance = JsonConvert.DeserializeObject(stdOutData); + var commandInstance = stdOut.GetString().DeserializeJson(); // Assert exitCode.Should().Be(0); @@ -162,8 +147,7 @@ namespace CliFx.Tests public async Task Property_annotated_as_parameter_must_always_be_bound_to_some_value() { // Arrange - await using var stdErr = new MemoryStream(); - var console = new VirtualConsole(error: stdErr); + var (console, _, stdErr) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -176,21 +160,18 @@ namespace CliFx.Tests "cmd" }); - var stdErrData = console.Error.Encoding.GetString(stdErr.ToArray()).TrimEnd(); - // Assert exitCode.Should().NotBe(0); - stdErrData.Should().NotBeEmpty(); + stdErr.GetString().Should().NotBeNullOrWhiteSpace(); - _output.WriteLine(stdErrData); + _output.WriteLine(stdErr.GetString()); } [Fact] public async Task Property_annotated_as_parameter_must_always_be_bound_to_at_least_one_value_if_it_expects_multiple_values() { // Arrange - await using var stdErr = new MemoryStream(); - var console = new VirtualConsole(error: stdErr); + var (console, _, stdErr) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -203,21 +184,18 @@ namespace CliFx.Tests "cmd", "foo", "13" }); - var stdErrData = console.Error.Encoding.GetString(stdErr.ToArray()).TrimEnd(); - // Assert exitCode.Should().NotBe(0); - stdErrData.Should().NotBeEmpty(); + stdErr.GetString().Should().NotBeNullOrWhiteSpace(); - _output.WriteLine(stdErrData); + _output.WriteLine(stdErr.GetString()); } [Fact] public async Task All_provided_option_arguments_must_be_bound_to_corresponding_properties() { // Arrange - await using var stdErr = new MemoryStream(); - var console = new VirtualConsole(error: stdErr); + var (console, _, stdErr) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -230,21 +208,18 @@ namespace CliFx.Tests "cmd", "--non-existing-option", "13" }); - var stdErrData = console.Error.Encoding.GetString(stdErr.ToArray()).TrimEnd(); - // Assert exitCode.Should().NotBe(0); - stdErrData.Should().NotBeEmpty(); + stdErr.GetString().Should().NotBeNullOrWhiteSpace(); - _output.WriteLine(stdErrData); + _output.WriteLine(stdErr.GetString()); } [Fact] public async Task All_provided_parameter_arguments_must_be_bound_to_corresponding_properties() { // Arrange - await using var stdErr = new MemoryStream(); - var console = new VirtualConsole(error: stdErr); + var (console, _, stdErr) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -257,13 +232,11 @@ namespace CliFx.Tests "cnd", "non-existing-parameter" }); - var stdErrData = console.Error.Encoding.GetString(stdErr.ToArray()).TrimEnd(); - // Assert exitCode.Should().NotBe(0); - stdErrData.Should().NotBeEmpty(); + stdErr.GetString().Should().NotBeNullOrWhiteSpace(); - _output.WriteLine(stdErrData); + _output.WriteLine(stdErr.GetString()); } } } \ No newline at end of file diff --git a/CliFx.Tests/ArgumentConversionSpecs.cs b/CliFx.Tests/ArgumentConversionSpecs.cs index 62844dd..9efe00d 100644 --- a/CliFx.Tests/ArgumentConversionSpecs.cs +++ b/CliFx.Tests/ArgumentConversionSpecs.cs @@ -1,11 +1,10 @@ using System; using System.Collections.Generic; using System.Globalization; -using System.IO; using System.Threading.Tasks; using CliFx.Tests.Commands; +using CliFx.Tests.Internal; using FluentAssertions; -using Newtonsoft.Json; using Xunit; using Xunit.Abstractions; @@ -21,8 +20,7 @@ namespace CliFx.Tests public async Task Property_of_type_object_is_bound_directly_from_the_argument_value() { // Arrange - await using var stdOut = new MemoryStream(); - var console = new VirtualConsole(output: stdOut); + var (console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -35,8 +33,7 @@ namespace CliFx.Tests "cmd", "--obj", "value" }); - var stdOutData = console.Output.Encoding.GetString(stdOut.ToArray()).TrimEnd(); - var commandInstance = JsonConvert.DeserializeObject(stdOutData); + var commandInstance = stdOut.GetString().DeserializeJson(); // Assert exitCode.Should().Be(0); @@ -51,8 +48,7 @@ namespace CliFx.Tests public async Task Property_of_type_object_array_is_bound_directly_from_the_argument_values() { // Arrange - await using var stdOut = new MemoryStream(); - var console = new VirtualConsole(output: stdOut); + var (console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -65,8 +61,7 @@ namespace CliFx.Tests "cmd", "--obj-array", "foo", "bar" }); - var stdOutData = console.Output.Encoding.GetString(stdOut.ToArray()).TrimEnd(); - var commandInstance = JsonConvert.DeserializeObject(stdOutData); + var commandInstance = stdOut.GetString().DeserializeJson(); // Assert exitCode.Should().Be(0); @@ -81,8 +76,7 @@ namespace CliFx.Tests public async Task Property_of_type_string_is_bound_directly_from_the_argument_value() { // Arrange - await using var stdOut = new MemoryStream(); - var console = new VirtualConsole(output: stdOut); + var (console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -95,8 +89,7 @@ namespace CliFx.Tests "cmd", "--str", "value" }); - var stdOutData = console.Output.Encoding.GetString(stdOut.ToArray()).TrimEnd(); - var commandInstance = JsonConvert.DeserializeObject(stdOutData); + var commandInstance = stdOut.GetString().DeserializeJson(); // Assert exitCode.Should().Be(0); @@ -111,8 +104,7 @@ namespace CliFx.Tests public async Task Property_of_type_string_array_is_bound_directly_from_the_argument_values() { // Arrange - await using var stdOut = new MemoryStream(); - var console = new VirtualConsole(output: stdOut); + var (console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -125,8 +117,7 @@ namespace CliFx.Tests "cmd", "--str-array", "foo", "bar" }); - var stdOutData = console.Output.Encoding.GetString(stdOut.ToArray()).TrimEnd(); - var commandInstance = JsonConvert.DeserializeObject(stdOutData); + var commandInstance = stdOut.GetString().DeserializeJson(); // Assert exitCode.Should().Be(0); @@ -141,8 +132,7 @@ namespace CliFx.Tests public async Task Property_of_type_string_IEnumerable_is_bound_directly_from_the_argument_values() { // Arrange - await using var stdOut = new MemoryStream(); - var console = new VirtualConsole(output: stdOut); + var (console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -155,8 +145,7 @@ namespace CliFx.Tests "cmd", "--str-enumerable", "foo", "bar" }); - var stdOutData = console.Output.Encoding.GetString(stdOut.ToArray()).TrimEnd(); - var commandInstance = JsonConvert.DeserializeObject(stdOutData); + var commandInstance = stdOut.GetString().DeserializeJson(); // Assert exitCode.Should().Be(0); @@ -171,8 +160,7 @@ namespace CliFx.Tests public async Task Property_of_type_string_IReadOnlyList_is_bound_directly_from_the_argument_values() { // Arrange - await using var stdOut = new MemoryStream(); - var console = new VirtualConsole(output: stdOut); + var (console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -185,8 +173,7 @@ namespace CliFx.Tests "cmd", "--str-read-only-list", "foo", "bar" }); - var stdOutData = console.Output.Encoding.GetString(stdOut.ToArray()).TrimEnd(); - var commandInstance = JsonConvert.DeserializeObject(stdOutData); + var commandInstance = stdOut.GetString().DeserializeJson(); // Assert exitCode.Should().Be(0); @@ -201,8 +188,7 @@ namespace CliFx.Tests public async Task Property_of_type_string_List_is_bound_directly_from_the_argument_values() { // Arrange - await using var stdOut = new MemoryStream(); - var console = new VirtualConsole(output: stdOut); + var (console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -215,8 +201,7 @@ namespace CliFx.Tests "cmd", "--str-list", "foo", "bar" }); - var stdOutData = console.Output.Encoding.GetString(stdOut.ToArray()).TrimEnd(); - var commandInstance = JsonConvert.DeserializeObject(stdOutData); + var commandInstance = stdOut.GetString().DeserializeJson(); // Assert exitCode.Should().Be(0); @@ -231,8 +216,7 @@ namespace CliFx.Tests public async Task Property_of_type_string_HashSet_is_bound_directly_from_the_argument_values() { // Arrange - await using var stdOut = new MemoryStream(); - var console = new VirtualConsole(output: stdOut); + var (console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -245,8 +229,7 @@ namespace CliFx.Tests "cmd", "--str-set", "foo", "bar" }); - var stdOutData = console.Output.Encoding.GetString(stdOut.ToArray()).TrimEnd(); - var commandInstance = JsonConvert.DeserializeObject(stdOutData); + var commandInstance = stdOut.GetString().DeserializeJson(); // Assert exitCode.Should().Be(0); @@ -261,8 +244,7 @@ namespace CliFx.Tests public async Task Property_of_type_bool_is_bound_as_true_if_the_argument_value_is_true() { // Arrange - await using var stdOut = new MemoryStream(); - var console = new VirtualConsole(output: stdOut); + var (console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -275,8 +257,7 @@ namespace CliFx.Tests "cmd", "--bool", "true" }); - var stdOutData = console.Output.Encoding.GetString(stdOut.ToArray()).TrimEnd(); - var commandInstance = JsonConvert.DeserializeObject(stdOutData); + var commandInstance = stdOut.GetString().DeserializeJson(); // Assert exitCode.Should().Be(0); @@ -291,8 +272,7 @@ namespace CliFx.Tests public async Task Property_of_type_bool_is_bound_as_false_if_the_argument_value_is_false() { // Arrange - await using var stdOut = new MemoryStream(); - var console = new VirtualConsole(output: stdOut); + var (console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -305,8 +285,7 @@ namespace CliFx.Tests "cmd", "--bool", "false" }); - var stdOutData = console.Output.Encoding.GetString(stdOut.ToArray()).TrimEnd(); - var commandInstance = JsonConvert.DeserializeObject(stdOutData); + var commandInstance = stdOut.GetString().DeserializeJson(); // Assert exitCode.Should().Be(0); @@ -321,8 +300,7 @@ namespace CliFx.Tests public async Task Property_of_type_bool_is_bound_as_true_if_the_argument_value_is_not_set() { // Arrange - await using var stdOut = new MemoryStream(); - var console = new VirtualConsole(output: stdOut); + var (console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -335,8 +313,7 @@ namespace CliFx.Tests "cmd", "--bool" }); - var stdOutData = console.Output.Encoding.GetString(stdOut.ToArray()).TrimEnd(); - var commandInstance = JsonConvert.DeserializeObject(stdOutData); + var commandInstance = stdOut.GetString().DeserializeJson(); // Assert exitCode.Should().Be(0); @@ -351,8 +328,7 @@ namespace CliFx.Tests public async Task Property_of_type_char_is_bound_directly_from_the_argument_value_if_it_contains_only_one_character() { // Arrange - await using var stdOut = new MemoryStream(); - var console = new VirtualConsole(output: stdOut); + var (console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -365,8 +341,7 @@ namespace CliFx.Tests "cmd", "--char", "a" }); - var stdOutData = console.Output.Encoding.GetString(stdOut.ToArray()).TrimEnd(); - var commandInstance = JsonConvert.DeserializeObject(stdOutData); + var commandInstance = stdOut.GetString().DeserializeJson(); // Assert exitCode.Should().Be(0); @@ -381,8 +356,7 @@ namespace CliFx.Tests public async Task Property_of_type_sbyte_is_bound_by_parsing_the_argument_value() { // Arrange - await using var stdOut = new MemoryStream(); - var console = new VirtualConsole(output: stdOut); + var (console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -395,8 +369,7 @@ namespace CliFx.Tests "cmd", "--sbyte", "15" }); - var stdOutData = console.Output.Encoding.GetString(stdOut.ToArray()).TrimEnd(); - var commandInstance = JsonConvert.DeserializeObject(stdOutData); + var commandInstance = stdOut.GetString().DeserializeJson(); // Assert exitCode.Should().Be(0); @@ -411,8 +384,7 @@ namespace CliFx.Tests public async Task Property_of_type_byte_is_bound_by_parsing_the_argument_value() { // Arrange - await using var stdOut = new MemoryStream(); - var console = new VirtualConsole(output: stdOut); + var (console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -425,8 +397,7 @@ namespace CliFx.Tests "cmd", "--byte", "15" }); - var stdOutData = console.Output.Encoding.GetString(stdOut.ToArray()).TrimEnd(); - var commandInstance = JsonConvert.DeserializeObject(stdOutData); + var commandInstance = stdOut.GetString().DeserializeJson(); // Assert exitCode.Should().Be(0); @@ -441,8 +412,7 @@ namespace CliFx.Tests public async Task Property_of_type_short_is_bound_by_parsing_the_argument_value() { // Arrange - await using var stdOut = new MemoryStream(); - var console = new VirtualConsole(output: stdOut); + var (console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -455,8 +425,7 @@ namespace CliFx.Tests "cmd", "--short", "15" }); - var stdOutData = console.Output.Encoding.GetString(stdOut.ToArray()).TrimEnd(); - var commandInstance = JsonConvert.DeserializeObject(stdOutData); + var commandInstance = stdOut.GetString().DeserializeJson(); // Assert exitCode.Should().Be(0); @@ -471,8 +440,7 @@ namespace CliFx.Tests public async Task Property_of_type_ushort_is_bound_by_parsing_the_argument_value() { // Arrange - await using var stdOut = new MemoryStream(); - var console = new VirtualConsole(output: stdOut); + var (console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -485,8 +453,7 @@ namespace CliFx.Tests "cmd", "--ushort", "15" }); - var stdOutData = console.Output.Encoding.GetString(stdOut.ToArray()).TrimEnd(); - var commandInstance = JsonConvert.DeserializeObject(stdOutData); + var commandInstance = stdOut.GetString().DeserializeJson(); // Assert exitCode.Should().Be(0); @@ -501,8 +468,7 @@ namespace CliFx.Tests public async Task Property_of_type_int_is_bound_by_parsing_the_argument_value() { // Arrange - await using var stdOut = new MemoryStream(); - var console = new VirtualConsole(output: stdOut); + var (console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -515,8 +481,7 @@ namespace CliFx.Tests "cmd", "--int", "15" }); - var stdOutData = console.Output.Encoding.GetString(stdOut.ToArray()).TrimEnd(); - var commandInstance = JsonConvert.DeserializeObject(stdOutData); + var commandInstance = stdOut.GetString().DeserializeJson(); // Assert exitCode.Should().Be(0); @@ -531,8 +496,7 @@ namespace CliFx.Tests public async Task Property_of_type_nullable_int_is_bound_by_parsing_the_argument_value_if_it_is_set() { // Arrange - await using var stdOut = new MemoryStream(); - var console = new VirtualConsole(output: stdOut); + var (console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -545,8 +509,7 @@ namespace CliFx.Tests "cmd", "--int-nullable", "15" }); - var stdOutData = console.Output.Encoding.GetString(stdOut.ToArray()).TrimEnd(); - var commandInstance = JsonConvert.DeserializeObject(stdOutData); + var commandInstance = stdOut.GetString().DeserializeJson(); // Assert exitCode.Should().Be(0); @@ -561,8 +524,7 @@ namespace CliFx.Tests public async Task Property_of_type_nullable_int_is_bound_as_null_if_the_argument_value_is_not_set() { // Arrange - await using var stdOut = new MemoryStream(); - var console = new VirtualConsole(output: stdOut); + var (console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -575,8 +537,7 @@ namespace CliFx.Tests "cmd", "--int-nullable" }); - var stdOutData = console.Output.Encoding.GetString(stdOut.ToArray()).TrimEnd(); - var commandInstance = JsonConvert.DeserializeObject(stdOutData); + var commandInstance = stdOut.GetString().DeserializeJson(); // Assert exitCode.Should().Be(0); @@ -591,8 +552,7 @@ namespace CliFx.Tests public async Task Property_of_type_int_array_is_bound_by_parsing_the_argument_values() { // Arrange - await using var stdOut = new MemoryStream(); - var console = new VirtualConsole(output: stdOut); + var (console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -605,8 +565,7 @@ namespace CliFx.Tests "cmd", "--int-array", "3", "15" }); - var stdOutData = console.Output.Encoding.GetString(stdOut.ToArray()).TrimEnd(); - var commandInstance = JsonConvert.DeserializeObject(stdOutData); + var commandInstance = stdOut.GetString().DeserializeJson(); // Assert exitCode.Should().Be(0); @@ -621,8 +580,7 @@ namespace CliFx.Tests public async Task Property_of_type_nullable_int_array_is_bound_by_parsing_the_argument_values() { // Arrange - await using var stdOut = new MemoryStream(); - var console = new VirtualConsole(output: stdOut); + var (console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -635,8 +593,7 @@ namespace CliFx.Tests "cmd", "--int-nullable-array", "3", "15" }); - var stdOutData = console.Output.Encoding.GetString(stdOut.ToArray()).TrimEnd(); - var commandInstance = JsonConvert.DeserializeObject(stdOutData); + var commandInstance = stdOut.GetString().DeserializeJson(); // Assert exitCode.Should().Be(0); @@ -651,8 +608,7 @@ namespace CliFx.Tests public async Task Property_of_type_uint_is_bound_by_parsing_the_argument_value() { // Arrange - await using var stdOut = new MemoryStream(); - var console = new VirtualConsole(output: stdOut); + var (console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -665,8 +621,7 @@ namespace CliFx.Tests "cmd", "--uint", "15" }); - var stdOutData = console.Output.Encoding.GetString(stdOut.ToArray()).TrimEnd(); - var commandInstance = JsonConvert.DeserializeObject(stdOutData); + var commandInstance = stdOut.GetString().DeserializeJson(); // Assert exitCode.Should().Be(0); @@ -681,8 +636,7 @@ namespace CliFx.Tests public async Task Property_of_type_long_is_bound_by_parsing_the_argument_value() { // Arrange - await using var stdOut = new MemoryStream(); - var console = new VirtualConsole(output: stdOut); + var (console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -695,8 +649,7 @@ namespace CliFx.Tests "cmd", "--long", "15" }); - var stdOutData = console.Output.Encoding.GetString(stdOut.ToArray()).TrimEnd(); - var commandInstance = JsonConvert.DeserializeObject(stdOutData); + var commandInstance = stdOut.GetString().DeserializeJson(); // Assert exitCode.Should().Be(0); @@ -711,8 +664,7 @@ namespace CliFx.Tests public async Task Property_of_type_ulong_is_bound_by_parsing_the_argument_value() { // Arrange - await using var stdOut = new MemoryStream(); - var console = new VirtualConsole(output: stdOut); + var (console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -725,8 +677,7 @@ namespace CliFx.Tests "cmd", "--ulong", "15" }); - var stdOutData = console.Output.Encoding.GetString(stdOut.ToArray()).TrimEnd(); - var commandInstance = JsonConvert.DeserializeObject(stdOutData); + var commandInstance = stdOut.GetString().DeserializeJson(); // Assert exitCode.Should().Be(0); @@ -741,8 +692,7 @@ namespace CliFx.Tests public async Task Property_of_type_float_is_bound_by_parsing_the_argument_value() { // Arrange - await using var stdOut = new MemoryStream(); - var console = new VirtualConsole(output: stdOut); + var (console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -755,8 +705,7 @@ namespace CliFx.Tests "cmd", "--float", "3.14" }); - var stdOutData = console.Output.Encoding.GetString(stdOut.ToArray()).TrimEnd(); - var commandInstance = JsonConvert.DeserializeObject(stdOutData); + var commandInstance = stdOut.GetString().DeserializeJson(); // Assert exitCode.Should().Be(0); @@ -771,8 +720,7 @@ namespace CliFx.Tests public async Task Property_of_type_double_is_bound_by_parsing_the_argument_value() { // Arrange - await using var stdOut = new MemoryStream(); - var console = new VirtualConsole(output: stdOut); + var (console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -785,8 +733,7 @@ namespace CliFx.Tests "cmd", "--double", "3.14" }); - var stdOutData = console.Output.Encoding.GetString(stdOut.ToArray()).TrimEnd(); - var commandInstance = JsonConvert.DeserializeObject(stdOutData); + var commandInstance = stdOut.GetString().DeserializeJson(); // Assert exitCode.Should().Be(0); @@ -801,8 +748,7 @@ namespace CliFx.Tests public async Task Property_of_type_decimal_is_bound_by_parsing_the_argument_value() { // Arrange - await using var stdOut = new MemoryStream(); - var console = new VirtualConsole(output: stdOut); + var (console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -815,8 +761,7 @@ namespace CliFx.Tests "cmd", "--decimal", "3.14" }); - var stdOutData = console.Output.Encoding.GetString(stdOut.ToArray()).TrimEnd(); - var commandInstance = JsonConvert.DeserializeObject(stdOutData); + var commandInstance = stdOut.GetString().DeserializeJson(); // Assert exitCode.Should().Be(0); @@ -831,8 +776,7 @@ namespace CliFx.Tests public async Task Property_of_type_DateTime_is_bound_by_parsing_the_argument_value() { // Arrange - await using var stdOut = new MemoryStream(); - var console = new VirtualConsole(output: stdOut); + var (console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -845,8 +789,7 @@ namespace CliFx.Tests "cmd", "--datetime", "28 Apr 1995" }); - var stdOutData = console.Output.Encoding.GetString(stdOut.ToArray()).TrimEnd(); - var commandInstance = JsonConvert.DeserializeObject(stdOutData); + var commandInstance = stdOut.GetString().DeserializeJson(); // Assert exitCode.Should().Be(0); @@ -861,8 +804,7 @@ namespace CliFx.Tests public async Task Property_of_type_DateTimeOffset_is_bound_by_parsing_the_argument_value() { // Arrange - await using var stdOut = new MemoryStream(); - var console = new VirtualConsole(output: stdOut); + var (console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -875,8 +817,7 @@ namespace CliFx.Tests "cmd", "--datetime-offset", "28 Apr 1995" }); - var stdOutData = console.Output.Encoding.GetString(stdOut.ToArray()).TrimEnd(); - var commandInstance = JsonConvert.DeserializeObject(stdOutData); + var commandInstance = stdOut.GetString().DeserializeJson(); // Assert exitCode.Should().Be(0); @@ -891,8 +832,7 @@ namespace CliFx.Tests public async Task Property_of_type_TimeSpan_is_bound_by_parsing_the_argument_value() { // Arrange - await using var stdOut = new MemoryStream(); - var console = new VirtualConsole(output: stdOut); + var (console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -905,8 +845,7 @@ namespace CliFx.Tests "cmd", "--timespan", "00:14:59" }); - var stdOutData = console.Output.Encoding.GetString(stdOut.ToArray()).TrimEnd(); - var commandInstance = JsonConvert.DeserializeObject(stdOutData); + var commandInstance = stdOut.GetString().DeserializeJson(); // Assert exitCode.Should().Be(0); @@ -921,8 +860,7 @@ namespace CliFx.Tests public async Task Property_of_type_nullable_TimeSpan_is_bound_by_parsing_the_argument_value_if_it_is_set() { // Arrange - await using var stdOut = new MemoryStream(); - var console = new VirtualConsole(output: stdOut); + var (console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -935,8 +873,7 @@ namespace CliFx.Tests "cmd", "--timespan-nullable", "00:14:59" }); - var stdOutData = console.Output.Encoding.GetString(stdOut.ToArray()).TrimEnd(); - var commandInstance = JsonConvert.DeserializeObject(stdOutData); + var commandInstance = stdOut.GetString().DeserializeJson(); // Assert exitCode.Should().Be(0); @@ -951,8 +888,7 @@ namespace CliFx.Tests public async Task Property_of_type_nullable_TimeSpan_is_bound_as_null_if_the_argument_value_is_not_set() { // Arrange - await using var stdOut = new MemoryStream(); - var console = new VirtualConsole(output: stdOut); + var (console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -965,8 +901,7 @@ namespace CliFx.Tests "cmd", "--timespan-nullable" }); - var stdOutData = console.Output.Encoding.GetString(stdOut.ToArray()).TrimEnd(); - var commandInstance = JsonConvert.DeserializeObject(stdOutData); + var commandInstance = stdOut.GetString().DeserializeJson(); // Assert exitCode.Should().Be(0); @@ -981,8 +916,7 @@ namespace CliFx.Tests public async Task Property_of_an_enum_type_is_bound_by_parsing_the_argument_value_as_name() { // Arrange - await using var stdOut = new MemoryStream(); - var console = new VirtualConsole(output: stdOut); + var (console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -995,8 +929,7 @@ namespace CliFx.Tests "cmd", "--enum", "value2" }); - var stdOutData = console.Output.Encoding.GetString(stdOut.ToArray()).TrimEnd(); - var commandInstance = JsonConvert.DeserializeObject(stdOutData); + var commandInstance = stdOut.GetString().DeserializeJson(); // Assert exitCode.Should().Be(0); @@ -1011,8 +944,7 @@ namespace CliFx.Tests public async Task Property_of_an_enum_type_is_bound_by_parsing_the_argument_value_as_id() { // Arrange - await using var stdOut = new MemoryStream(); - var console = new VirtualConsole(output: stdOut); + var (console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -1025,8 +957,7 @@ namespace CliFx.Tests "cmd", "--enum", "2" }); - var stdOutData = console.Output.Encoding.GetString(stdOut.ToArray()).TrimEnd(); - var commandInstance = JsonConvert.DeserializeObject(stdOutData); + var commandInstance = stdOut.GetString().DeserializeJson(); // Assert exitCode.Should().Be(0); @@ -1041,8 +972,7 @@ namespace CliFx.Tests public async Task Property_of_a_nullable_enum_type_is_bound_by_parsing_the_argument_value_as_name_if_it_is_set() { // Arrange - await using var stdOut = new MemoryStream(); - var console = new VirtualConsole(output: stdOut); + var (console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -1055,8 +985,7 @@ namespace CliFx.Tests "cmd", "--enum-nullable", "value3" }); - var stdOutData = console.Output.Encoding.GetString(stdOut.ToArray()).TrimEnd(); - var commandInstance = JsonConvert.DeserializeObject(stdOutData); + var commandInstance = stdOut.GetString().DeserializeJson(); // Assert exitCode.Should().Be(0); @@ -1071,8 +1000,7 @@ namespace CliFx.Tests public async Task Property_of_a_nullable_enum_type_is_bound_by_parsing_the_argument_value_as_id_if_it_is_set() { // Arrange - await using var stdOut = new MemoryStream(); - var console = new VirtualConsole(output: stdOut); + var (console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -1085,8 +1013,7 @@ namespace CliFx.Tests "cmd", "--enum-nullable", "3" }); - var stdOutData = console.Output.Encoding.GetString(stdOut.ToArray()).TrimEnd(); - var commandInstance = JsonConvert.DeserializeObject(stdOutData); + var commandInstance = stdOut.GetString().DeserializeJson(); // Assert exitCode.Should().Be(0); @@ -1101,8 +1028,7 @@ namespace CliFx.Tests public async Task Property_of_a_nullable_enum_type_is_bound_as_null_if_the_argument_value_is_not_set() { // Arrange - await using var stdOut = new MemoryStream(); - var console = new VirtualConsole(output: stdOut); + var (console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -1115,8 +1041,7 @@ namespace CliFx.Tests "cmd", "--enum-nullable" }); - var stdOutData = console.Output.Encoding.GetString(stdOut.ToArray()).TrimEnd(); - var commandInstance = JsonConvert.DeserializeObject(stdOutData); + var commandInstance = stdOut.GetString().DeserializeJson(); // Assert exitCode.Should().Be(0); @@ -1131,8 +1056,7 @@ namespace CliFx.Tests public async Task Property_of_an_enum_array_type_is_bound_by_parsing_the_argument_values_as_names() { // Arrange - await using var stdOut = new MemoryStream(); - var console = new VirtualConsole(output: stdOut); + var (console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -1145,8 +1069,7 @@ namespace CliFx.Tests "cmd", "--enum-array", "value1", "value3" }); - var stdOutData = console.Output.Encoding.GetString(stdOut.ToArray()).TrimEnd(); - var commandInstance = JsonConvert.DeserializeObject(stdOutData); + var commandInstance = stdOut.GetString().DeserializeJson(); // Assert exitCode.Should().Be(0); @@ -1161,8 +1084,7 @@ namespace CliFx.Tests public async Task Property_of_an_enum_array_type_is_bound_by_parsing_the_argument_values_as_ids() { // Arrange - await using var stdOut = new MemoryStream(); - var console = new VirtualConsole(output: stdOut); + var (console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -1175,8 +1097,7 @@ namespace CliFx.Tests "cmd", "--enum-array", "1", "3" }); - var stdOutData = console.Output.Encoding.GetString(stdOut.ToArray()).TrimEnd(); - var commandInstance = JsonConvert.DeserializeObject(stdOutData); + var commandInstance = stdOut.GetString().DeserializeJson(); // Assert exitCode.Should().Be(0); @@ -1191,8 +1112,7 @@ namespace CliFx.Tests public async Task Property_of_an_enum_array_type_is_bound_by_parsing_the_argument_values_as_either_names_or_ids() { // Arrange - await using var stdOut = new MemoryStream(); - var console = new VirtualConsole(output: stdOut); + var (console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -1205,8 +1125,7 @@ namespace CliFx.Tests "cmd", "--enum-array", "1", "value3" }); - var stdOutData = console.Output.Encoding.GetString(stdOut.ToArray()).TrimEnd(); - var commandInstance = JsonConvert.DeserializeObject(stdOutData); + var commandInstance = stdOut.GetString().DeserializeJson(); // Assert exitCode.Should().Be(0); @@ -1221,8 +1140,7 @@ namespace CliFx.Tests public async Task Property_of_a_type_that_has_a_constructor_accepting_a_string_is_bound_by_invoking_the_constructor_with_the_argument_value() { // Arrange - await using var stdOut = new MemoryStream(); - var console = new VirtualConsole(output: stdOut); + var (console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -1235,8 +1153,7 @@ namespace CliFx.Tests "cmd", "--str-constructible", "foobar" }); - var stdOutData = console.Output.Encoding.GetString(stdOut.ToArray()).TrimEnd(); - var commandInstance = JsonConvert.DeserializeObject(stdOutData); + var commandInstance = stdOut.GetString().DeserializeJson(); // Assert exitCode.Should().Be(0); @@ -1251,8 +1168,7 @@ namespace CliFx.Tests public async Task Property_of_an_array_of_type_that_has_a_constructor_accepting_a_string_is_bound_by_invoking_the_constructor_with_the_argument_values() { // Arrange - await using var stdOut = new MemoryStream(); - var console = new VirtualConsole(output: stdOut); + var (console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -1265,8 +1181,7 @@ namespace CliFx.Tests "cmd", "--str-constructible-array", "foo", "bar" }); - var stdOutData = console.Output.Encoding.GetString(stdOut.ToArray()).TrimEnd(); - var commandInstance = JsonConvert.DeserializeObject(stdOutData); + var commandInstance = stdOut.GetString().DeserializeJson(); // Assert exitCode.Should().Be(0); @@ -1285,8 +1200,7 @@ namespace CliFx.Tests public async Task Property_of_a_type_that_has_a_static_Parse_method_accepting_a_string_is_bound_by_invoking_the_method() { // Arrange - await using var stdOut = new MemoryStream(); - var console = new VirtualConsole(output: stdOut); + var (console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -1299,8 +1213,7 @@ namespace CliFx.Tests "cmd", "--str-parseable", "foobar" }); - var stdOutData = console.Output.Encoding.GetString(stdOut.ToArray()).TrimEnd(); - var commandInstance = JsonConvert.DeserializeObject(stdOutData); + var commandInstance = stdOut.GetString().DeserializeJson(); // Assert exitCode.Should().Be(0); @@ -1315,8 +1228,7 @@ namespace CliFx.Tests public async Task Property_of_a_type_that_has_a_static_Parse_method_accepting_a_string_and_format_provider_is_bound_by_invoking_the_method() { // Arrange - await using var stdOut = new MemoryStream(); - var console = new VirtualConsole(output: stdOut); + var (console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -1329,8 +1241,7 @@ namespace CliFx.Tests "cmd", "--str-parseable-format", "foobar" }); - var stdOutData = console.Output.Encoding.GetString(stdOut.ToArray()).TrimEnd(); - var commandInstance = JsonConvert.DeserializeObject(stdOutData); + var commandInstance = stdOut.GetString().DeserializeJson(); // Assert exitCode.Should().Be(0); @@ -1346,8 +1257,7 @@ namespace CliFx.Tests public async Task Property_of_custom_type_must_be_string_initializable_in_order_to_be_bound() { // Arrange - await using var stdErr = new MemoryStream(); - var console = new VirtualConsole(error: stdErr); + var (console, _, stdErr) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -1360,21 +1270,18 @@ namespace CliFx.Tests "cmd", "--str-non-initializable", "foobar" }); - var stdErrData = console.Error.Encoding.GetString(stdErr.ToArray()).TrimEnd(); - // Assert exitCode.Should().NotBe(0); - stdErrData.Should().NotBeEmpty(); + stdErr.GetString().Should().NotBeNullOrWhiteSpace(); - _output.WriteLine(stdErrData); + _output.WriteLine(stdErr.GetString()); } [Fact] public async Task Property_of_custom_type_that_implements_IEnumerable_can_only_be_bound_if_that_type_has_a_constructor_accepting_an_array() { // Arrange - await using var stdErr = new MemoryStream(); - var console = new VirtualConsole(error: stdErr); + var (console, _, stdErr) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -1387,21 +1294,18 @@ namespace CliFx.Tests "cmd", "--str-enumerable-non-initializable", "foobar" }); - var stdErrData = console.Error.Encoding.GetString(stdErr.ToArray()).TrimEnd(); - // Assert exitCode.Should().NotBe(0); - stdErrData.Should().NotBeEmpty(); + stdErr.GetString().Should().NotBeNullOrWhiteSpace(); - _output.WriteLine(stdErrData); + _output.WriteLine(stdErr.GetString()); } [Fact] public async Task Property_of_non_nullable_type_can_only_be_bound_if_the_argument_value_is_set() { // Arrange - await using var stdErr = new MemoryStream(); - var console = new VirtualConsole(error: stdErr); + var (console, _, stdErr) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -1414,21 +1318,18 @@ namespace CliFx.Tests "cmd", "--int" }); - var stdErrData = console.Error.Encoding.GetString(stdErr.ToArray()).TrimEnd(); - // Assert exitCode.Should().NotBe(0); - stdErrData.Should().NotBeEmpty(); + stdErr.GetString().Should().NotBeNullOrWhiteSpace(); - _output.WriteLine(stdErrData); + _output.WriteLine(stdErr.GetString()); } [Fact] public async Task Property_must_have_a_type_that_implements_IEnumerable_in_order_to_be_bound_from_multiple_argument_values() { // Arrange - await using var stdErr = new MemoryStream(); - var console = new VirtualConsole(error: stdErr); + var (console, _, stdErr) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -1441,13 +1342,11 @@ namespace CliFx.Tests "cmd", "--int", "1", "2", "3" }); - var stdErrData = console.Error.Encoding.GetString(stdErr.ToArray()).TrimEnd(); - // Assert exitCode.Should().NotBe(0); - stdErrData.Should().NotBeEmpty(); + stdErr.GetString().Should().NotBeNullOrWhiteSpace(); - _output.WriteLine(stdErrData); + _output.WriteLine(stdErr.GetString()); } } } \ No newline at end of file diff --git a/CliFx.Tests/CancellationSpecs.cs b/CliFx.Tests/CancellationSpecs.cs index 0f38568..b7cd1f5 100644 --- a/CliFx.Tests/CancellationSpecs.cs +++ b/CliFx.Tests/CancellationSpecs.cs @@ -1,5 +1,4 @@ using System; -using System.IO; using System.Threading; using System.Threading.Tasks; using CliFx.Tests.Commands; @@ -17,9 +16,7 @@ namespace CliFx.Tests // Arrange using var cts = new CancellationTokenSource(); - - await using var stdOut = new MemoryStream(); - var console = new VirtualConsole(output: stdOut, cancellationToken: cts.Token); + var (console, stdOut, _) = VirtualConsole.CreateBuffered(cts.Token); var application = new CliApplicationBuilder() .AddCommand() @@ -30,11 +27,10 @@ namespace CliFx.Tests cts.CancelAfter(TimeSpan.FromSeconds(0.2)); var exitCode = await application.RunAsync(new[] {"cmd"}); - var stdOutData = console.Output.Encoding.GetString(stdOut.ToArray()).TrimEnd(); // Assert exitCode.Should().NotBe(0); - stdOutData.Should().Be(CancellableCommand.CancellationOutputText); + stdOut.GetString().Trim().Should().Be(CancellableCommand.CancellationOutputText); } } } \ No newline at end of file diff --git a/CliFx.Tests/Commands/DefaultCommand.cs b/CliFx.Tests/Commands/DefaultCommand.cs index 4c58b99..489c79e 100644 --- a/CliFx.Tests/Commands/DefaultCommand.cs +++ b/CliFx.Tests/Commands/DefaultCommand.cs @@ -3,7 +3,7 @@ using CliFx.Attributes; namespace CliFx.Tests.Commands { - [Command(Description = nameof(DefaultCommand))] + [Command(Description = "Default command description")] public class DefaultCommand : ICommand { public const string ExpectedOutputText = nameof(DefaultCommand); diff --git a/CliFx.Tests/Commands/NamedCommand.cs b/CliFx.Tests/Commands/NamedCommand.cs index a3990db..d50f225 100644 --- a/CliFx.Tests/Commands/NamedCommand.cs +++ b/CliFx.Tests/Commands/NamedCommand.cs @@ -3,7 +3,7 @@ using CliFx.Attributes; namespace CliFx.Tests.Commands { - [Command("named", Description = nameof(NamedCommand))] + [Command("named", Description = "Named command description")] public class NamedCommand : ICommand { public const string ExpectedOutputText = nameof(NamedCommand); diff --git a/CliFx.Tests/Commands/NamedSubCommand.cs b/CliFx.Tests/Commands/NamedSubCommand.cs index 9ade0e0..abc798c 100644 --- a/CliFx.Tests/Commands/NamedSubCommand.cs +++ b/CliFx.Tests/Commands/NamedSubCommand.cs @@ -3,7 +3,7 @@ using CliFx.Attributes; namespace CliFx.Tests.Commands { - [Command("named sub", Description = nameof(NamedSubCommand))] + [Command("named sub", Description = "Named sub command description")] public class NamedSubCommand : ICommand { public const string ExpectedOutputText = nameof(NamedSubCommand); diff --git a/CliFx.Tests/DirectivesSpecs.cs b/CliFx.Tests/DirectivesSpecs.cs index 65c02c3..2c79c7e 100644 --- a/CliFx.Tests/DirectivesSpecs.cs +++ b/CliFx.Tests/DirectivesSpecs.cs @@ -18,8 +18,7 @@ namespace CliFx.Tests public async Task Preview_directive_can_be_specified_to_print_provided_arguments_as_they_were_parsed() { // Arrange - await using var stdOut = new MemoryStream(); - var console = new VirtualConsole(output: stdOut); + var (console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -32,13 +31,13 @@ namespace CliFx.Tests new[] {"[preview]", "named", "param", "-abc", "--option", "foo"}, new Dictionary()); - var stdOutData = console.Output.Encoding.GetString(stdOut.ToArray()).TrimEnd(); - // Assert exitCode.Should().Be(0); - stdOutData.Should().ContainAll("named", "", "[-a]", "[-b]", "[-c]", "[--option \"foo\"]"); + stdOut.GetString().Should().ContainAll( + "named", "", "[-a]", "[-b]", "[-c]", "[--option \"foo\"]" + ); - _output.WriteLine(stdOutData); + _output.WriteLine(stdOut.GetString()); } } } \ No newline at end of file diff --git a/CliFx.Tests/EnvironmentVariablesSpecs.cs b/CliFx.Tests/EnvironmentVariablesSpecs.cs index 19e6cc6..09f9ef6 100644 --- a/CliFx.Tests/EnvironmentVariablesSpecs.cs +++ b/CliFx.Tests/EnvironmentVariablesSpecs.cs @@ -2,10 +2,10 @@ using System.IO; using System.Threading.Tasks; using CliFx.Tests.Commands; +using CliFx.Tests.Internal; using CliWrap; using CliWrap.Buffered; using FluentAssertions; -using Newtonsoft.Json; using Xunit; namespace CliFx.Tests @@ -27,7 +27,7 @@ namespace CliFx.Tests var stdOut = await command.ExecuteBufferedAsync().Select(r => r.StandardOutput); // Assert - stdOut.TrimEnd().Should().Be("Hello Mars!"); + stdOut.Trim().Should().Be("Hello Mars!"); } // This test uses a real application to make sure environment variables are actually read correctly @@ -47,14 +47,13 @@ namespace CliFx.Tests var stdOut = await command.ExecuteBufferedAsync().Select(r => r.StandardOutput); // Assert - stdOut.TrimEnd().Should().Be("Hello Jupiter!"); + stdOut.Trim().Should().Be("Hello Jupiter!"); } [Fact] public async Task Option_only_uses_an_environment_variable_as_fallback_if_the_name_matches_case_sensitively() { - await using var stdOut = new MemoryStream(); - var console = new VirtualConsole(output: stdOut); + var (console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -71,8 +70,7 @@ namespace CliFx.Tests } ); - var stdOutData = console.Output.Encoding.GetString(stdOut.ToArray()).TrimEnd(); - var commandInstance = JsonConvert.DeserializeObject(stdOutData); + var commandInstance = stdOut.GetString().DeserializeJson(); // Assert exitCode.Should().Be(0); @@ -85,8 +83,7 @@ namespace CliFx.Tests [Fact] public async Task Option_of_non_scalar_type_can_use_an_environment_variable_as_fallback_and_extract_multiple_values() { - await using var stdOut = new MemoryStream(); - var console = new VirtualConsole(output: stdOut); + var (console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -102,8 +99,7 @@ namespace CliFx.Tests } ); - var stdOutData = console.Output.Encoding.GetString(stdOut.ToArray()).TrimEnd(); - var commandInstance = JsonConvert.DeserializeObject(stdOutData); + var commandInstance = stdOut.GetString().DeserializeJson(); // Assert exitCode.Should().Be(0); @@ -116,8 +112,7 @@ namespace CliFx.Tests [Fact] public async Task Option_of_scalar_type_can_use_an_environment_variable_as_fallback_regardless_of_separators() { - await using var stdOut = new MemoryStream(); - var console = new VirtualConsole(output: stdOut); + var (console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -133,8 +128,7 @@ namespace CliFx.Tests } ); - var stdOutData = console.Output.Encoding.GetString(stdOut.ToArray()).TrimEnd(); - var commandInstance = JsonConvert.DeserializeObject(stdOutData); + var commandInstance = stdOut.GetString().DeserializeJson(); // Assert exitCode.Should().Be(0); diff --git a/CliFx.Tests/ErrorReportingSpecs.cs b/CliFx.Tests/ErrorReportingSpecs.cs index 84601bf..302d6b1 100644 --- a/CliFx.Tests/ErrorReportingSpecs.cs +++ b/CliFx.Tests/ErrorReportingSpecs.cs @@ -1,5 +1,4 @@ -using System.IO; -using System.Threading.Tasks; +using System.Threading.Tasks; using CliFx.Tests.Commands; using FluentAssertions; using Xunit; @@ -17,10 +16,7 @@ namespace CliFx.Tests public async Task Command_may_throw_a_generic_exception_which_exits_and_prints_error_message_and_stack_trace() { // Arrange - await using var stdOut = new MemoryStream(); - await using var stdErr = new MemoryStream(); - - var console = new VirtualConsole(output: stdOut, error: stdErr); + var (console, stdOut, stdErr) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -30,30 +26,24 @@ namespace CliFx.Tests // Act var exitCode = await application.RunAsync(new[] {"cmd", "-m", "Kaput"}); - var stdOutData = console.Output.Encoding.GetString(stdOut.ToArray()).TrimEnd(); - var stdErrData = console.Error.Encoding.GetString(stdErr.ToArray()).TrimEnd(); - // Assert exitCode.Should().NotBe(0); - stdOutData.Should().BeEmpty(); - stdErrData.Should().ContainAll( + stdOut.GetString().Should().BeEmpty(); + stdErr.GetString().Should().ContainAll( "System.Exception:", "Kaput", "at", "CliFx.Tests" ); - _output.WriteLine(stdOutData); - _output.WriteLine(stdErrData); + _output.WriteLine(stdOut.GetString()); + _output.WriteLine(stdErr.GetString()); } [Fact] public async Task Command_may_throw_a_specialized_exception_which_exits_with_custom_code_and_prints_minimal_error_details() { // Arrange - await using var stdOut = new MemoryStream(); - await using var stdErr = new MemoryStream(); - - var console = new VirtualConsole(output: stdOut, error: stdErr); + var (console, stdOut, stdErr) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -63,26 +53,20 @@ namespace CliFx.Tests // Act var exitCode = await application.RunAsync(new[] {"cmd", "-m", "Kaput", "-c", "69"}); - var stdOutData = console.Output.Encoding.GetString(stdOut.ToArray()).TrimEnd(); - var stdErrData = console.Error.Encoding.GetString(stdErr.ToArray()).TrimEnd(); - // Assert exitCode.Should().Be(69); - stdOutData.Should().BeEmpty(); - stdErrData.Should().Be("Kaput"); + stdOut.GetString().Should().BeEmpty(); + stdErr.GetString().Trim().Should().Be("Kaput"); - _output.WriteLine(stdOutData); - _output.WriteLine(stdErrData); + _output.WriteLine(stdOut.GetString()); + _output.WriteLine(stdErr.GetString()); } [Fact] public async Task Command_may_throw_a_specialized_exception_without_error_message_which_exits_and_prints_full_error_details() { // Arrange - await using var stdOut = new MemoryStream(); - await using var stdErr = new MemoryStream(); - - var console = new VirtualConsole(output: stdOut, error: stdErr); + var (console, stdOut, stdErr) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -92,30 +76,24 @@ namespace CliFx.Tests // Act var exitCode = await application.RunAsync(new[] {"cmd"}); - var stdOutData = console.Output.Encoding.GetString(stdOut.ToArray()).TrimEnd(); - var stdErrData = console.Error.Encoding.GetString(stdErr.ToArray()).TrimEnd(); - // Assert exitCode.Should().NotBe(0); - stdOutData.Should().BeEmpty(); - stdErrData.Should().ContainAll( + stdOut.GetString().Should().BeEmpty(); + stdErr.GetString().Should().ContainAll( "CliFx.Exceptions.CommandException:", "at", "CliFx.Tests" ); - _output.WriteLine(stdOutData); - _output.WriteLine(stdErrData); + _output.WriteLine(stdOut.GetString()); + _output.WriteLine(stdErr.GetString()); } [Fact] public async Task Command_may_throw_a_specialized_exception_which_exits_and_prints_help_text() { // Arrange - await using var stdOut = new MemoryStream(); - await using var stdErr = new MemoryStream(); - - var console = new VirtualConsole(output: stdOut, error: stdErr); + var (console, stdOut, stdErr) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -125,30 +103,24 @@ namespace CliFx.Tests // Act var exitCode = await application.RunAsync(new[] {"cmd", "-m", "Kaput", "--show-help"}); - var stdOutData = console.Output.Encoding.GetString(stdOut.ToArray()).TrimEnd(); - var stdErrData = console.Error.Encoding.GetString(stdErr.ToArray()).TrimEnd(); - // Assert exitCode.Should().NotBe(0); - stdOutData.Should().ContainAll( + stdOut.GetString().Should().ContainAll( "Usage", "Options", "-h|--help" ); - stdErrData.Should().Be("Kaput"); + stdErr.GetString().Trim().Should().Be("Kaput"); - _output.WriteLine(stdOutData); - _output.WriteLine(stdErrData); + _output.WriteLine(stdOut.GetString()); + _output.WriteLine(stdErr.GetString()); } [Fact] public async Task Command_shows_help_text_on_invalid_user_input() { // Arrange - await using var stdOut = new MemoryStream(); - await using var stdErr = new MemoryStream(); - - var console = new VirtualConsole(output: stdOut, error: stdErr); + var (console, stdOut, stdErr) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -158,20 +130,17 @@ namespace CliFx.Tests // Act var exitCode = await application.RunAsync(new[] {"not-a-valid-command", "-r", "foo"}); - var stdOutData = console.Output.Encoding.GetString(stdOut.ToArray()).TrimEnd(); - var stdErrData = console.Error.Encoding.GetString(stdErr.ToArray()).TrimEnd(); - // Assert exitCode.Should().NotBe(0); - stdOutData.Should().ContainAll( + stdOut.GetString().Should().ContainAll( "Usage", "Options", "-h|--help" ); - stdErrData.Should().NotBeNullOrWhiteSpace(); + stdErr.GetString().Should().NotBeNullOrWhiteSpace(); - _output.WriteLine(stdOutData); - _output.WriteLine(stdErrData); + _output.WriteLine(stdOut.GetString()); + _output.WriteLine(stdErr.GetString()); } } } \ No newline at end of file diff --git a/CliFx.Tests/HelpTextSpecs.cs b/CliFx.Tests/HelpTextSpecs.cs index 3358752..0939236 100644 --- a/CliFx.Tests/HelpTextSpecs.cs +++ b/CliFx.Tests/HelpTextSpecs.cs @@ -1,5 +1,4 @@ -using System.IO; -using System.Threading.Tasks; +using System.Threading.Tasks; using CliFx.Tests.Commands; using FluentAssertions; using Xunit; @@ -17,8 +16,7 @@ namespace CliFx.Tests public async Task Help_text_shows_usage_format_which_lists_all_parameters() { // Arrange - await using var stdOut = new MemoryStream(); - var console = new VirtualConsole(output: stdOut); + var (console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -27,24 +25,22 @@ namespace CliFx.Tests // Act var exitCode = await application.RunAsync(new[] {"cmd", "--help"}); - var stdOutData = console.Output.Encoding.GetString(stdOut.ToArray()).TrimEnd(); // Assert exitCode.Should().Be(0); - stdOutData.Should().ContainAll( + stdOut.GetString().Should().ContainAll( "Usage", "cmd", "", "", "" ); - _output.WriteLine(stdOutData); + _output.WriteLine(stdOut.GetString()); } [Fact] public async Task Help_text_shows_usage_format_which_lists_all_required_options() { // Arrange - await using var stdOut = new MemoryStream(); - var console = new VirtualConsole(output: stdOut); + var (console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -53,11 +49,10 @@ namespace CliFx.Tests // Act var exitCode = await application.RunAsync(new[] {"cmd", "--help"}); - var stdOutData = console.Output.Encoding.GetString(stdOut.ToArray()).TrimEnd(); // Assert exitCode.Should().Be(0); - stdOutData.Should().ContainAll( + stdOut.GetString().Should().ContainAll( "Usage", "cmd", "--opt-a ", "--opt-c ", "[options]", "Options", @@ -66,15 +61,14 @@ namespace CliFx.Tests "* -c|--opt-c" ); - _output.WriteLine(stdOutData); + _output.WriteLine(stdOut.GetString()); } [Fact] public async Task Help_text_shows_all_valid_values_for_enum_arguments() { // Arrange - await using var stdOut = new MemoryStream(); - var console = new VirtualConsole(output: stdOut); + var (console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -83,11 +77,10 @@ namespace CliFx.Tests // Act var exitCode = await application.RunAsync(new[] {"cmd", "--help"}); - var stdOutData = console.Output.Encoding.GetString(stdOut.ToArray()).TrimEnd(); // Assert exitCode.Should().Be(0); - stdOutData.Should().ContainAll( + stdOut.GetString().Should().ContainAll( "Parameters", "enum", "Valid values: \"Value1\", \"Value2\", \"Value3\".", "Options", @@ -95,15 +88,14 @@ namespace CliFx.Tests "* --required-enum", "Valid values: \"Value1\", \"Value2\", \"Value3\"." ); - _output.WriteLine(stdOutData); + _output.WriteLine(stdOut.GetString()); } [Fact] public async Task Help_text_shows_environment_variable_names_for_options_that_have_them_defined() { // Arrange - await using var stdOut = new MemoryStream(); - var console = new VirtualConsole(output: stdOut); + var (console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -112,25 +104,23 @@ namespace CliFx.Tests // Act var exitCode = await application.RunAsync(new[] {"cmd", "--help"}); - var stdOutData = console.Output.Encoding.GetString(stdOut.ToArray()).TrimEnd(); // Assert exitCode.Should().Be(0); - stdOutData.Should().ContainAll( + stdOut.GetString().Should().ContainAll( "Options", "-a|--opt-a", "Environment variable:", "ENV_OPT_A", "-b|--opt-b", "Environment variable:", "ENV_OPT_B" ); - _output.WriteLine(stdOutData); + _output.WriteLine(stdOut.GetString()); } [Fact] public async Task Help_text_shows_default_values_for_non_required_options() { // Arrange - await using var stdOut = new MemoryStream(); - var console = new VirtualConsole(output: stdOut); + var (console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -139,11 +129,10 @@ namespace CliFx.Tests // Act var exitCode = await application.RunAsync(new[] {"cmd", "--help"}); - var stdOutData = console.Output.Encoding.GetString(stdOut.ToArray()).TrimEnd(); // Assert exitCode.Should().Be(0); - stdOutData.Should().ContainAll( + stdOut.GetString().Should().ContainAll( "Options", "--obj", "Default: \"42\"", "--str", "Default: \"foo\"", @@ -158,7 +147,7 @@ namespace CliFx.Tests "--enum", "Default: \"Value2\"" ); - _output.WriteLine(stdOutData); + _output.WriteLine(stdOut.GetString()); } } } \ No newline at end of file diff --git a/CliFx.Tests/Internal/JsonExtensions.cs b/CliFx.Tests/Internal/JsonExtensions.cs new file mode 100644 index 0000000..68b636f --- /dev/null +++ b/CliFx.Tests/Internal/JsonExtensions.cs @@ -0,0 +1,10 @@ +using Newtonsoft.Json; + +namespace CliFx.Tests.Internal +{ + internal static class JsonExtensions + { + public static T DeserializeJson(this string json) => + JsonConvert.DeserializeObject(json); + } +} \ No newline at end of file diff --git a/CliFx.Tests/RoutingSpecs.cs b/CliFx.Tests/RoutingSpecs.cs index 3a8341b..f9fd378 100644 --- a/CliFx.Tests/RoutingSpecs.cs +++ b/CliFx.Tests/RoutingSpecs.cs @@ -1,5 +1,4 @@ using System; -using System.IO; using System.Threading.Tasks; using CliFx.Tests.Commands; using FluentAssertions; @@ -18,8 +17,7 @@ namespace CliFx.Tests public async Task Default_command_is_executed_if_provided_arguments_do_not_match_any_named_command() { // Arrange - await using var stdOut = new MemoryStream(); - var console = new VirtualConsole(output: stdOut); + var (console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -30,21 +28,19 @@ namespace CliFx.Tests // Act var exitCode = await application.RunAsync(Array.Empty()); - var stdOutData = console.Output.Encoding.GetString(stdOut.ToArray()).TrimEnd(); // Assert exitCode.Should().Be(0); - stdOutData.Should().Be(DefaultCommand.ExpectedOutputText); + stdOut.GetString().Trim().Should().Be(DefaultCommand.ExpectedOutputText); - _output.WriteLine(stdOutData); + _output.WriteLine(stdOut.GetString()); } [Fact] public async Task Specific_named_command_is_executed_if_provided_arguments_match_its_name() { // Arrange - await using var stdOut = new MemoryStream(); - var console = new VirtualConsole(output: stdOut); + var (console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -55,21 +51,19 @@ namespace CliFx.Tests // Act var exitCode = await application.RunAsync(new[] {"named"}); - var stdOutData = console.Output.Encoding.GetString(stdOut.ToArray()).TrimEnd(); // Assert exitCode.Should().Be(0); - stdOutData.Should().Be(NamedCommand.ExpectedOutputText); + stdOut.GetString().Trim().Should().Be(NamedCommand.ExpectedOutputText); - _output.WriteLine(stdOutData); + _output.WriteLine(stdOut.GetString()); } [Fact] public async Task Specific_named_sub_command_is_executed_if_provided_arguments_match_its_name() { // Arrange - await using var stdOut = new MemoryStream(); - var console = new VirtualConsole(output: stdOut); + var (console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -80,21 +74,19 @@ namespace CliFx.Tests // Act var exitCode = await application.RunAsync(new[] {"named", "sub"}); - var stdOutData = console.Output.Encoding.GetString(stdOut.ToArray()).TrimEnd(); // Assert exitCode.Should().Be(0); - stdOutData.Should().Be(NamedSubCommand.ExpectedOutputText); + stdOut.GetString().Trim().Should().Be(NamedSubCommand.ExpectedOutputText); - _output.WriteLine(stdOutData); + _output.WriteLine(stdOut.GetString()); } [Fact] public async Task Help_text_is_printed_if_no_arguments_were_provided_and_default_command_is_not_defined() { // Arrange - await using var stdOut = new MemoryStream(); - var console = new VirtualConsole(output: stdOut); + var (console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -105,21 +97,19 @@ namespace CliFx.Tests // Act var exitCode = await application.RunAsync(Array.Empty()); - var stdOutData = console.Output.Encoding.GetString(stdOut.ToArray()).TrimEnd(); // Assert exitCode.Should().Be(0); - stdOutData.Should().Contain("This will be visible in help"); + stdOut.GetString().Should().Contain("This will be visible in help"); - _output.WriteLine(stdOutData); + _output.WriteLine(stdOut.GetString()); } [Fact] public async Task Help_text_is_printed_if_provided_arguments_contain_the_help_option() { // Arrange - await using var stdOut = new MemoryStream(); - var console = new VirtualConsole(output: stdOut); + var (console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -130,24 +120,22 @@ namespace CliFx.Tests // Act var exitCode = await application.RunAsync(new[] {"--help"}); - var stdOutData = console.Output.Encoding.GetString(stdOut.ToArray()).TrimEnd(); // Assert exitCode.Should().Be(0); - stdOutData.Should().ContainAll( - nameof(DefaultCommand), + stdOut.GetString().Should().ContainAll( + "Default command description", "Usage" ); - _output.WriteLine(stdOutData); + _output.WriteLine(stdOut.GetString()); } [Fact] public async Task Help_text_is_printed_if_provided_arguments_contain_the_help_option_even_if_default_command_is_not_defined() { // Arrange - await using var stdOut = new MemoryStream(); - var console = new VirtualConsole(output: stdOut); + var (console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -158,21 +146,19 @@ namespace CliFx.Tests // Act var exitCode = await application.RunAsync(new[] {"--help"}); - var stdOutData = console.Output.Encoding.GetString(stdOut.ToArray()).TrimEnd(); // Assert exitCode.Should().Be(0); - stdOutData.Should().Contain("This will be visible in help"); + stdOut.GetString().Should().Contain("This will be visible in help"); - _output.WriteLine(stdOutData); + _output.WriteLine(stdOut.GetString()); } [Fact] public async Task Help_text_for_a_specific_named_command_is_printed_if_provided_arguments_match_its_name_and_contain_the_help_option() { // Arrange - await using var stdOut = new MemoryStream(); - var console = new VirtualConsole(output: stdOut); + var (console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -183,25 +169,23 @@ namespace CliFx.Tests // Act var exitCode = await application.RunAsync(new[] {"named", "--help"}); - var stdOutData = console.Output.Encoding.GetString(stdOut.ToArray()).TrimEnd(); // Assert exitCode.Should().Be(0); - stdOutData.Should().ContainAll( - nameof(NamedCommand), + stdOut.GetString().Should().ContainAll( + "Named command description", "Usage", "named" ); - _output.WriteLine(stdOutData); + _output.WriteLine(stdOut.GetString()); } [Fact] public async Task Help_text_for_a_specific_named_sub_command_is_printed_if_provided_arguments_match_its_name_and_contain_the_help_option() { // Arrange - await using var stdOut = new MemoryStream(); - var console = new VirtualConsole(output: stdOut); + var (console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -212,25 +196,23 @@ namespace CliFx.Tests // Act var exitCode = await application.RunAsync(new[] {"named", "sub", "--help"}); - var stdOutData = console.Output.Encoding.GetString(stdOut.ToArray()).TrimEnd(); // Assert exitCode.Should().Be(0); - stdOutData.Should().ContainAll( - nameof(NamedSubCommand), + stdOut.GetString().Should().ContainAll( + "Named sub command description", "Usage", "named", "sub" ); - _output.WriteLine(stdOutData); + _output.WriteLine(stdOut.GetString()); } [Fact] public async Task Version_is_printed_if_the_only_provided_argument_is_the_version_option() { // Arrange - await using var stdOut = new MemoryStream(); - var console = new VirtualConsole(output: stdOut); + var (console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand() @@ -242,13 +224,12 @@ namespace CliFx.Tests // Act var exitCode = await application.RunAsync(new[] {"--version"}); - var stdOutData = console.Output.Encoding.GetString(stdOut.ToArray()).TrimEnd(); // Assert exitCode.Should().Be(0); - stdOutData.Should().Be("v6.9"); + stdOut.GetString().Trim().Should().Be("v6.9"); - _output.WriteLine(stdOutData); + _output.WriteLine(stdOut.GetString()); } } } \ No newline at end of file diff --git a/CliFx/Utilities/MemoryStreamWriter.cs b/CliFx/Utilities/MemoryStreamWriter.cs new file mode 100644 index 0000000..a39e1d2 --- /dev/null +++ b/CliFx/Utilities/MemoryStreamWriter.cs @@ -0,0 +1,43 @@ +using System.IO; +using System.Text; + +namespace CliFx.Utilities +{ + /// + /// Implementation of with a as a backing store. + /// + public class MemoryStreamWriter : StreamWriter + { + private new MemoryStream BaseStream => (MemoryStream) base.BaseStream; + + /// + /// Initializes an instance of . + /// + public MemoryStreamWriter(Encoding encoding) + : base(new MemoryStream(), encoding) + { + } + + /// + /// Initializes an instance of . + /// + public MemoryStreamWriter() + : base(new MemoryStream()) + { + } + + /// + /// Gets the bytes written to the underlying stream. + /// + public byte[] GetBytes() + { + Flush(); + return BaseStream.ToArray(); + } + + /// + /// Gets the string written to the underlying stream. + /// + public string GetString() => Encoding.GetString(GetBytes()); + } +} \ No newline at end of file diff --git a/CliFx/VirtualConsole.cs b/CliFx/VirtualConsole.cs index e92094f..3dc5e29 100644 --- a/CliFx/VirtualConsole.cs +++ b/CliFx/VirtualConsole.cs @@ -1,6 +1,7 @@ using System; using System.IO; using System.Threading; +using CliFx.Utilities; namespace CliFx { @@ -101,5 +102,25 @@ namespace CliFx stream != null ? new StreamWriter(Stream.Synchronized(stream), Console.OutputEncoding) {AutoFlush = true} : StreamWriter.Null; + + /// + /// Creates a that uses in-memory output and error streams. + /// Use the exposed streams to easily get the current output. + /// + public static (VirtualConsole console, MemoryStreamWriter output, MemoryStreamWriter error) CreateBuffered( + CancellationToken cancellationToken = default) + { + // Memory streams don't need to be disposed + var output = new MemoryStreamWriter(Console.OutputEncoding); + var error = new MemoryStreamWriter(Console.OutputEncoding); + + var console = new VirtualConsole( + output: output, + error: error, + cancellationToken: cancellationToken + ); + + return (console, output, error); + } } } \ No newline at end of file