public async Task Help_text_shows_all_valid_values_for_enum_arguments() { // Arrange var(console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand <WithEnumArgumentsCommand>() .UseConsole(console) .Build(); // Act int exitCode = await application.RunAsync(new[] { "cmd", "--help" }); // Assert exitCode.Should().Be(ExitCodes.Success); stdOut.GetString().Should().ContainAll( "Parameters", "enum", "Valid values: \"Value1\", \"Value2\", \"Value3\".", "Options", "--enum", "Valid values: \"Value1\", \"Value2\", \"Value3\".", "* --required-enum", "Valid values: \"Value1\", \"Value2\", \"Value3\"." ); _output.WriteLine(stdOut.GetString()); }
public async Task Custom_throwable_directive_with_inner_exception_should_throw_exception() { // Arrange var(console, stdOut, stdErr) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand <NamedCommand>() .UseConsole(console) .AddDirective <PreviewDirective>() .AddDirective <CustomThrowableDirective>() .AddDirective <CustomThrowableDirectiveWithMessage>() .AddDirective <CustomThrowableDirectiveWithInnerException>() .AddDirective <CustomDirective>() .AddDirective <CustomStopDirective>() .AddDirective <CustomInteractiveModeOnlyDirective>() .Build(); // Act int exitCode = await application.RunAsync( new[] { "[custom-throwable-with-inner-exception]", "named", "param", "-abc", "--option", "foo" }, new Dictionary <string, string>()); // Assert exitCode.Should().Be(CustomThrowableDirectiveWithInnerException.ExpectedExitCode); stdOut.GetString().Should().Be(CustomThrowableDirectiveWithInnerException.ExpectedOutput); stdErr.GetString().Should().ContainEquivalentOf(CustomThrowableDirectiveWithInnerException.ExpectedExceptionMessage); _output.WriteLine(stdOut.GetString()); _output.WriteLine(stdErr.GetString()); }
public async Task Interactive_only_directive_cannot_be_executed_in_normal_mode() { // Arrange var(console, stdOut, stdErr) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand <NamedCommand>() .UseConsole(console) .AddDirective <CustomInteractiveModeOnlyDirective>() .Build(); // Act int exitCode = await application.RunAsync( new[] { "[custom-interactive]", "named", "param", "-abc", "--option", "foo" }, new Dictionary <string, string>()); // Assert exitCode.Should().Be(ExitCodes.Error); stdOut.GetString().Should().BeNullOrWhiteSpace(); stdOut.GetString().Should().NotContainAll("-h", "--help"); stdErr.GetString().Should().NotBeNullOrWhiteSpace(); stdErr.GetString().Should().Contain("Directive '[custom-interactive]' is for interactive mode only. Thus, cannot be used in normal mode."); _output.WriteLine(stdOut.GetString()); _output.WriteLine(stdErr.GetString()); }
public async Task Custom_directive_should_run() { // Arrange var(console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand <NamedCommand>() .UseConsole(console) .AddDirective <PreviewDirective>() .AddDirective <CustomDirective>() .AddDirective <CustomStopDirective>() .Build(); // Act int exitCode = await application.RunAsync( new[] { "[custom]", "named" }, new Dictionary <string, string>()); // Assert exitCode.Should().Be(ExitCodes.Success); stdOut.GetString().Should().NotBeNullOrWhiteSpace(); stdOut.GetString().Should().ContainAll( CustomDirective.ExpectedOutput, NamedCommand.ExpectedOutputText ); _output.WriteLine(stdOut.GetString()); }
public async Task Custom_interactive_directive_should_not_run_in_normal_mode() { // Arrange var(console, stdOut, stdErr) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand <NamedCommand>() .UseConsole(console) .AddDirective <PreviewDirective>() .AddDirective <CustomDirective>() .AddDirective <CustomStopDirective>() .AddDirective <CustomInteractiveModeOnlyDirective>() .Build(); // Act int exitCode = await application.RunAsync( new[] { "[custom-interactive]", "named", "param", "-abc", "--option", "foo" }, new Dictionary <string, string>()); // Assert exitCode.Should().NotBe(0); stdOut.GetString().Should().BeNullOrWhiteSpace(); stdOut.GetString().Should().NotContainAll( "@ [custom-interactive]", "Description", "Usage", "Directives", "[custom]" ); stdErr.GetString().Should().ContainAll( "Directive", "[custom-interactive]", "is for interactive mode only." ); _output.WriteLine(stdOut.GetString()); }
public async Task Application_without_interactive_mode_cannot_execute_interactive_only_commands() { // Arrange var(console, stdOut, stdErr) = VirtualConsole.CreateBuffered(); // Act var app = new CliApplicationBuilder().AddCommand <BenchmarkDefaultCommand>() .AddCommand <NamedInteractiveOnlyCommand>() .UseConsole(console) .Build(); // Assert app.Should().NotBeNull(); // Act int exitCode = await app.RunAsync(new string[] { "named-interactive-only" }, new Dictionary <string, string>()); // Asert exitCode.Should().Be(ExitCodes.Error); stdOut.GetString().Should().BeNullOrWhiteSpace(); stdErr.GetString().Should().NotBeNullOrWhiteSpace(); stdErr.GetString().Should().Contain("can be executed only in interactive mode, but this application is using CliApplication."); _output.WriteLine(stdOut.GetString()); _output.WriteLine(stdErr.GetString()); }
public async Task Option_only_uses_an_environment_variable_as_fallback_if_the_name_matches_case_sensitively() { var(console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand <WithEnvironmentVariablesCommand>() .UseConsole(console) .Build(); // Act int exitCode = await application.RunAsync( new[] { "cmd" }, new Dictionary <string, string> { ["ENV_opt_A"] = "incorrect", ["ENV_OPT_A"] = "correct" } ); var commandInstance = stdOut.GetString().DeserializeJson <WithEnvironmentVariablesCommand>(); // Assert exitCode.Should().Be(ExitCodes.Success); commandInstance.Should().BeEquivalentTo(new WithEnvironmentVariablesCommand { OptA = "correct" }); }
public async Task Command_may_throw_a_specialized_exception_without_error_message_which_exits_and_prints_full_error_details() { // Arrange var(console, stdOut, stdErr) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand <CommandExceptionCommand>() .UseConsole(console) .Build(); // Act int exitCode = await application.RunAsync(new[] { "cmd" }); // Assert exitCode.Should().NotBe(ExitCodes.Success); stdOut.GetString().Should().BeEmpty(); stdErr.GetString().Should().ContainAll( "Typin.Exceptions.CommandException:", "at", "Typin.Tests" ); _output.WriteLine(stdOut.GetString()); _output.WriteLine(stdErr.GetString()); }
public async Task Command_may_throw_a_specialized_exception_which_exits_and_prints_help_text() { // Arrange var(console, stdOut, stdErr) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand <CommandExceptionCommand>() .UseConsole(console) .Build(); // Act int exitCode = await application.RunAsync(new[] { "cmd", "-m", "Kaput", "--show-help" }); // Assert exitCode.Should().NotBe(ExitCodes.Success); stdOut.GetString().Should().ContainAll( "Usage", "Options", "-h|--help" ); stdErr.GetString().Trim().Should().Be("Kaput"); _output.WriteLine(stdOut.GetString()); _output.WriteLine(stdErr.GetString()); }
public async Task Command_do_not_show_help_text_on_invalid_user_input_with_default_exception_handler() { // Arrange var(console, stdOut, stdErr) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand <DefaultCommand>() .UseConsole(console) .Build(); // Act int exitCode = await application.RunAsync(new[] { "not-a-valid-command", "-r", "foo" }); // Assert exitCode.Should().NotBe(ExitCodes.Success); stdOut.GetString().Should().NotContainAll( "Usage", "Options", "-h|--help" ); stdErr.GetString().Should().NotBeNullOrWhiteSpace(); _output.WriteLine(stdOut.GetString()); _output.WriteLine(stdErr.GetString()); }
public async Task Command_may_throw_a_generic_exception_which_exits_and_prints_error_message_and_stack_trace() { // Arrange var(console, stdOut, stdErr) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand <GenericExceptionCommand>() .UseConsole(console) .Build(); // Act int exitCode = await application.RunAsync(new[] { "cmd", "-m", "Kaput" }); // Assert exitCode.Should().NotBe(ExitCodes.Success); stdOut.GetString().Should().BeEmpty(); stdErr.GetString().Should().ContainAll( "System.Exception:", "Kaput", "at", "Typin.Tests" ); _output.WriteLine(stdOut.GetString()); _output.WriteLine(stdErr.GetString()); }
public Benchmarks() { Day14 = new Day14(); Day15 = new Day15(); Day16 = new Day16(); (console, _, _) = VirtualConsole.CreateBuffered(); }
public async Task Middleware_pipeline_should_be_executed() { // Arrange var(console, stdOut, stdErr) = VirtualConsole.CreateBuffered(); // Act var app = new CliApplicationBuilder() .AddCommand <DefaultCommand>() .AddCommand <PipelineCommand>() .UseConsole(console) .UseMiddleware <ExecutionTimingMiddleware>() .UseMiddleware(typeof(ExitCodeMiddleware)) .Build(); // Assert app.Should().NotBeNull(); // Act int exitCode = await app.RunAsync(new string[] { }, new Dictionary <string, string>()); // Asert exitCode.Should().Be(0); stdOut.GetString().Should().NotBeNullOrWhiteSpace(); stdErr.GetString().Should().BeNullOrWhiteSpace(); stdOut.GetString().Should().ContainAll( ExecutionTimingMiddleware.ExpectedOutput0, ExecutionTimingMiddleware.ExpectedOutput1, ExitCodeMiddleware.ExpectedOutput, DefaultCommand.ExpectedOutputText); _output.WriteLine(stdOut.GetString()); }
public async Task Middleware_types_collection_should_contain_all_user_defined_middlewares() { // Arrange var(console, stdOut, stdErr) = VirtualConsole.CreateBuffered(); // Act var app = new CliApplicationBuilder() .AddCommand <DefaultCommand>() .AddCommand <PipelineCommand>() .UseConsole(console) .UseMiddleware <ExecutionTimingMiddleware>() .UseMiddleware(typeof(ExitCodeMiddleware)) .Build(); // Assert app.Should().NotBeNull(); // Act int exitCode = await app.RunAsync(new string[] { "pipeline" }, new Dictionary <string, string>()); // Asert exitCode.Should().Be(0); stdOut.GetString().Should().NotBeNullOrWhiteSpace(); stdErr.GetString().Should().BeNullOrWhiteSpace(); stdOut.GetString().Should().ContainAll( typeof(ExecutionTimingMiddleware).AssemblyQualifiedName, typeof(ExitCodeMiddleware).AssemblyQualifiedName, PipelineCommand.PipelineTermination, "Typin.Internal.Pipeline"); _output.WriteLine(stdOut.GetString()); }
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 var(console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand <DefaultCommand>() .AddCommand <NamedCommand>() .AddCommand <NamedSubCommand>() .UseConsole(console) .Build(); // Act int exitCode = await application.RunAsync(new[] { "named", "sub", "--help" }); // Assert exitCode.Should().Be(ExitCodes.Success); stdOut.GetString().Should().ContainAll( "Named sub command description", "Usage", "named", "sub" ); _output.WriteLine(stdOut.GetString()); }
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 var(console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand <SupportedArgumentTypesCommand>() .UseConsole(console) .Build(); // Act int exitCode = await application.RunAsync(new[] { "cmd", "--str-constructible-array", "foo", "bar" }); var commandInstance = stdOut.GetString().DeserializeJson <SupportedArgumentTypesCommand>(); // Assert exitCode.Should().Be(ExitCodes.Success); commandInstance.Should().BeEquivalentTo(new SupportedArgumentTypesCommand { StringConstructibleArray = new[] { new CustomStringConstructible("foo"), new CustomStringConstructible("bar") } }); }
public void Application_can_be_created_with_VirtualConsole_CreateBuffered() { // Arrange var(console, _, _) = VirtualConsole.CreateBuffered(isInputRedirected: false); // Act var app = new CliApplicationBuilder() .AddCommand <DefaultCommand>() .AddCommandsFrom(typeof(DefaultCommand).Assembly) .AddCommands(new[] { typeof(DefaultCommand) }) .AddCommandsFrom(new[] { typeof(DefaultCommand).Assembly }) .AddCommandsFromThisAssembly() .UseExceptionHandler(typeof(DefaultExceptionHandler)) .AddDirective <DebugDirective>() .AddDirective <PreviewDirective>() .AddDirective <CustomInteractiveModeOnlyDirective>() .AddDirective <CustomDirective>() .UseTitle("test") .UseExecutableName("test") .UseVersionText("test") .UseDescription("test") .UseConsole(console) .Build(); // Assert app.Should().NotBeNull(); }
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 var(console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand <SupportedArgumentTypesCommand>() .UseConsole(console) .Build(); // Act int exitCode = await application.RunAsync(new[] { "cmd", "--str-parseable-format", "foobar" }); var commandInstance = stdOut.GetString().DeserializeJson <SupportedArgumentTypesCommand>(); // Assert exitCode.Should().Be(ExitCodes.Success); commandInstance.Should().BeEquivalentTo(new SupportedArgumentTypesCommand { StringParseableWithFormatProvider = CustomStringParseableWithFormatProvider.Parse("foobar", CultureInfo.InvariantCulture) }); }
public void Table_utils_write_should_write_a_table2() { // Arrange var(console, stdOut, _) = VirtualConsole.CreateBuffered(isOutputRedirected: false, isErrorRedirected: false); // Act TableUtils.Write(console, _testData.GroupBy(x => x.Group), new string[] { "Header0", "Header1", "Header2" }, null, x => x.Integer.ToString(), x => x.Str ?? string.Empty); // Assert string output = stdOut.GetString(); output.Should().NotBeNullOrWhiteSpace(); output.Should().ContainAll("Header0", "Header1", "testA", "testB", "testC", "testD", "0", "1", "2", "3", "4", "X", "Z", "X (2)", "Z (2)", "(1)"); output.Should().NotContainAll("Header2"); _output.WriteLine(output); }
public async Task Property_of_type_nullable_int_array_is_bound_by_parsing_the_argument_values() { // Arrange var(console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand <SupportedArgumentTypesCommand>() .UseConsole(console) .Build(); // Act int exitCode = await application.RunAsync(new[] { "cmd", "--int-nullable-array", "3", "15" }); var commandInstance = stdOut.GetString().DeserializeJson <SupportedArgumentTypesCommand>(); // Assert exitCode.Should().Be(ExitCodes.Success); commandInstance.Should().BeEquivalentTo(new SupportedArgumentTypesCommand { IntNullableArray = new int?[] { 3, 15 } }); }
public async Task Option_of_non_scalar_type_can_use_an_environment_variable_as_fallback_and_extract_multiple_values() { var(console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand <WithEnvironmentVariablesCommand>() .UseConsole(console) .Build(); // Act int exitCode = await application.RunAsync( new[] { "cmd" }, new Dictionary <string, string> { ["ENV_OPT_B"] = $"foo{Path.PathSeparator}bar" } ); var commandInstance = stdOut.GetString().DeserializeJson <WithEnvironmentVariablesCommand>(); // Assert exitCode.Should().Be(ExitCodes.Success); commandInstance.Should().BeEquivalentTo(new WithEnvironmentVariablesCommand { OptB = new[] { "foo", "bar" } }); }
public async Task Property_of_type_string_is_bound_directly_from_the_argument_value() { // Arrange var(console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand <SupportedArgumentTypesCommand>() .UseConsole(console) .Build(); // Act int exitCode = await application.RunAsync(new[] { "cmd", "--str", "value" }); var commandInstance = stdOut.GetString().DeserializeJson <SupportedArgumentTypesCommand>(); // Assert exitCode.Should().Be(ExitCodes.Success); commandInstance.Should().BeEquivalentTo(new SupportedArgumentTypesCommand { String = "value" }); }
public async Task Default_directive_should_allow_default_command_to_execute_when_there_is_a_name_conflict() { // Arrange var(console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand <DefaultCommandWithParameter>() .AddCommand <NamedCommand>() .UseConsole(console) .AddDirective <DefaultDirective>() .Build(); // Act int exitCode = await application.RunAsync( new[] { "[!]", "named" }, new Dictionary <string, string>()); // Assert exitCode.Should().Be(ExitCodes.Success); stdOut.GetString().Should().NotBeNullOrWhiteSpace(); stdOut.GetString().Should().ContainAll( "named", DefaultCommandWithParameter.ExpectedOutputText ); _output.WriteLine(stdOut.GetString()); }
public async Task Property_of_type_DateTimeOffset_is_bound_by_parsing_the_argument_value() { // Arrange var(console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand <SupportedArgumentTypesCommand>() .UseConsole(console) .Build(); // Act int exitCode = await application.RunAsync(new[] { "cmd", "--datetime-offset", "28 Apr 1995" }); var commandInstance = stdOut.GetString().DeserializeJson <SupportedArgumentTypesCommand>(); // Assert exitCode.Should().Be(ExitCodes.Success); commandInstance.Should().BeEquivalentTo(new SupportedArgumentTypesCommand { DateTimeOffset = new DateTime(1995, 04, 28) }); }
public async Task Normal_mode_application_cannot_process_interactive_directive() { // Arrange var(console, stdOut, stdErr) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand <NamedCommand>() .UseConsole(console) .AddDirective <PreviewDirective>() .Build(); // Act int exitCode = await application.RunAsync( new[] { "[interactive]" }, new Dictionary <string, string>()); // Assert exitCode.Should().Be(ExitCodes.Error); stdOut.GetString().Should().BeNullOrWhiteSpace(); stdOut.GetString().Should().NotContainAll("-h", "--help"); stdErr.GetString().Should().NotBeNullOrWhiteSpace(); stdErr.GetString().Should().Contain("This application does not support interactive mode."); _output.WriteLine(stdOut.GetString()); _output.WriteLine(stdErr.GetString()); }
public async Task Property_of_type_nullable_TimeSpan_is_bound_as_null_if_the_argument_value_is_not_set() { // Arrange var(console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand <SupportedArgumentTypesCommand>() .UseConsole(console) .Build(); // Act int exitCode = await application.RunAsync(new[] { "cmd", "--timespan-nullable" }); var commandInstance = stdOut.GetString().DeserializeJson <SupportedArgumentTypesCommand>(); // Assert exitCode.Should().Be(ExitCodes.Success); commandInstance.Should().BeEquivalentTo(new SupportedArgumentTypesCommand { TimeSpanNullable = null }); }
public async Task Custom_directive_should_have_non_empty_name() { // Arrange var(console, stdOut, stdErr) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand <NamedCommand>() .UseConsole(console) .AddDirective <PreviewDirective>() .AddDirective <EmptyNameDirective>() .Build(); // Act int exitCode = await application.RunAsync( new[] { "[preview]", "named", "param", "-abc", "--option", "foo" }, new Dictionary <string, string>()); // Assert exitCode.Should().Be(ExitCodes.Error); stdOut.GetString().Should().BeNullOrWhiteSpace(); stdErr.GetString().Should().NotBeNullOrWhiteSpace(); stdErr.GetString().Should().Contain("[ ]"); _output.WriteLine(stdOut.GetString()); _output.WriteLine(stdErr.GetString()); }
public async Task Property_of_a_nullable_enum_type_is_bound_by_parsing_the_argument_value_as_name_if_it_is_set() { // Arrange var(console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand <SupportedArgumentTypesCommand>() .UseConsole(console) .Build(); // Act int exitCode = await application.RunAsync(new[] { "cmd", "--enum-nullable", "value3" }); var commandInstance = stdOut.GetString().DeserializeJson <SupportedArgumentTypesCommand>(); // Assert exitCode.Should().Be(ExitCodes.Success); commandInstance.Should().BeEquivalentTo(new SupportedArgumentTypesCommand { EnumNullable = CustomEnum.Value3 }); }
public async Task Preview_directive_can_be_specified_to_print_provided_arguments_as_they_were_parsed() { // Arrange var(console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand <NamedCommand>() .UseConsole(console) .AddDirective <PreviewDirective>() .Build(); // Act int exitCode = await application.RunAsync( new[] { "[preview]", "named", "param", "-abc", "--option", "foo" }, new Dictionary <string, string>()); // Assert exitCode.Should().Be(ExitCodes.Success); stdOut.GetString().Should().NotBeNullOrWhiteSpace(); stdOut.GetString().Should().ContainAll( "named", "<param>", "[-a]", "[-b]", "[-c]", "[--option \"foo\"]" ); _output.WriteLine(stdOut.GetString()); }
public async Task Help_text_shows_usage_format_which_lists_all_required_options() { // Arrange var(console, stdOut, _) = VirtualConsole.CreateBuffered(); var application = new CliApplicationBuilder() .AddCommand <WithRequiredOptionsCommand>() .UseConsole(console) .Build(); // Act int exitCode = await application.RunAsync(new[] { "cmd", "--help" }); // Assert exitCode.Should().Be(ExitCodes.Success); stdOut.GetString().Should().ContainAll( "Usage", "cmd", "--opt-a <value>", "--opt-c <values...>", "[options]", "Options", "* -a|--opt-a", "-b|--opt-b", "* -c|--opt-c" ); _output.WriteLine(stdOut.GetString()); }