Information
- OS: Linux
- Version: 0.50.0
- Terminal: VS Code
Describe the bug
When uncaught exception is thrown during command execution while executing test, CommandAppTester throws System.ObjectDisposedException : Cannot write to a closed TextWriter..
To Reproduce
using System.Reflection;
using Microsoft.Extensions.DependencyInjection;
using Spectre.Console;
using Spectre.Console.Cli;
using Spectre.Console.Testing;
using Xunit;
namespace GitHub.Issues;
/// <summary>
/// A Spectre.Console Command
/// </summary>
public class HelloWorldCommand(IAnsiConsole console) : Command
{
private readonly IAnsiConsole _console = console;
public override int Execute(CommandContext context)
{
throw new NotImplementedException(); // intentionally throw to reproduce easily
}
}
/// <summary>
/// A Spectre.Console AsyncCommand
/// </summary>
public class AsyncHelloWorldCommand(IAnsiConsole console) : AsyncCommand
{
private readonly IAnsiConsole _console = console;
public override Task<int> ExecuteAsync(CommandContext context)
{
throw new NotImplementedException(); // intentionally throw to reproduce easily
}
}
public class TestConsoleBugTests
{
[Fact]
public void Should_Not_Throw_ObjectDisposed_Exception_When_TypeRegistrar_Is_Used()
{
// Given
var app = new CommandAppTester(WithServices());
app.SetDefaultCommand<HelloWorldCommand>();
// When
var result = app.RunAndCatch<Exception>();
// Then
result.Exception.Should().NotBeOfType<ObjectDisposedException>();
}
[Fact]
public void Should_Not_Throw_ObjectDisposed_Exception_When_Custom_TypeRegistrar_Is_Used()
{
// Given
var app = new CommandAppTester(WithServices());
app.SetDefaultCommand<HelloWorldCommand>();
// When
var result = app.Run();
// Then
result.ExitCode.Should().NotBe(0);
result.Output.Should().Be("Error: The method or operation is not implemented.");
}
[Fact]
public void Should_Not_Throw_ObjectDisposed_Exception_When_TypeRegistrar_Is_Not_Used()
{
// Given
var app = new CommandAppTester();
app.SetDefaultCommand<HelloWorldCommand>();
// When
var result = app.Run();
// Then
result.ExitCode.Should().NotBe(0);
result.Output.Should().Be("Error: The method or operation is not implemented.");
}
[Fact]
public async Task Should_Not_Throw_ObjectDisposed_Exception_When_TypeRegistrar_Is_Used_Async()
{
// Given
var app = new CommandAppTester(WithServices());
app.SetDefaultCommand<AsyncHelloWorldCommand>();
// When
var result = await app.RunAsync();
// Then
result.ExitCode.Should().NotBe(0);
result.Output.Should().Be("Error: The method or operation is not implemented.");
}
private ITypeRegistrar WithServices()
{
var services = new ServiceCollection();
// Create a type registrar and register any dependencies.
// A type registrar is an adapter for a DI framework.
return new MyTypeRegistrar(services);
}
}
public sealed class MyTypeResolver : ITypeResolver, IDisposable
{
private readonly IServiceProvider _provider;
public MyTypeResolver(IServiceProvider provider)
{
_provider = provider ?? throw new ArgumentNullException(nameof(provider));
}
public object Resolve(Type type)
{
if (type == null)
{
return null;
}
return _provider.GetService(type);
}
public void Dispose()
{
if (_provider is IDisposable disposable)
{
disposable.Dispose();
}
}
}
public sealed class MyTypeRegistrar : ITypeRegistrar
{
private readonly IServiceCollection _builder;
public MyTypeRegistrar(IServiceCollection builder)
{
_builder = builder;
}
public ITypeResolver Build()
{
return new MyTypeResolver(_builder.BuildServiceProvider());
}
public void Register(Type service, Type implementation)
{
_builder.AddSingleton(service, implementation);
}
public void RegisterInstance(Type service, object implementation)
{
_builder.AddSingleton(service, implementation);
}
public void RegisterLazy(Type service, Func<object> func)
{
if (func is null)
{
throw new ArgumentNullException(nameof(func));
}
_builder.AddSingleton(service, (provider) => func());
}
}
Expected behavior
I expect new CommandAppTester().Run() and new CommandAppTester(myTypeRegistrar).Run() to behave the same way. A non-zero exit code should be returned and message printed to console.
Screenshots
Behavior can be observed by running the above tests.
Additional context
None.
Information
Describe the bug
When uncaught exception is thrown during command execution while executing test,
CommandAppTesterthrowsSystem.ObjectDisposedException : Cannot write to a closed TextWriter..To Reproduce
Expected behavior
I expect
new CommandAppTester().Run()andnew CommandAppTester(myTypeRegistrar).Run()to behave the same way. A non-zero exit code should be returned and message printed to console.Screenshots
Behavior can be observed by running the above tests.
Additional context
None.