mirror of
				https://github.com/nsnail/spectre.console.git
				synced 2025-11-04 02:25:28 +08:00 
			
		
		
		
	Add global usings (#668)
* Use global usings * Fix namespace declarations for test projects
This commit is contained in:
		@@ -1,21 +1,18 @@
 | 
			
		||||
using Spectre.Console.Cli;
 | 
			
		||||
namespace Spectre.Console.Tests;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests
 | 
			
		||||
public static class Constants
 | 
			
		||||
{
 | 
			
		||||
    public static class Constants
 | 
			
		||||
    {
 | 
			
		||||
        public static string[] VersionCommand { get; } =
 | 
			
		||||
            new[]
 | 
			
		||||
            {
 | 
			
		||||
    public static string[] VersionCommand { get; } =
 | 
			
		||||
        new[]
 | 
			
		||||
        {
 | 
			
		||||
                CliConstants.Commands.Branch,
 | 
			
		||||
                CliConstants.Commands.Version,
 | 
			
		||||
            };
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        public static string[] XmlDocCommand { get; } =
 | 
			
		||||
            new[]
 | 
			
		||||
            {
 | 
			
		||||
    public static string[] XmlDocCommand { get; } =
 | 
			
		||||
        new[]
 | 
			
		||||
        {
 | 
			
		||||
                CliConstants.Commands.Branch,
 | 
			
		||||
                CliConstants.Commands.XmlDoc,
 | 
			
		||||
            };
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
        };
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,49 +1,45 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using Spectre.Console.Cli;
 | 
			
		||||
using SystemConsole = System.Console;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Data
 | 
			
		||||
namespace Spectre.Console.Tests.Data;
 | 
			
		||||
 | 
			
		||||
public abstract class AnimalCommand<TSettings> : Command<TSettings>
 | 
			
		||||
    where TSettings : CommandSettings
 | 
			
		||||
{
 | 
			
		||||
    public abstract class AnimalCommand<TSettings> : Command<TSettings>
 | 
			
		||||
        where TSettings : CommandSettings
 | 
			
		||||
    protected void DumpSettings(CommandContext context, TSettings settings)
 | 
			
		||||
    {
 | 
			
		||||
        protected void DumpSettings(CommandContext context, TSettings settings)
 | 
			
		||||
        if (context == null)
 | 
			
		||||
        {
 | 
			
		||||
            if (context == null)
 | 
			
		||||
            {
 | 
			
		||||
                throw new ArgumentNullException(nameof(context));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (settings == null)
 | 
			
		||||
            {
 | 
			
		||||
                throw new ArgumentNullException(nameof(settings));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var properties = settings.GetType().GetProperties();
 | 
			
		||||
            foreach (var group in properties.GroupBy(x => x.DeclaringType).Reverse())
 | 
			
		||||
            {
 | 
			
		||||
                SystemConsole.WriteLine();
 | 
			
		||||
                SystemConsole.ForegroundColor = ConsoleColor.Yellow;
 | 
			
		||||
                SystemConsole.WriteLine(group.Key.FullName);
 | 
			
		||||
                SystemConsole.ResetColor();
 | 
			
		||||
 | 
			
		||||
                foreach (var property in group)
 | 
			
		||||
                {
 | 
			
		||||
                    SystemConsole.WriteLine($"  {property.Name} = {property.GetValue(settings)}");
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (context.Remaining.Raw.Count > 0)
 | 
			
		||||
            {
 | 
			
		||||
                SystemConsole.WriteLine();
 | 
			
		||||
                SystemConsole.ForegroundColor = ConsoleColor.Yellow;
 | 
			
		||||
                SystemConsole.WriteLine("Remaining:");
 | 
			
		||||
                SystemConsole.ResetColor();
 | 
			
		||||
                SystemConsole.WriteLine(string.Join(", ", context.Remaining));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            SystemConsole.WriteLine();
 | 
			
		||||
            throw new ArgumentNullException(nameof(context));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (settings == null)
 | 
			
		||||
        {
 | 
			
		||||
            throw new ArgumentNullException(nameof(settings));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var properties = settings.GetType().GetProperties();
 | 
			
		||||
        foreach (var group in properties.GroupBy(x => x.DeclaringType).Reverse())
 | 
			
		||||
        {
 | 
			
		||||
            SystemConsole.WriteLine();
 | 
			
		||||
            SystemConsole.ForegroundColor = ConsoleColor.Yellow;
 | 
			
		||||
            SystemConsole.WriteLine(group.Key.FullName);
 | 
			
		||||
            SystemConsole.ResetColor();
 | 
			
		||||
 | 
			
		||||
            foreach (var property in group)
 | 
			
		||||
            {
 | 
			
		||||
                SystemConsole.WriteLine($"  {property.Name} = {property.GetValue(settings)}");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (context.Remaining.Raw.Count > 0)
 | 
			
		||||
        {
 | 
			
		||||
            SystemConsole.WriteLine();
 | 
			
		||||
            SystemConsole.ForegroundColor = ConsoleColor.Yellow;
 | 
			
		||||
            SystemConsole.WriteLine("Remaining:");
 | 
			
		||||
            SystemConsole.ResetColor();
 | 
			
		||||
            SystemConsole.WriteLine(string.Join(", ", context.Remaining));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        SystemConsole.WriteLine();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,13 +1,10 @@
 | 
			
		||||
using Spectre.Console.Cli;
 | 
			
		||||
namespace Spectre.Console.Tests.Data;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Data
 | 
			
		||||
public class CatCommand : AnimalCommand<CatSettings>
 | 
			
		||||
{
 | 
			
		||||
    public class CatCommand : AnimalCommand<CatSettings>
 | 
			
		||||
    public override int Execute(CommandContext context, CatSettings settings)
 | 
			
		||||
    {
 | 
			
		||||
        public override int Execute(CommandContext context, CatSettings settings)
 | 
			
		||||
        {
 | 
			
		||||
            DumpSettings(context, settings);
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
        DumpSettings(context, settings);
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,36 +1,31 @@
 | 
			
		||||
using System.ComponentModel;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using Spectre.Console.Cli;
 | 
			
		||||
namespace Spectre.Console.Tests.Data;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Data
 | 
			
		||||
[Description("The dog command.")]
 | 
			
		||||
public class DogCommand : AnimalCommand<DogSettings>
 | 
			
		||||
{
 | 
			
		||||
    [Description("The dog command.")]
 | 
			
		||||
    public class DogCommand : AnimalCommand<DogSettings>
 | 
			
		||||
    public override ValidationResult Validate(CommandContext context, DogSettings settings)
 | 
			
		||||
    {
 | 
			
		||||
        public override ValidationResult Validate(CommandContext context, DogSettings settings)
 | 
			
		||||
        if (context is null)
 | 
			
		||||
        {
 | 
			
		||||
            if (context is null)
 | 
			
		||||
            {
 | 
			
		||||
                throw new System.ArgumentNullException(nameof(context));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (settings is null)
 | 
			
		||||
            {
 | 
			
		||||
                throw new System.ArgumentNullException(nameof(settings));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (settings.Age > 100 && !context.Remaining.Raw.Contains("zombie"))
 | 
			
		||||
            {
 | 
			
		||||
                return ValidationResult.Error("Dog is too old...");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return base.Validate(context, settings);
 | 
			
		||||
            throw new System.ArgumentNullException(nameof(context));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public override int Execute(CommandContext context, DogSettings settings)
 | 
			
		||||
        if (settings is null)
 | 
			
		||||
        {
 | 
			
		||||
            DumpSettings(context, settings);
 | 
			
		||||
            return 0;
 | 
			
		||||
            throw new System.ArgumentNullException(nameof(settings));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (settings.Age > 100 && !context.Remaining.Raw.Contains("zombie"))
 | 
			
		||||
        {
 | 
			
		||||
            return ValidationResult.Error("Dog is too old...");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return base.Validate(context, settings);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    public override int Execute(CommandContext context, DogSettings settings)
 | 
			
		||||
    {
 | 
			
		||||
        DumpSettings(context, settings);
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,39 +1,34 @@
 | 
			
		||||
using System.Diagnostics.CodeAnalysis;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using Spectre.Console.Cli;
 | 
			
		||||
namespace Spectre.Console.Tests.Data;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Data
 | 
			
		||||
public sealed class DumpRemainingCommand : Command<EmptyCommandSettings>
 | 
			
		||||
{
 | 
			
		||||
    public sealed class DumpRemainingCommand : Command<EmptyCommandSettings>
 | 
			
		||||
    private readonly IAnsiConsole _console;
 | 
			
		||||
 | 
			
		||||
    public DumpRemainingCommand(IAnsiConsole console)
 | 
			
		||||
    {
 | 
			
		||||
        private readonly IAnsiConsole _console;
 | 
			
		||||
 | 
			
		||||
        public DumpRemainingCommand(IAnsiConsole console)
 | 
			
		||||
        {
 | 
			
		||||
            _console = console;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public override int Execute([NotNull] CommandContext context, [NotNull] EmptyCommandSettings settings)
 | 
			
		||||
        {
 | 
			
		||||
            if (context.Remaining.Raw.Count > 0)
 | 
			
		||||
            {
 | 
			
		||||
                _console.WriteLine("# Raw");
 | 
			
		||||
                foreach (var item in context.Remaining.Raw)
 | 
			
		||||
                {
 | 
			
		||||
                    _console.WriteLine(item);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (context.Remaining.Parsed.Count > 0)
 | 
			
		||||
            {
 | 
			
		||||
                _console.WriteLine("# Parsed");
 | 
			
		||||
                foreach (var item in context.Remaining.Parsed)
 | 
			
		||||
                {
 | 
			
		||||
                    _console.WriteLine(string.Format("{0}={1}", item.Key, string.Join(",", item.Select(x => x))));
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
        _console = console;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    public override int Execute([NotNull] CommandContext context, [NotNull] EmptyCommandSettings settings)
 | 
			
		||||
    {
 | 
			
		||||
        if (context.Remaining.Raw.Count > 0)
 | 
			
		||||
        {
 | 
			
		||||
            _console.WriteLine("# Raw");
 | 
			
		||||
            foreach (var item in context.Remaining.Raw)
 | 
			
		||||
            {
 | 
			
		||||
                _console.WriteLine(item);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (context.Remaining.Parsed.Count > 0)
 | 
			
		||||
        {
 | 
			
		||||
            _console.WriteLine("# Parsed");
 | 
			
		||||
            foreach (var item in context.Remaining.Parsed)
 | 
			
		||||
            {
 | 
			
		||||
                _console.WriteLine(string.Format("{0}={1}", item.Key, string.Join(",", item.Select(x => x))));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,12 +1,9 @@
 | 
			
		||||
using Spectre.Console.Cli;
 | 
			
		||||
namespace Spectre.Console.Tests.Data;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Data
 | 
			
		||||
public sealed class EmptyCommand : Command<EmptyCommandSettings>
 | 
			
		||||
{
 | 
			
		||||
    public sealed class EmptyCommand : Command<EmptyCommandSettings>
 | 
			
		||||
    public override int Execute(CommandContext context, EmptyCommandSettings settings)
 | 
			
		||||
    {
 | 
			
		||||
        public override int Execute(CommandContext context, EmptyCommandSettings settings)
 | 
			
		||||
        {
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,13 +1,10 @@
 | 
			
		||||
using Spectre.Console.Cli;
 | 
			
		||||
namespace Spectre.Console.Tests.Data;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Data
 | 
			
		||||
public sealed class GenericCommand<TSettings> : Command<TSettings>
 | 
			
		||||
    where TSettings : CommandSettings
 | 
			
		||||
{
 | 
			
		||||
    public sealed class GenericCommand<TSettings> : Command<TSettings>
 | 
			
		||||
        where TSettings : CommandSettings
 | 
			
		||||
    public override int Execute(CommandContext context, TSettings settings)
 | 
			
		||||
    {
 | 
			
		||||
        public override int Execute(CommandContext context, TSettings settings)
 | 
			
		||||
        {
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,14 +1,10 @@
 | 
			
		||||
using System.ComponentModel;
 | 
			
		||||
using Spectre.Console.Cli;
 | 
			
		||||
namespace Spectre.Console.Tests.Data;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Data
 | 
			
		||||
[Description("The giraffe command.")]
 | 
			
		||||
public sealed class GiraffeCommand : Command<GiraffeSettings>
 | 
			
		||||
{
 | 
			
		||||
    [Description("The giraffe command.")]
 | 
			
		||||
    public sealed class GiraffeCommand : Command<GiraffeSettings>
 | 
			
		||||
    public override int Execute(CommandContext context, GiraffeSettings settings)
 | 
			
		||||
    {
 | 
			
		||||
        public override int Execute(CommandContext context, GiraffeSettings settings)
 | 
			
		||||
        {
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,12 +1,9 @@
 | 
			
		||||
using Spectre.Console.Cli;
 | 
			
		||||
namespace Spectre.Console.Tests.Data;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Data
 | 
			
		||||
public sealed class HiddenOptionsCommand : Command<HiddenOptionSettings>
 | 
			
		||||
{
 | 
			
		||||
    public sealed class HiddenOptionsCommand : Command<HiddenOptionSettings>
 | 
			
		||||
    public override int Execute(CommandContext context, HiddenOptionSettings settings)
 | 
			
		||||
    {
 | 
			
		||||
        public override int Execute(CommandContext context, HiddenOptionSettings settings)
 | 
			
		||||
        {
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,15 +1,11 @@
 | 
			
		||||
using System.ComponentModel;
 | 
			
		||||
using Spectre.Console.Cli;
 | 
			
		||||
namespace Spectre.Console.Tests.Data;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Data
 | 
			
		||||
[Description("The horse command.")]
 | 
			
		||||
public class HorseCommand : AnimalCommand<MammalSettings>
 | 
			
		||||
{
 | 
			
		||||
    [Description("The horse command.")]
 | 
			
		||||
    public class HorseCommand : AnimalCommand<MammalSettings>
 | 
			
		||||
    public override int Execute(CommandContext context, MammalSettings settings)
 | 
			
		||||
    {
 | 
			
		||||
        public override int Execute(CommandContext context, MammalSettings settings)
 | 
			
		||||
        {
 | 
			
		||||
            DumpSettings(context, settings);
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
        DumpSettings(context, settings);
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,12 +1,9 @@
 | 
			
		||||
using Spectre.Console.Cli;
 | 
			
		||||
namespace Spectre.Console.Tests.Data;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Data
 | 
			
		||||
public sealed class InvalidCommand : Command<InvalidSettings>
 | 
			
		||||
{
 | 
			
		||||
    public sealed class InvalidCommand : Command<InvalidSettings>
 | 
			
		||||
    public override int Execute(CommandContext context, InvalidSettings settings)
 | 
			
		||||
    {
 | 
			
		||||
        public override int Execute(CommandContext context, InvalidSettings settings)
 | 
			
		||||
        {
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,14 +1,10 @@
 | 
			
		||||
using System.ComponentModel;
 | 
			
		||||
using Spectre.Console.Cli;
 | 
			
		||||
namespace Spectre.Console.Tests.Data;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Data
 | 
			
		||||
[Description("The lion command.")]
 | 
			
		||||
public class LionCommand : AnimalCommand<LionSettings>
 | 
			
		||||
{
 | 
			
		||||
    [Description("The lion command.")]
 | 
			
		||||
    public class LionCommand : AnimalCommand<LionSettings>
 | 
			
		||||
    public override int Execute(CommandContext context, LionSettings settings)
 | 
			
		||||
    {
 | 
			
		||||
        public override int Execute(CommandContext context, LionSettings settings)
 | 
			
		||||
        {
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,16 +1,12 @@
 | 
			
		||||
using System.Diagnostics.CodeAnalysis;
 | 
			
		||||
using Spectre.Console.Cli;
 | 
			
		||||
namespace Spectre.Console.Tests.Data;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Data
 | 
			
		||||
public sealed class NoDescriptionCommand : Command<EmptyCommandSettings>
 | 
			
		||||
{
 | 
			
		||||
    public sealed class NoDescriptionCommand : Command<EmptyCommandSettings>
 | 
			
		||||
    {
 | 
			
		||||
        [CommandOption("-f|--foo <VALUE>")]
 | 
			
		||||
        public int Foo { get; set; }
 | 
			
		||||
    [CommandOption("-f|--foo <VALUE>")]
 | 
			
		||||
    public int Foo { get; set; }
 | 
			
		||||
 | 
			
		||||
        public override int Execute([NotNull] CommandContext context, [NotNull] EmptyCommandSettings settings)
 | 
			
		||||
        {
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
    public override int Execute([NotNull] CommandContext context, [NotNull] EmptyCommandSettings settings)
 | 
			
		||||
    {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,12 +1,9 @@
 | 
			
		||||
using Spectre.Console.Cli;
 | 
			
		||||
namespace Spectre.Console.Tests.Data;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Data
 | 
			
		||||
public class OptionVectorCommand : Command<OptionVectorSettings>
 | 
			
		||||
{
 | 
			
		||||
    public class OptionVectorCommand : Command<OptionVectorSettings>
 | 
			
		||||
    public override int Execute(CommandContext context, OptionVectorSettings settings)
 | 
			
		||||
    {
 | 
			
		||||
        public override int Execute(CommandContext context, OptionVectorSettings settings)
 | 
			
		||||
        {
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,17 +1,13 @@
 | 
			
		||||
using System;
 | 
			
		||||
using Spectre.Console.Cli;
 | 
			
		||||
namespace Spectre.Console.Tests.Data;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Data
 | 
			
		||||
public sealed class ThrowingCommand : Command<ThrowingCommandSettings>
 | 
			
		||||
{
 | 
			
		||||
    public sealed class ThrowingCommand : Command<ThrowingCommandSettings>
 | 
			
		||||
    public override int Execute(CommandContext context, ThrowingCommandSettings settings)
 | 
			
		||||
    {
 | 
			
		||||
        public override int Execute(CommandContext context, ThrowingCommandSettings settings)
 | 
			
		||||
        {
 | 
			
		||||
            throw new InvalidOperationException("W00t?");
 | 
			
		||||
        }
 | 
			
		||||
        throw new InvalidOperationException("W00t?");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    public sealed class ThrowingCommandSettings : CommandSettings
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
public sealed class ThrowingCommandSettings : CommandSettings
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,18 +1,14 @@
 | 
			
		||||
using System.ComponentModel;
 | 
			
		||||
using System.Globalization;
 | 
			
		||||
namespace Spectre.Console.Tests.Data;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Data
 | 
			
		||||
public sealed class CatAgilityConverter : TypeConverter
 | 
			
		||||
{
 | 
			
		||||
    public sealed class CatAgilityConverter : TypeConverter
 | 
			
		||||
    public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
 | 
			
		||||
    {
 | 
			
		||||
        public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
 | 
			
		||||
        if (value is string stringValue)
 | 
			
		||||
        {
 | 
			
		||||
            if (value is string stringValue)
 | 
			
		||||
            {
 | 
			
		||||
                return stringValue.Length;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return base.ConvertFrom(context, culture, value);
 | 
			
		||||
            return stringValue.Length;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return base.ConvertFrom(context, culture, value);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,18 +1,14 @@
 | 
			
		||||
using System.ComponentModel;
 | 
			
		||||
using System.Globalization;
 | 
			
		||||
namespace Spectre.Console.Tests.Data;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Data
 | 
			
		||||
public sealed class StringToIntegerConverter : TypeConverter
 | 
			
		||||
{
 | 
			
		||||
    public sealed class StringToIntegerConverter : TypeConverter
 | 
			
		||||
    public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
 | 
			
		||||
    {
 | 
			
		||||
        public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
 | 
			
		||||
        if (value is string stringValue)
 | 
			
		||||
        {
 | 
			
		||||
            if (value is string stringValue)
 | 
			
		||||
            {
 | 
			
		||||
                return int.Parse(stringValue, CultureInfo.InvariantCulture);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return base.ConvertFrom(context, culture, value);
 | 
			
		||||
            return int.Parse(stringValue, CultureInfo.InvariantCulture);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return base.ConvertFrom(context, culture, value);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,35 +1,32 @@
 | 
			
		||||
using System;
 | 
			
		||||
namespace Spectre.Console.Tests.Data;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Data
 | 
			
		||||
public static class TestExceptions
 | 
			
		||||
{
 | 
			
		||||
    public static class TestExceptions
 | 
			
		||||
    public static bool MethodThatThrows(int? number) => throw new InvalidOperationException("Throwing!");
 | 
			
		||||
 | 
			
		||||
    public static bool GenericMethodThatThrows<T0, T1, TRet>(int? number) => throw new InvalidOperationException("Throwing!");
 | 
			
		||||
 | 
			
		||||
    public static void ThrowWithInnerException()
 | 
			
		||||
    {
 | 
			
		||||
        public static bool MethodThatThrows(int? number) => throw new InvalidOperationException("Throwing!");
 | 
			
		||||
 | 
			
		||||
        public static bool GenericMethodThatThrows<T0, T1, TRet>(int? number) => throw new InvalidOperationException("Throwing!");
 | 
			
		||||
 | 
			
		||||
        public static void ThrowWithInnerException()
 | 
			
		||||
        try
 | 
			
		||||
        {
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                MethodThatThrows(null);
 | 
			
		||||
            }
 | 
			
		||||
            catch (Exception ex)
 | 
			
		||||
            {
 | 
			
		||||
                throw new InvalidOperationException("Something threw!", ex);
 | 
			
		||||
            }
 | 
			
		||||
            MethodThatThrows(null);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static void ThrowWithGenericInnerException()
 | 
			
		||||
        catch (Exception ex)
 | 
			
		||||
        {
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                GenericMethodThatThrows<int, float, double>(null);
 | 
			
		||||
            }
 | 
			
		||||
            catch (Exception ex)
 | 
			
		||||
            {
 | 
			
		||||
                throw new InvalidOperationException("Something threw!", ex);
 | 
			
		||||
            }
 | 
			
		||||
            throw new InvalidOperationException("Something threw!", ex);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    public static void ThrowWithGenericInnerException()
 | 
			
		||||
    {
 | 
			
		||||
        try
 | 
			
		||||
        {
 | 
			
		||||
            GenericMethodThatThrows<int, float, double>(null);
 | 
			
		||||
        }
 | 
			
		||||
        catch (Exception ex)
 | 
			
		||||
        {
 | 
			
		||||
            throw new InvalidOperationException("Something threw!", ex);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,18 +1,14 @@
 | 
			
		||||
using System.ComponentModel;
 | 
			
		||||
using Spectre.Console.Cli;
 | 
			
		||||
namespace Spectre.Console.Tests.Data;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Data
 | 
			
		||||
public abstract class AnimalSettings : CommandSettings
 | 
			
		||||
{
 | 
			
		||||
    public abstract class AnimalSettings : CommandSettings
 | 
			
		||||
    {
 | 
			
		||||
        [CommandOption("-a|--alive|--not-dead")]
 | 
			
		||||
        [Description("Indicates whether or not the animal is alive.")]
 | 
			
		||||
        public bool IsAlive { get; set; }
 | 
			
		||||
    [CommandOption("-a|--alive|--not-dead")]
 | 
			
		||||
    [Description("Indicates whether or not the animal is alive.")]
 | 
			
		||||
    public bool IsAlive { get; set; }
 | 
			
		||||
 | 
			
		||||
        [CommandArgument(1, "[LEGS]")]
 | 
			
		||||
        [Description("The number of legs.")]
 | 
			
		||||
        [EvenNumberValidator("Animals must have an even number of legs.")]
 | 
			
		||||
        [PositiveNumberValidator("Number of legs must be greater than 0.")]
 | 
			
		||||
        public int Legs { get; set; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
    [CommandArgument(1, "[LEGS]")]
 | 
			
		||||
    [Description("The number of legs.")]
 | 
			
		||||
    [EvenNumberValidator("Animals must have an even number of legs.")]
 | 
			
		||||
    [PositiveNumberValidator("Number of legs must be greater than 0.")]
 | 
			
		||||
    public int Legs { get; set; }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,22 +1,19 @@
 | 
			
		||||
using Spectre.Console.Cli;
 | 
			
		||||
namespace Spectre.Console.Tests.Data;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Data
 | 
			
		||||
public sealed class ArgumentOrderSettings : CommandSettings
 | 
			
		||||
{
 | 
			
		||||
    public sealed class ArgumentOrderSettings : CommandSettings
 | 
			
		||||
    {
 | 
			
		||||
        [CommandArgument(0, "[QUX]")]
 | 
			
		||||
        public int Qux { get; set; }
 | 
			
		||||
    [CommandArgument(0, "[QUX]")]
 | 
			
		||||
    public int Qux { get; set; }
 | 
			
		||||
 | 
			
		||||
        [CommandArgument(3, "<CORGI>")]
 | 
			
		||||
        public int Corgi { get; set; }
 | 
			
		||||
    [CommandArgument(3, "<CORGI>")]
 | 
			
		||||
    public int Corgi { get; set; }
 | 
			
		||||
 | 
			
		||||
        [CommandArgument(1, "<BAR>")]
 | 
			
		||||
        public int Bar { get; set; }
 | 
			
		||||
    [CommandArgument(1, "<BAR>")]
 | 
			
		||||
    public int Bar { get; set; }
 | 
			
		||||
 | 
			
		||||
        [CommandArgument(2, "<BAZ>")]
 | 
			
		||||
        public int Baz { get; set; }
 | 
			
		||||
    [CommandArgument(2, "<BAZ>")]
 | 
			
		||||
    public int Baz { get; set; }
 | 
			
		||||
 | 
			
		||||
        [CommandArgument(0, "<FOO>")]
 | 
			
		||||
        public int Foo { get; set; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
    [CommandArgument(0, "<FOO>")]
 | 
			
		||||
    public int Foo { get; set; }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,10 +1,7 @@
 | 
			
		||||
using Spectre.Console.Cli;
 | 
			
		||||
namespace Spectre.Console.Tests.Data;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Data
 | 
			
		||||
public class ArgumentVectorSettings : CommandSettings
 | 
			
		||||
{
 | 
			
		||||
    public class ArgumentVectorSettings : CommandSettings
 | 
			
		||||
    {
 | 
			
		||||
        [CommandArgument(0, "<Foos>")]
 | 
			
		||||
        public string[] Foo { get; set; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
    [CommandArgument(0, "<Foos>")]
 | 
			
		||||
    public string[] Foo { get; set; }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,12 +1,8 @@
 | 
			
		||||
using System.ComponentModel;
 | 
			
		||||
using Spectre.Console.Cli;
 | 
			
		||||
namespace Spectre.Console.Tests.Data;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Data
 | 
			
		||||
public class BarCommandSettings : FooCommandSettings
 | 
			
		||||
{
 | 
			
		||||
    public class BarCommandSettings : FooCommandSettings
 | 
			
		||||
    {
 | 
			
		||||
        [CommandArgument(0, "<CORGI>")]
 | 
			
		||||
        [Description("The corgi value.")]
 | 
			
		||||
        public string Corgi { get; set; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
    [CommandArgument(0, "<CORGI>")]
 | 
			
		||||
    [Description("The corgi value.")]
 | 
			
		||||
    public string Corgi { get; set; }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,15 +1,11 @@
 | 
			
		||||
using System.ComponentModel;
 | 
			
		||||
using Spectre.Console.Cli;
 | 
			
		||||
namespace Spectre.Console.Tests.Data;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Data
 | 
			
		||||
public class CatSettings : MammalSettings
 | 
			
		||||
{
 | 
			
		||||
    public class CatSettings : MammalSettings
 | 
			
		||||
    {
 | 
			
		||||
        [CommandOption("--agility <VALUE>")]
 | 
			
		||||
        [TypeConverter(typeof(CatAgilityConverter))]
 | 
			
		||||
        [DefaultValue(10)]
 | 
			
		||||
        [Description("The agility between 0 and 100.")]
 | 
			
		||||
        [PositiveNumberValidator("Agility cannot be negative.")]
 | 
			
		||||
        public int Agility { get; set; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
    [CommandOption("--agility <VALUE>")]
 | 
			
		||||
    [TypeConverter(typeof(CatAgilityConverter))]
 | 
			
		||||
    [DefaultValue(10)]
 | 
			
		||||
    [Description("The agility between 0 and 100.")]
 | 
			
		||||
    [PositiveNumberValidator("Agility cannot be negative.")]
 | 
			
		||||
    public int Agility { get; set; }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,23 +1,20 @@
 | 
			
		||||
using Spectre.Console.Cli;
 | 
			
		||||
namespace Spectre.Console.Tests.Data;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Data
 | 
			
		||||
public sealed class DogSettings : MammalSettings
 | 
			
		||||
{
 | 
			
		||||
    public sealed class DogSettings : MammalSettings
 | 
			
		||||
    [CommandArgument(0, "<AGE>")]
 | 
			
		||||
    public int Age { get; set; }
 | 
			
		||||
 | 
			
		||||
    [CommandOption("-g|--good-boy")]
 | 
			
		||||
    public bool GoodBoy { get; set; }
 | 
			
		||||
 | 
			
		||||
    public override ValidationResult Validate()
 | 
			
		||||
    {
 | 
			
		||||
        [CommandArgument(0, "<AGE>")]
 | 
			
		||||
        public int Age { get; set; }
 | 
			
		||||
 | 
			
		||||
        [CommandOption("-g|--good-boy")]
 | 
			
		||||
        public bool GoodBoy { get; set; }
 | 
			
		||||
 | 
			
		||||
        public override ValidationResult Validate()
 | 
			
		||||
        if (Name == "Tiger")
 | 
			
		||||
        {
 | 
			
		||||
            if (Name == "Tiger")
 | 
			
		||||
            {
 | 
			
		||||
                return ValidationResult.Error("Tiger is not a dog name!");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return ValidationResult.Success();
 | 
			
		||||
            return ValidationResult.Error("Tiger is not a dog name!");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return ValidationResult.Success();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,5 @@
 | 
			
		||||
using Spectre.Console.Cli;
 | 
			
		||||
namespace Spectre.Console.Tests.Data;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Data
 | 
			
		||||
public sealed class EmptySettings : CommandSettings
 | 
			
		||||
{
 | 
			
		||||
    public sealed class EmptySettings : CommandSettings
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,12 +1,8 @@
 | 
			
		||||
using System.ComponentModel;
 | 
			
		||||
using Spectre.Console.Cli;
 | 
			
		||||
namespace Spectre.Console.Tests.Data;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Data
 | 
			
		||||
public class FooCommandSettings : CommandSettings
 | 
			
		||||
{
 | 
			
		||||
    public class FooCommandSettings : CommandSettings
 | 
			
		||||
    {
 | 
			
		||||
        [CommandArgument(0, "[QUX]")]
 | 
			
		||||
        [Description("The qux value.")]
 | 
			
		||||
        public string Qux { get; set; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
    [CommandArgument(0, "[QUX]")]
 | 
			
		||||
    [Description("The qux value.")]
 | 
			
		||||
    public string Qux { get; set; }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,12 +1,8 @@
 | 
			
		||||
using System.ComponentModel;
 | 
			
		||||
using Spectre.Console.Cli;
 | 
			
		||||
namespace Spectre.Console.Tests.Data;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Data
 | 
			
		||||
public sealed class GiraffeSettings : MammalSettings
 | 
			
		||||
{
 | 
			
		||||
    public sealed class GiraffeSettings : MammalSettings
 | 
			
		||||
    {
 | 
			
		||||
        [CommandArgument(0, "<LENGTH>")]
 | 
			
		||||
        [Description("The option description.")]
 | 
			
		||||
        public int Length { get; set; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
    [CommandArgument(0, "<LENGTH>")]
 | 
			
		||||
    [Description("The option description.")]
 | 
			
		||||
    public int Length { get; set; }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,20 +1,16 @@
 | 
			
		||||
using System.ComponentModel;
 | 
			
		||||
using Spectre.Console.Cli;
 | 
			
		||||
namespace Spectre.Console.Tests.Data;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Data
 | 
			
		||||
public sealed class HiddenOptionSettings : CommandSettings
 | 
			
		||||
{
 | 
			
		||||
    public sealed class HiddenOptionSettings : CommandSettings
 | 
			
		||||
    {
 | 
			
		||||
        [CommandArgument(0, "<FOO>")]
 | 
			
		||||
        [Description("Dummy argument FOO")]
 | 
			
		||||
        public int Foo { get; set; }
 | 
			
		||||
    [CommandArgument(0, "<FOO>")]
 | 
			
		||||
    [Description("Dummy argument FOO")]
 | 
			
		||||
    public int Foo { get; set; }
 | 
			
		||||
 | 
			
		||||
        [CommandOption("--bar", IsHidden = true)]
 | 
			
		||||
        [Description("You should not be able to read this unless you used the 'cli explain' command with the '--hidden' option")]
 | 
			
		||||
        public int Bar { get; set; }
 | 
			
		||||
    [CommandOption("--bar", IsHidden = true)]
 | 
			
		||||
    [Description("You should not be able to read this unless you used the 'cli explain' command with the '--hidden' option")]
 | 
			
		||||
    public int Bar { get; set; }
 | 
			
		||||
 | 
			
		||||
        [CommandOption("--baz")]
 | 
			
		||||
        [Description("Dummy option BAZ")]
 | 
			
		||||
        public int Baz { get; set; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
    [CommandOption("--baz")]
 | 
			
		||||
    [Description("Dummy option BAZ")]
 | 
			
		||||
    public int Baz { get; set; }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,10 +1,7 @@
 | 
			
		||||
using Spectre.Console.Cli;
 | 
			
		||||
namespace Spectre.Console.Tests.Data;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Data
 | 
			
		||||
public sealed class InvalidSettings : CommandSettings
 | 
			
		||||
{
 | 
			
		||||
    public sealed class InvalidSettings : CommandSettings
 | 
			
		||||
    {
 | 
			
		||||
        [CommandOption("-f|--foo [BAR]")]
 | 
			
		||||
        public string Value { get; set; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
    [CommandOption("-f|--foo [BAR]")]
 | 
			
		||||
    public string Value { get; set; }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,16 +1,12 @@
 | 
			
		||||
using System.ComponentModel;
 | 
			
		||||
using Spectre.Console.Cli;
 | 
			
		||||
namespace Spectre.Console.Tests.Data;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Data
 | 
			
		||||
public class LionSettings : CatSettings
 | 
			
		||||
{
 | 
			
		||||
    public class LionSettings : CatSettings
 | 
			
		||||
    {
 | 
			
		||||
        [CommandArgument(0, "<TEETH>")]
 | 
			
		||||
        [Description("The number of teeth the lion has.")]
 | 
			
		||||
        public int Teeth { get; set; }
 | 
			
		||||
    [CommandArgument(0, "<TEETH>")]
 | 
			
		||||
    [Description("The number of teeth the lion has.")]
 | 
			
		||||
    public int Teeth { get; set; }
 | 
			
		||||
 | 
			
		||||
        [CommandOption("-c <CHILDREN>")]
 | 
			
		||||
        [Description("The number of children the lion has.")]
 | 
			
		||||
        public int Children { get; set; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
    [CommandOption("-c <CHILDREN>")]
 | 
			
		||||
    [Description("The number of children the lion has.")]
 | 
			
		||||
    public int Children { get; set; }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,10 +1,7 @@
 | 
			
		||||
using Spectre.Console.Cli;
 | 
			
		||||
namespace Spectre.Console.Tests.Data;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Data
 | 
			
		||||
public class MammalSettings : AnimalSettings
 | 
			
		||||
{
 | 
			
		||||
    public class MammalSettings : AnimalSettings
 | 
			
		||||
    {
 | 
			
		||||
        [CommandOption("-n|-p|--name|--pet-name <VALUE>")]
 | 
			
		||||
        public string Name { get; set; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
    [CommandOption("-n|-p|--name|--pet-name <VALUE>")]
 | 
			
		||||
    public string Name { get; set; }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,22 +1,19 @@
 | 
			
		||||
using Spectre.Console.Cli;
 | 
			
		||||
namespace Spectre.Console.Tests.Data;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Data
 | 
			
		||||
public class MultipleArgumentVectorSettings : CommandSettings
 | 
			
		||||
{
 | 
			
		||||
    public class MultipleArgumentVectorSettings : CommandSettings
 | 
			
		||||
    {
 | 
			
		||||
        [CommandArgument(0, "<Foos>")]
 | 
			
		||||
        public string[] Foo { get; set; }
 | 
			
		||||
    [CommandArgument(0, "<Foos>")]
 | 
			
		||||
    public string[] Foo { get; set; }
 | 
			
		||||
 | 
			
		||||
        [CommandArgument(0, "<Bars>")]
 | 
			
		||||
        public string[] Bar { get; set; }
 | 
			
		||||
    }
 | 
			
		||||
    [CommandArgument(0, "<Bars>")]
 | 
			
		||||
    public string[] Bar { get; set; }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    public class MultipleArgumentVectorSpecifiedFirstSettings : CommandSettings
 | 
			
		||||
    {
 | 
			
		||||
        [CommandArgument(1, "[Bar]")]
 | 
			
		||||
        public string Bar { get; set; }
 | 
			
		||||
public class MultipleArgumentVectorSpecifiedFirstSettings : CommandSettings
 | 
			
		||||
{
 | 
			
		||||
    [CommandArgument(1, "[Bar]")]
 | 
			
		||||
    public string Bar { get; set; }
 | 
			
		||||
 | 
			
		||||
        [CommandArgument(0, "<Foos>")]
 | 
			
		||||
        public string[] Foo { get; set; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
    [CommandArgument(0, "<Foos>")]
 | 
			
		||||
    public string[] Foo { get; set; }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,13 +1,10 @@
 | 
			
		||||
using Spectre.Console.Cli;
 | 
			
		||||
namespace Spectre.Console.Tests.Data;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Data
 | 
			
		||||
public class OptionVectorSettings : CommandSettings
 | 
			
		||||
{
 | 
			
		||||
    public class OptionVectorSettings : CommandSettings
 | 
			
		||||
    {
 | 
			
		||||
        [CommandOption("--foo")]
 | 
			
		||||
        public string[] Foo { get; set; }
 | 
			
		||||
    [CommandOption("--foo")]
 | 
			
		||||
    public string[] Foo { get; set; }
 | 
			
		||||
 | 
			
		||||
        [CommandOption("--bar")]
 | 
			
		||||
        public int[] Bar { get; set; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
    [CommandOption("--bar")]
 | 
			
		||||
    public int[] Bar { get; set; }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,40 +1,35 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.ComponentModel;
 | 
			
		||||
using Spectre.Console.Cli;
 | 
			
		||||
namespace Spectre.Console.Tests.Data;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Data
 | 
			
		||||
public sealed class OptionalArgumentWithDefaultValueSettings : CommandSettings
 | 
			
		||||
{
 | 
			
		||||
    public sealed class OptionalArgumentWithDefaultValueSettings : CommandSettings
 | 
			
		||||
    {
 | 
			
		||||
        [CommandArgument(0, "[GREETING]")]
 | 
			
		||||
        [DefaultValue("Hello World")]
 | 
			
		||||
        public string Greeting { get; set; }
 | 
			
		||||
    }
 | 
			
		||||
    [CommandArgument(0, "[GREETING]")]
 | 
			
		||||
    [DefaultValue("Hello World")]
 | 
			
		||||
    public string Greeting { get; set; }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    public sealed class OptionalArgumentWithPropertyInitializerSettings : CommandSettings
 | 
			
		||||
    {
 | 
			
		||||
        [CommandArgument(0, "[NAMES]")]
 | 
			
		||||
        public string[] Names { get; set; } = Array.Empty<string>();
 | 
			
		||||
public sealed class OptionalArgumentWithPropertyInitializerSettings : CommandSettings
 | 
			
		||||
{
 | 
			
		||||
    [CommandArgument(0, "[NAMES]")]
 | 
			
		||||
    public string[] Names { get; set; } = Array.Empty<string>();
 | 
			
		||||
 | 
			
		||||
        [CommandOption("-c")]
 | 
			
		||||
        public int Count { get; set; } = 1;
 | 
			
		||||
    [CommandOption("-c")]
 | 
			
		||||
    public int Count { get; set; } = 1;
 | 
			
		||||
 | 
			
		||||
        [CommandOption("-v")]
 | 
			
		||||
        public int Value { get; set; } = 0;
 | 
			
		||||
    }
 | 
			
		||||
    [CommandOption("-v")]
 | 
			
		||||
    public int Value { get; set; } = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    public sealed class OptionalArgumentWithDefaultValueAndTypeConverterSettings : CommandSettings
 | 
			
		||||
    {
 | 
			
		||||
        [CommandArgument(0, "[GREETING]")]
 | 
			
		||||
        [DefaultValue("5")]
 | 
			
		||||
        [TypeConverter(typeof(StringToIntegerConverter))]
 | 
			
		||||
        public int Greeting { get; set; }
 | 
			
		||||
    }
 | 
			
		||||
public sealed class OptionalArgumentWithDefaultValueAndTypeConverterSettings : CommandSettings
 | 
			
		||||
{
 | 
			
		||||
    [CommandArgument(0, "[GREETING]")]
 | 
			
		||||
    [DefaultValue("5")]
 | 
			
		||||
    [TypeConverter(typeof(StringToIntegerConverter))]
 | 
			
		||||
    public int Greeting { get; set; }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    public sealed class RequiredArgumentWithDefaultValueSettings : CommandSettings
 | 
			
		||||
    {
 | 
			
		||||
        [CommandArgument(0, "<GREETING>")]
 | 
			
		||||
        [DefaultValue("Hello World")]
 | 
			
		||||
        public string Greeting { get; set; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
public sealed class RequiredArgumentWithDefaultValueSettings : CommandSettings
 | 
			
		||||
{
 | 
			
		||||
    [CommandArgument(0, "<GREETING>")]
 | 
			
		||||
    [DefaultValue("Hello World")]
 | 
			
		||||
    public string Greeting { get; set; }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,10 +1,7 @@
 | 
			
		||||
using Spectre.Console.Cli;
 | 
			
		||||
namespace Spectre.Console.Tests.Data;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Data
 | 
			
		||||
public sealed class StringOptionSettings : CommandSettings
 | 
			
		||||
{
 | 
			
		||||
    public sealed class StringOptionSettings : CommandSettings
 | 
			
		||||
    {
 | 
			
		||||
        [CommandOption("-f|--foo")]
 | 
			
		||||
        public string Foo { get; set; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
    [CommandOption("-f|--foo")]
 | 
			
		||||
    public string Foo { get; set; }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,29 +1,25 @@
 | 
			
		||||
using System;
 | 
			
		||||
using Spectre.Console.Cli;
 | 
			
		||||
namespace Spectre.Console.Tests.Data;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Data
 | 
			
		||||
[AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
 | 
			
		||||
public sealed class EvenNumberValidatorAttribute : ParameterValidationAttribute
 | 
			
		||||
{
 | 
			
		||||
    [AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
 | 
			
		||||
    public sealed class EvenNumberValidatorAttribute : ParameterValidationAttribute
 | 
			
		||||
    public EvenNumberValidatorAttribute(string errorMessage)
 | 
			
		||||
        : base(errorMessage)
 | 
			
		||||
    {
 | 
			
		||||
        public EvenNumberValidatorAttribute(string errorMessage)
 | 
			
		||||
            : base(errorMessage)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        public override ValidationResult Validate(CommandParameterContext context)
 | 
			
		||||
    public override ValidationResult Validate(CommandParameterContext context)
 | 
			
		||||
    {
 | 
			
		||||
        if (context.Value is int integer)
 | 
			
		||||
        {
 | 
			
		||||
            if (context.Value is int integer)
 | 
			
		||||
            if (integer % 2 == 0)
 | 
			
		||||
            {
 | 
			
		||||
                if (integer % 2 == 0)
 | 
			
		||||
                {
 | 
			
		||||
                    return ValidationResult.Success();
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                return ValidationResult.Error($"Number is not even ({context.Parameter.PropertyName}).");
 | 
			
		||||
                return ValidationResult.Success();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            throw new InvalidOperationException($"Parameter is not a number ({context.Parameter.PropertyName}).");
 | 
			
		||||
            return ValidationResult.Error($"Number is not even ({context.Parameter.PropertyName}).");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        throw new InvalidOperationException($"Parameter is not a number ({context.Parameter.PropertyName}).");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,29 +1,25 @@
 | 
			
		||||
using System;
 | 
			
		||||
using Spectre.Console.Cli;
 | 
			
		||||
namespace Spectre.Console.Tests.Data;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Data
 | 
			
		||||
[AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
 | 
			
		||||
public sealed class PositiveNumberValidatorAttribute : ParameterValidationAttribute
 | 
			
		||||
{
 | 
			
		||||
    [AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
 | 
			
		||||
    public sealed class PositiveNumberValidatorAttribute : ParameterValidationAttribute
 | 
			
		||||
    public PositiveNumberValidatorAttribute(string errorMessage)
 | 
			
		||||
        : base(errorMessage)
 | 
			
		||||
    {
 | 
			
		||||
        public PositiveNumberValidatorAttribute(string errorMessage)
 | 
			
		||||
            : base(errorMessage)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        public override ValidationResult Validate(CommandParameterContext context)
 | 
			
		||||
    public override ValidationResult Validate(CommandParameterContext context)
 | 
			
		||||
    {
 | 
			
		||||
        if (context.Value is int integer)
 | 
			
		||||
        {
 | 
			
		||||
            if (context.Value is int integer)
 | 
			
		||||
            if (integer > 0)
 | 
			
		||||
            {
 | 
			
		||||
                if (integer > 0)
 | 
			
		||||
                {
 | 
			
		||||
                    return ValidationResult.Success();
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                return ValidationResult.Error($"Number is not greater than 0 ({context.Parameter.PropertyName}).");
 | 
			
		||||
                return ValidationResult.Success();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            throw new InvalidOperationException($"Parameter is not a number ({context.Parameter.PropertyName}).");
 | 
			
		||||
            return ValidationResult.Error($"Number is not greater than 0 ({context.Parameter.PropertyName}).");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        throw new InvalidOperationException($"Parameter is not a number ({context.Parameter.PropertyName}).");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										24
									
								
								test/Spectre.Console.Tests/Properties/Usings.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								test/Spectre.Console.Tests/Properties/Usings.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,24 @@
 | 
			
		||||
global using System;
 | 
			
		||||
global using System.Collections.Generic;
 | 
			
		||||
global using System.ComponentModel;
 | 
			
		||||
global using System.Diagnostics;
 | 
			
		||||
global using System.Diagnostics.CodeAnalysis;
 | 
			
		||||
global using System.Globalization;
 | 
			
		||||
global using System.IO;
 | 
			
		||||
global using System.Linq;
 | 
			
		||||
global using System.Reflection;
 | 
			
		||||
global using System.Runtime.CompilerServices;
 | 
			
		||||
global using System.Text.RegularExpressions;
 | 
			
		||||
global using System.Threading;
 | 
			
		||||
global using System.Threading.Tasks;
 | 
			
		||||
global using Shouldly;
 | 
			
		||||
global using Spectre.Console.Advanced;
 | 
			
		||||
global using Spectre.Console.Cli;
 | 
			
		||||
global using Spectre.Console.Cli.Unsafe;
 | 
			
		||||
global using Spectre.Console.Rendering;
 | 
			
		||||
global using Spectre.Console.Testing;
 | 
			
		||||
global using Spectre.Console.Tests.Data;
 | 
			
		||||
global using Spectre.Verify.Extensions;
 | 
			
		||||
global using VerifyTests;
 | 
			
		||||
global using VerifyXunit;
 | 
			
		||||
global using Xunit;
 | 
			
		||||
@@ -1,9 +1,12 @@
 | 
			
		||||
<Project Sdk="Microsoft.NET.Sdk">
 | 
			
		||||
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <AdditionalFiles Include="..\..\src\stylecop.json" Link="Properties/stylecop.json" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
 | 
			
		||||
  <PropertyGroup>
 | 
			
		||||
    <TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('Windows'))">net6.0;net5.0;net48</TargetFrameworks>
 | 
			
		||||
    <TargetFrameworks Condition="!$([MSBuild]::IsOSPlatform('Windows'))">net6.0;net5.0</TargetFrameworks>
 | 
			
		||||
    <LangVersion>9.0</LangVersion>
 | 
			
		||||
  </PropertyGroup>
 | 
			
		||||
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,79 +1,71 @@
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Shouldly;
 | 
			
		||||
using Spectre.Console.Testing;
 | 
			
		||||
using Spectre.Verify.Extensions;
 | 
			
		||||
using VerifyXunit;
 | 
			
		||||
using Xunit;
 | 
			
		||||
namespace Spectre.Console.Tests.Unit;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Unit
 | 
			
		||||
[UsesVerify]
 | 
			
		||||
[ExpectationPath("AlternateScreen")]
 | 
			
		||||
public sealed class AlternateScreenTests
 | 
			
		||||
{
 | 
			
		||||
    [UsesVerify]
 | 
			
		||||
    [ExpectationPath("AlternateScreen")]
 | 
			
		||||
    public sealed class AlternateScreenTests
 | 
			
		||||
    [Fact]
 | 
			
		||||
    public void Should_Throw_If_Alternative_Buffer_Is_Not_Supported_By_Terminal()
 | 
			
		||||
    {
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Throw_If_Alternative_Buffer_Is_Not_Supported_By_Terminal()
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole();
 | 
			
		||||
        console.Profile.Capabilities.AlternateBuffer = false;
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        var result = Record.Exception(() =>
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
            console.Profile.Capabilities.AlternateBuffer = false;
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            var result = Record.Exception(() =>
 | 
			
		||||
            {
 | 
			
		||||
                console.WriteLine("Foo");
 | 
			
		||||
                console.AlternateScreen(() =>
 | 
			
		||||
                {
 | 
			
		||||
                    console.WriteLine("Bar");
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ShouldNotBeNull();
 | 
			
		||||
            result.Message.ShouldBe("Alternate buffers are not supported by your terminal.");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Throw_If_Ansi_Is_Not_Supported_By_Terminal()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
            console.Profile.Capabilities.Ansi = false;
 | 
			
		||||
            console.Profile.Capabilities.AlternateBuffer = true;
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            var result = Record.Exception(() =>
 | 
			
		||||
            {
 | 
			
		||||
                console.WriteLine("Foo");
 | 
			
		||||
                console.AlternateScreen(() =>
 | 
			
		||||
                {
 | 
			
		||||
                    console.WriteLine("Bar");
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ShouldNotBeNull();
 | 
			
		||||
            result.Message.ShouldBe("Alternate buffers are not supported since your terminal does not support ANSI.");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Show")]
 | 
			
		||||
        public async Task Should_Write_To_Alternate_Screen()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
            console.EmitAnsiSequences = true;
 | 
			
		||||
            console.Profile.Capabilities.AlternateBuffer = true;
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.WriteLine("Foo");
 | 
			
		||||
            console.AlternateScreen(() =>
 | 
			
		||||
            {
 | 
			
		||||
                console.WriteLine("Bar");
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            await Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
        // Then
 | 
			
		||||
        result.ShouldNotBeNull();
 | 
			
		||||
        result.Message.ShouldBe("Alternate buffers are not supported by your terminal.");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    public void Should_Throw_If_Ansi_Is_Not_Supported_By_Terminal()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole();
 | 
			
		||||
        console.Profile.Capabilities.Ansi = false;
 | 
			
		||||
        console.Profile.Capabilities.AlternateBuffer = true;
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        var result = Record.Exception(() =>
 | 
			
		||||
        {
 | 
			
		||||
            console.WriteLine("Foo");
 | 
			
		||||
            console.AlternateScreen(() =>
 | 
			
		||||
            {
 | 
			
		||||
                console.WriteLine("Bar");
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        result.ShouldNotBeNull();
 | 
			
		||||
        result.Message.ShouldBe("Alternate buffers are not supported since your terminal does not support ANSI.");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("Show")]
 | 
			
		||||
    public async Task Should_Write_To_Alternate_Screen()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole();
 | 
			
		||||
        console.EmitAnsiSequences = true;
 | 
			
		||||
        console.Profile.Capabilities.AlternateBuffer = true;
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.WriteLine("Foo");
 | 
			
		||||
        console.AlternateScreen(() =>
 | 
			
		||||
        {
 | 
			
		||||
            console.WriteLine("Bar");
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        await Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,61 +1,55 @@
 | 
			
		||||
using Shouldly;
 | 
			
		||||
using Spectre.Console.Advanced;
 | 
			
		||||
using Spectre.Console.Testing;
 | 
			
		||||
using Xunit;
 | 
			
		||||
namespace Spectre.Console.Tests.Unit;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Unit
 | 
			
		||||
public sealed partial class AnsiConsoleTests
 | 
			
		||||
{
 | 
			
		||||
    public sealed partial class AnsiConsoleTests
 | 
			
		||||
    public sealed class Advanced
 | 
			
		||||
    {
 | 
			
		||||
        public sealed class Advanced
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Write_Ansi_Codes_To_Console_If_Supported()
 | 
			
		||||
        {
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Write_Ansi_Codes_To_Console_If_Supported()
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var console = new TestConsole()
 | 
			
		||||
                    .SupportsAnsi(true)
 | 
			
		||||
                    .Colors(ColorSystem.Standard)
 | 
			
		||||
                    .EmitAnsiSequences();
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole()
 | 
			
		||||
                .SupportsAnsi(true)
 | 
			
		||||
                .Colors(ColorSystem.Standard)
 | 
			
		||||
                .EmitAnsiSequences();
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                console.WriteAnsi("[101mHello[0m");
 | 
			
		||||
            // When
 | 
			
		||||
            console.WriteAnsi("[101mHello[0m");
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                console.Output.NormalizeLineEndings()
 | 
			
		||||
                    .ShouldBe("[101mHello[0m");
 | 
			
		||||
            }
 | 
			
		||||
            // Then
 | 
			
		||||
            console.Output.NormalizeLineEndings()
 | 
			
		||||
                .ShouldBe("[101mHello[0m");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Not_Write_Ansi_Codes_To_Console_If_Not_Supported()
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var console = new TestConsole()
 | 
			
		||||
                    .SupportsAnsi(false)
 | 
			
		||||
                    .Colors(ColorSystem.Standard)
 | 
			
		||||
                    .EmitAnsiSequences();
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Not_Write_Ansi_Codes_To_Console_If_Not_Supported()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole()
 | 
			
		||||
                .SupportsAnsi(false)
 | 
			
		||||
                .Colors(ColorSystem.Standard)
 | 
			
		||||
                .EmitAnsiSequences();
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                console.WriteAnsi("[101mHello[0m");
 | 
			
		||||
            // When
 | 
			
		||||
            console.WriteAnsi("[101mHello[0m");
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                console.Output.NormalizeLineEndings()
 | 
			
		||||
                    .ShouldBeEmpty();
 | 
			
		||||
            }
 | 
			
		||||
            // Then
 | 
			
		||||
            console.Output.NormalizeLineEndings()
 | 
			
		||||
                .ShouldBeEmpty();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Return_Ansi_For_Renderable()
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var console = new TestConsole().Colors(ColorSystem.TrueColor);
 | 
			
		||||
                var markup = new Console.Markup("[yellow]Hello [blue]World[/]![/]");
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Return_Ansi_For_Renderable()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole().Colors(ColorSystem.TrueColor);
 | 
			
		||||
            var markup = new Console.Markup("[yellow]Hello [blue]World[/]![/]");
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = console.ToAnsi(markup);
 | 
			
		||||
            // When
 | 
			
		||||
            var result = console.ToAnsi(markup);
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ShouldBe("[38;5;11mHello [0m[38;5;12mWorld[0m[38;5;11m![0m");
 | 
			
		||||
            }
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ShouldBe("[38;5;11mHello [0m[38;5;12mWorld[0m[38;5;11m![0m");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,248 +1,242 @@
 | 
			
		||||
using System.IO;
 | 
			
		||||
using Shouldly;
 | 
			
		||||
using Spectre.Console.Testing;
 | 
			
		||||
using Xunit;
 | 
			
		||||
namespace Spectre.Console.Tests.Unit;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Unit
 | 
			
		||||
public partial class AnsiConsoleTests
 | 
			
		||||
{
 | 
			
		||||
    public partial class AnsiConsoleTests
 | 
			
		||||
    [Theory]
 | 
			
		||||
    [InlineData(ColorSystemSupport.NoColors, ColorSystem.NoColors)]
 | 
			
		||||
    [InlineData(ColorSystemSupport.Legacy, ColorSystem.Legacy)]
 | 
			
		||||
    [InlineData(ColorSystemSupport.Standard, ColorSystem.Standard)]
 | 
			
		||||
    [InlineData(ColorSystemSupport.EightBit, ColorSystem.EightBit)]
 | 
			
		||||
    [InlineData(ColorSystemSupport.TrueColor, ColorSystem.TrueColor)]
 | 
			
		||||
    public void Should_Create_Console_With_Requested_ColorSystem(ColorSystemSupport requested, ColorSystem expected)
 | 
			
		||||
    {
 | 
			
		||||
        // Given, When
 | 
			
		||||
        var console = AnsiConsole.Create(new AnsiConsoleSettings
 | 
			
		||||
        {
 | 
			
		||||
            ColorSystem = requested,
 | 
			
		||||
            Out = new AnsiConsoleOutput(new StringWriter()),
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        console.Profile.Capabilities.ColorSystem.ShouldBe(expected);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public sealed class TrueColor
 | 
			
		||||
    {
 | 
			
		||||
        [Theory]
 | 
			
		||||
        [InlineData(ColorSystemSupport.NoColors, ColorSystem.NoColors)]
 | 
			
		||||
        [InlineData(ColorSystemSupport.Legacy, ColorSystem.Legacy)]
 | 
			
		||||
        [InlineData(ColorSystemSupport.Standard, ColorSystem.Standard)]
 | 
			
		||||
        [InlineData(ColorSystemSupport.EightBit, ColorSystem.EightBit)]
 | 
			
		||||
        [InlineData(ColorSystemSupport.TrueColor, ColorSystem.TrueColor)]
 | 
			
		||||
        public void Should_Create_Console_With_Requested_ColorSystem(ColorSystemSupport requested, ColorSystem expected)
 | 
			
		||||
        [InlineData(true, "\u001b[38;2;128;0;128mHello\u001b[0m")]
 | 
			
		||||
        [InlineData(false, "\u001b[48;2;128;0;128mHello\u001b[0m")]
 | 
			
		||||
        public void Should_Return_Correct_Code(bool foreground, string expected)
 | 
			
		||||
        {
 | 
			
		||||
            // Given, When
 | 
			
		||||
            var console = AnsiConsole.Create(new AnsiConsoleSettings
 | 
			
		||||
            {
 | 
			
		||||
                ColorSystem = requested,
 | 
			
		||||
                Out = new AnsiConsoleOutput(new StringWriter()),
 | 
			
		||||
            });
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole()
 | 
			
		||||
                .Colors(ColorSystem.TrueColor)
 | 
			
		||||
                .EmitAnsiSequences();
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write("Hello", new Style().SetColor(new Color(128, 0, 128), foreground));
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            console.Profile.Capabilities.ColorSystem.ShouldBe(expected);
 | 
			
		||||
            console.Output.ShouldBe(expected);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public sealed class TrueColor
 | 
			
		||||
        [Theory]
 | 
			
		||||
        [InlineData(true, "\u001b[38;5;5mHello\u001b[0m")]
 | 
			
		||||
        [InlineData(false, "\u001b[48;5;5mHello\u001b[0m")]
 | 
			
		||||
        public void Should_Return_Eight_Bit_Ansi_Code_For_Known_Colors(bool foreground, string expected)
 | 
			
		||||
        {
 | 
			
		||||
            [Theory]
 | 
			
		||||
            [InlineData(true, "\u001b[38;2;128;0;128mHello\u001b[0m")]
 | 
			
		||||
            [InlineData(false, "\u001b[48;2;128;0;128mHello\u001b[0m")]
 | 
			
		||||
            public void Should_Return_Correct_Code(bool foreground, string expected)
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var console = new TestConsole()
 | 
			
		||||
                    .Colors(ColorSystem.TrueColor)
 | 
			
		||||
                    .EmitAnsiSequences();
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole()
 | 
			
		||||
                .Colors(ColorSystem.TrueColor)
 | 
			
		||||
                .EmitAnsiSequences();
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                console.Write("Hello", new Style().SetColor(new Color(128, 0, 128), foreground));
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write("Hello", new Style().SetColor(Color.Purple, foreground));
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                console.Output.ShouldBe(expected);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Theory]
 | 
			
		||||
            [InlineData(true, "\u001b[38;5;5mHello\u001b[0m")]
 | 
			
		||||
            [InlineData(false, "\u001b[48;5;5mHello\u001b[0m")]
 | 
			
		||||
            public void Should_Return_Eight_Bit_Ansi_Code_For_Known_Colors(bool foreground, string expected)
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var console = new TestConsole()
 | 
			
		||||
                    .Colors(ColorSystem.TrueColor)
 | 
			
		||||
                    .EmitAnsiSequences();
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                console.Write("Hello", new Style().SetColor(Color.Purple, foreground));
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                console.Output.ShouldBe(expected);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public sealed class EightBit
 | 
			
		||||
        {
 | 
			
		||||
            [Theory]
 | 
			
		||||
            [InlineData(true, "\u001b[38;5;3mHello\u001b[0m")]
 | 
			
		||||
            [InlineData(false, "\u001b[48;5;3mHello\u001b[0m")]
 | 
			
		||||
            public void Should_Return_Correct_Code_For_Known_Color(bool foreground, string expected)
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var console = new TestConsole()
 | 
			
		||||
                    .Colors(ColorSystem.EightBit)
 | 
			
		||||
                    .EmitAnsiSequences();
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                console.Write("Hello", new Style().SetColor(Color.Olive, foreground));
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                console.Output.ShouldBe(expected);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Theory]
 | 
			
		||||
            [InlineData(true, "\u001b[38;5;3mHello\u001b[0m")]
 | 
			
		||||
            [InlineData(false, "\u001b[48;5;3mHello\u001b[0m")]
 | 
			
		||||
            public void Should_Map_TrueColor_To_Nearest_Eight_Bit_Color_If_Possible(bool foreground, string expected)
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var console = new TestConsole()
 | 
			
		||||
                    .Colors(ColorSystem.EightBit)
 | 
			
		||||
                    .EmitAnsiSequences();
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                console.Write("Hello", new Style().SetColor(new Color(128, 128, 0), foreground));
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                console.Output.ShouldBe(expected);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Theory]
 | 
			
		||||
            [InlineData(true, "\u001b[38;5;3mHello\u001b[0m")]
 | 
			
		||||
            [InlineData(false, "\u001b[48;5;3mHello\u001b[0m")]
 | 
			
		||||
            public void Should_Estimate_TrueColor_To_Nearest_Eight_Bit_Color(bool foreground, string expected)
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var console = new TestConsole()
 | 
			
		||||
                    .Colors(ColorSystem.EightBit)
 | 
			
		||||
                    .EmitAnsiSequences();
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                console.Write("Hello", new Style().SetColor(new Color(126, 127, 0), foreground));
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                console.Output.ShouldBe(expected);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public sealed class Standard
 | 
			
		||||
        {
 | 
			
		||||
            [Theory]
 | 
			
		||||
            [InlineData(true, "\u001b[33mHello\u001b[0m")]
 | 
			
		||||
            [InlineData(false, "\u001b[43mHello\u001b[0m")]
 | 
			
		||||
            public void Should_Return_Correct_Code_For_Known_Color(bool foreground, string expected)
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var console = new TestConsole()
 | 
			
		||||
                    .Colors(ColorSystem.Standard)
 | 
			
		||||
                    .EmitAnsiSequences();
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                console.Write("Hello", new Style().SetColor(Color.Olive, foreground));
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                console.Output.ShouldBe(expected);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Theory]
 | 
			
		||||
            [InlineData(true, 128, 128, 128, "\u001b[90mHello\u001b[0m")]
 | 
			
		||||
            [InlineData(false, 128, 128, 128, "\u001b[100mHello\u001b[0m")]
 | 
			
		||||
            [InlineData(true, 0, 128, 0, "\u001b[32mHello\u001b[0m")]
 | 
			
		||||
            [InlineData(false, 0, 128, 0, "\u001b[42mHello\u001b[0m")]
 | 
			
		||||
            public void Should_Map_TrueColor_To_Nearest_Four_Bit_Color_If_Possible(
 | 
			
		||||
                bool foreground,
 | 
			
		||||
                byte r, byte g, byte b,
 | 
			
		||||
                string expected)
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var console = new TestConsole()
 | 
			
		||||
                    .Colors(ColorSystem.Standard)
 | 
			
		||||
                    .EmitAnsiSequences();
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                console.Write("Hello", new Style().SetColor(new Color(r, g, b), foreground));
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                console.Output.ShouldBe(expected);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Theory]
 | 
			
		||||
            [InlineData(true, 112, 120, 128, "\u001b[90mHello\u001b[0m")]
 | 
			
		||||
            [InlineData(false, 112, 120, 128, "\u001b[100mHello\u001b[0m")]
 | 
			
		||||
            [InlineData(true, 0, 120, 12, "\u001b[32mHello\u001b[0m")]
 | 
			
		||||
            [InlineData(false, 0, 120, 12, "\u001b[42mHello\u001b[0m")]
 | 
			
		||||
            public void Should_Estimate_TrueColor_To_Nearest_Four_Bit_Color(
 | 
			
		||||
                bool foreground,
 | 
			
		||||
                byte r, byte g, byte b,
 | 
			
		||||
                string expected)
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var console = new TestConsole()
 | 
			
		||||
                    .Colors(ColorSystem.Standard)
 | 
			
		||||
                    .EmitAnsiSequences();
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                console.Write("Hello", new Style().SetColor(new Color(r, g, b), foreground));
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                console.Output.ShouldBe(expected);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public sealed class Legacy
 | 
			
		||||
        {
 | 
			
		||||
            [Theory]
 | 
			
		||||
            [InlineData(true, "\u001b[33mHello\u001b[0m")]
 | 
			
		||||
            [InlineData(false, "\u001b[43mHello\u001b[0m")]
 | 
			
		||||
            public void Should_Return_Correct_Code_For_Known_Color(bool foreground, string expected)
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var console = new TestConsole()
 | 
			
		||||
                    .Colors(ColorSystem.Legacy)
 | 
			
		||||
                    .EmitAnsiSequences();
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                console.Write("Hello", new Style().SetColor(Color.Olive, foreground));
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                console.Output.ShouldBe(expected);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Theory]
 | 
			
		||||
            [InlineData(true, 128, 128, 128, "\u001b[37mHello\u001b[0m")]
 | 
			
		||||
            [InlineData(false, 128, 128, 128, "\u001b[47mHello\u001b[0m")]
 | 
			
		||||
            [InlineData(true, 0, 128, 0, "\u001b[32mHello\u001b[0m")]
 | 
			
		||||
            [InlineData(false, 0, 128, 0, "\u001b[42mHello\u001b[0m")]
 | 
			
		||||
            public void Should_Map_TrueColor_To_Nearest_Three_Bit_Color_If_Possible(
 | 
			
		||||
                bool foreground,
 | 
			
		||||
                byte r, byte g, byte b,
 | 
			
		||||
                string expected)
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var console = new TestConsole()
 | 
			
		||||
                    .Colors(ColorSystem.Legacy)
 | 
			
		||||
                    .EmitAnsiSequences();
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                console.Write("Hello", new Style().SetColor(new Color(r, g, b), foreground));
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                console.Output.ShouldBe(expected);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Theory]
 | 
			
		||||
            [InlineData(true, 112, 120, 128, "\u001b[36mHello\u001b[0m")]
 | 
			
		||||
            [InlineData(false, 112, 120, 128, "\u001b[46mHello\u001b[0m")]
 | 
			
		||||
            [InlineData(true, 0, 120, 12, "\u001b[32mHello\u001b[0m")]
 | 
			
		||||
            [InlineData(false, 0, 120, 12, "\u001b[42mHello\u001b[0m")]
 | 
			
		||||
            public void Should_Estimate_TrueColor_To_Nearest_Three_Bit_Color(
 | 
			
		||||
                bool foreground,
 | 
			
		||||
                byte r, byte g, byte b,
 | 
			
		||||
                string expected)
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var console = new TestConsole()
 | 
			
		||||
                    .Colors(ColorSystem.Legacy)
 | 
			
		||||
                    .EmitAnsiSequences();
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                console.Write("Hello", new Style().SetColor(new Color(r, g, b), foreground));
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                console.Output.ShouldBe(expected);
 | 
			
		||||
            }
 | 
			
		||||
            // Then
 | 
			
		||||
            console.Output.ShouldBe(expected);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    public sealed class EightBit
 | 
			
		||||
    {
 | 
			
		||||
        [Theory]
 | 
			
		||||
        [InlineData(true, "\u001b[38;5;3mHello\u001b[0m")]
 | 
			
		||||
        [InlineData(false, "\u001b[48;5;3mHello\u001b[0m")]
 | 
			
		||||
        public void Should_Return_Correct_Code_For_Known_Color(bool foreground, string expected)
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole()
 | 
			
		||||
                .Colors(ColorSystem.EightBit)
 | 
			
		||||
                .EmitAnsiSequences();
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write("Hello", new Style().SetColor(Color.Olive, foreground));
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            console.Output.ShouldBe(expected);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Theory]
 | 
			
		||||
        [InlineData(true, "\u001b[38;5;3mHello\u001b[0m")]
 | 
			
		||||
        [InlineData(false, "\u001b[48;5;3mHello\u001b[0m")]
 | 
			
		||||
        public void Should_Map_TrueColor_To_Nearest_Eight_Bit_Color_If_Possible(bool foreground, string expected)
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole()
 | 
			
		||||
                .Colors(ColorSystem.EightBit)
 | 
			
		||||
                .EmitAnsiSequences();
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write("Hello", new Style().SetColor(new Color(128, 128, 0), foreground));
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            console.Output.ShouldBe(expected);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Theory]
 | 
			
		||||
        [InlineData(true, "\u001b[38;5;3mHello\u001b[0m")]
 | 
			
		||||
        [InlineData(false, "\u001b[48;5;3mHello\u001b[0m")]
 | 
			
		||||
        public void Should_Estimate_TrueColor_To_Nearest_Eight_Bit_Color(bool foreground, string expected)
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole()
 | 
			
		||||
                .Colors(ColorSystem.EightBit)
 | 
			
		||||
                .EmitAnsiSequences();
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write("Hello", new Style().SetColor(new Color(126, 127, 0), foreground));
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            console.Output.ShouldBe(expected);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public sealed class Standard
 | 
			
		||||
    {
 | 
			
		||||
        [Theory]
 | 
			
		||||
        [InlineData(true, "\u001b[33mHello\u001b[0m")]
 | 
			
		||||
        [InlineData(false, "\u001b[43mHello\u001b[0m")]
 | 
			
		||||
        public void Should_Return_Correct_Code_For_Known_Color(bool foreground, string expected)
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole()
 | 
			
		||||
                .Colors(ColorSystem.Standard)
 | 
			
		||||
                .EmitAnsiSequences();
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write("Hello", new Style().SetColor(Color.Olive, foreground));
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            console.Output.ShouldBe(expected);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Theory]
 | 
			
		||||
        [InlineData(true, 128, 128, 128, "\u001b[90mHello\u001b[0m")]
 | 
			
		||||
        [InlineData(false, 128, 128, 128, "\u001b[100mHello\u001b[0m")]
 | 
			
		||||
        [InlineData(true, 0, 128, 0, "\u001b[32mHello\u001b[0m")]
 | 
			
		||||
        [InlineData(false, 0, 128, 0, "\u001b[42mHello\u001b[0m")]
 | 
			
		||||
        public void Should_Map_TrueColor_To_Nearest_Four_Bit_Color_If_Possible(
 | 
			
		||||
            bool foreground,
 | 
			
		||||
            byte r, byte g, byte b,
 | 
			
		||||
            string expected)
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole()
 | 
			
		||||
                .Colors(ColorSystem.Standard)
 | 
			
		||||
                .EmitAnsiSequences();
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write("Hello", new Style().SetColor(new Color(r, g, b), foreground));
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            console.Output.ShouldBe(expected);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Theory]
 | 
			
		||||
        [InlineData(true, 112, 120, 128, "\u001b[90mHello\u001b[0m")]
 | 
			
		||||
        [InlineData(false, 112, 120, 128, "\u001b[100mHello\u001b[0m")]
 | 
			
		||||
        [InlineData(true, 0, 120, 12, "\u001b[32mHello\u001b[0m")]
 | 
			
		||||
        [InlineData(false, 0, 120, 12, "\u001b[42mHello\u001b[0m")]
 | 
			
		||||
        public void Should_Estimate_TrueColor_To_Nearest_Four_Bit_Color(
 | 
			
		||||
            bool foreground,
 | 
			
		||||
            byte r, byte g, byte b,
 | 
			
		||||
            string expected)
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole()
 | 
			
		||||
                .Colors(ColorSystem.Standard)
 | 
			
		||||
                .EmitAnsiSequences();
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write("Hello", new Style().SetColor(new Color(r, g, b), foreground));
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            console.Output.ShouldBe(expected);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public sealed class Legacy
 | 
			
		||||
    {
 | 
			
		||||
        [Theory]
 | 
			
		||||
        [InlineData(true, "\u001b[33mHello\u001b[0m")]
 | 
			
		||||
        [InlineData(false, "\u001b[43mHello\u001b[0m")]
 | 
			
		||||
        public void Should_Return_Correct_Code_For_Known_Color(bool foreground, string expected)
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole()
 | 
			
		||||
                .Colors(ColorSystem.Legacy)
 | 
			
		||||
                .EmitAnsiSequences();
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write("Hello", new Style().SetColor(Color.Olive, foreground));
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            console.Output.ShouldBe(expected);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Theory]
 | 
			
		||||
        [InlineData(true, 128, 128, 128, "\u001b[37mHello\u001b[0m")]
 | 
			
		||||
        [InlineData(false, 128, 128, 128, "\u001b[47mHello\u001b[0m")]
 | 
			
		||||
        [InlineData(true, 0, 128, 0, "\u001b[32mHello\u001b[0m")]
 | 
			
		||||
        [InlineData(false, 0, 128, 0, "\u001b[42mHello\u001b[0m")]
 | 
			
		||||
        public void Should_Map_TrueColor_To_Nearest_Three_Bit_Color_If_Possible(
 | 
			
		||||
            bool foreground,
 | 
			
		||||
            byte r, byte g, byte b,
 | 
			
		||||
            string expected)
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole()
 | 
			
		||||
                .Colors(ColorSystem.Legacy)
 | 
			
		||||
                .EmitAnsiSequences();
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write("Hello", new Style().SetColor(new Color(r, g, b), foreground));
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            console.Output.ShouldBe(expected);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Theory]
 | 
			
		||||
        [InlineData(true, 112, 120, 128, "\u001b[36mHello\u001b[0m")]
 | 
			
		||||
        [InlineData(false, 112, 120, 128, "\u001b[46mHello\u001b[0m")]
 | 
			
		||||
        [InlineData(true, 0, 120, 12, "\u001b[32mHello\u001b[0m")]
 | 
			
		||||
        [InlineData(false, 0, 120, 12, "\u001b[42mHello\u001b[0m")]
 | 
			
		||||
        public void Should_Estimate_TrueColor_To_Nearest_Three_Bit_Color(
 | 
			
		||||
            bool foreground,
 | 
			
		||||
            byte r, byte g, byte b,
 | 
			
		||||
            string expected)
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole()
 | 
			
		||||
                .Colors(ColorSystem.Legacy)
 | 
			
		||||
                .EmitAnsiSequences();
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write("Hello", new Style().SetColor(new Color(r, g, b), foreground));
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            console.Output.ShouldBe(expected);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,52 +1,47 @@
 | 
			
		||||
using Shouldly;
 | 
			
		||||
using Spectre.Console.Testing;
 | 
			
		||||
using Xunit;
 | 
			
		||||
namespace Spectre.Console.Tests.Unit;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Unit
 | 
			
		||||
public partial class AnsiConsoleTests
 | 
			
		||||
{
 | 
			
		||||
    public partial class AnsiConsoleTests
 | 
			
		||||
    public sealed class Cursor
 | 
			
		||||
    {
 | 
			
		||||
        public sealed class Cursor
 | 
			
		||||
        public sealed class TheMoveMethod
 | 
			
		||||
        {
 | 
			
		||||
            public sealed class TheMoveMethod
 | 
			
		||||
            [Theory]
 | 
			
		||||
            [InlineData(CursorDirection.Up, "Hello[2AWorld")]
 | 
			
		||||
            [InlineData(CursorDirection.Down, "Hello[2BWorld")]
 | 
			
		||||
            [InlineData(CursorDirection.Right, "Hello[2CWorld")]
 | 
			
		||||
            [InlineData(CursorDirection.Left, "Hello[2DWorld")]
 | 
			
		||||
            public void Should_Return_Correct_Ansi_Code(CursorDirection direction, string expected)
 | 
			
		||||
            {
 | 
			
		||||
                [Theory]
 | 
			
		||||
                [InlineData(CursorDirection.Up, "Hello[2AWorld")]
 | 
			
		||||
                [InlineData(CursorDirection.Down, "Hello[2BWorld")]
 | 
			
		||||
                [InlineData(CursorDirection.Right, "Hello[2CWorld")]
 | 
			
		||||
                [InlineData(CursorDirection.Left, "Hello[2DWorld")]
 | 
			
		||||
                public void Should_Return_Correct_Ansi_Code(CursorDirection direction, string expected)
 | 
			
		||||
                {
 | 
			
		||||
                    // Given
 | 
			
		||||
                    var console = new TestConsole().EmitAnsiSequences();
 | 
			
		||||
                // Given
 | 
			
		||||
                var console = new TestConsole().EmitAnsiSequences();
 | 
			
		||||
 | 
			
		||||
                    // When
 | 
			
		||||
                    console.Write("Hello");
 | 
			
		||||
                    console.Cursor.Move(direction, 2);
 | 
			
		||||
                    console.Write("World");
 | 
			
		||||
                // When
 | 
			
		||||
                console.Write("Hello");
 | 
			
		||||
                console.Cursor.Move(direction, 2);
 | 
			
		||||
                console.Write("World");
 | 
			
		||||
 | 
			
		||||
                    // Then
 | 
			
		||||
                    console.Output.ShouldBe(expected);
 | 
			
		||||
                }
 | 
			
		||||
                // Then
 | 
			
		||||
                console.Output.ShouldBe(expected);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
            public sealed class TheSetPositionMethod
 | 
			
		||||
        public sealed class TheSetPositionMethod
 | 
			
		||||
        {
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Return_Correct_Ansi_Code()
 | 
			
		||||
            {
 | 
			
		||||
                [Fact]
 | 
			
		||||
                public void Should_Return_Correct_Ansi_Code()
 | 
			
		||||
                {
 | 
			
		||||
                    // Given
 | 
			
		||||
                    var console = new TestConsole().EmitAnsiSequences();
 | 
			
		||||
                // Given
 | 
			
		||||
                var console = new TestConsole().EmitAnsiSequences();
 | 
			
		||||
 | 
			
		||||
                    // When
 | 
			
		||||
                    console.Write("Hello");
 | 
			
		||||
                    console.Cursor.SetPosition(5, 3);
 | 
			
		||||
                    console.Write("World");
 | 
			
		||||
                // When
 | 
			
		||||
                console.Write("Hello");
 | 
			
		||||
                console.Cursor.SetPosition(5, 3);
 | 
			
		||||
                console.Write("World");
 | 
			
		||||
 | 
			
		||||
                    // Then
 | 
			
		||||
                    console.Output.ShouldBe("Hello[3;5HWorld");
 | 
			
		||||
                }
 | 
			
		||||
                // Then
 | 
			
		||||
                console.Output.ShouldBe("Hello[3;5HWorld");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,120 +1,114 @@
 | 
			
		||||
using System;
 | 
			
		||||
using Shouldly;
 | 
			
		||||
using Spectre.Console.Testing;
 | 
			
		||||
using Xunit;
 | 
			
		||||
namespace Spectre.Console.Tests.Unit;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Unit
 | 
			
		||||
public partial class AnsiConsoleTests
 | 
			
		||||
{
 | 
			
		||||
    public partial class AnsiConsoleTests
 | 
			
		||||
    public sealed class Markup
 | 
			
		||||
    {
 | 
			
		||||
        public sealed class Markup
 | 
			
		||||
        [Theory]
 | 
			
		||||
        [InlineData("[yellow]Hello[/]", "[93mHello[0m")]
 | 
			
		||||
        [InlineData("[yellow]Hello [italic]World[/]![/]", "[93mHello [0m[3;93mWorld[0m[93m![0m")]
 | 
			
		||||
        public void Should_Output_Expected_Ansi_For_Markup(string markup, string expected)
 | 
			
		||||
        {
 | 
			
		||||
            [Theory]
 | 
			
		||||
            [InlineData("[yellow]Hello[/]", "[93mHello[0m")]
 | 
			
		||||
            [InlineData("[yellow]Hello [italic]World[/]![/]", "[93mHello [0m[3;93mWorld[0m[93m![0m")]
 | 
			
		||||
            public void Should_Output_Expected_Ansi_For_Markup(string markup, string expected)
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var console = new TestConsole()
 | 
			
		||||
                    .Colors(ColorSystem.Standard)
 | 
			
		||||
                    .EmitAnsiSequences();
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole()
 | 
			
		||||
                .Colors(ColorSystem.Standard)
 | 
			
		||||
                .EmitAnsiSequences();
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                console.Markup(markup);
 | 
			
		||||
            // When
 | 
			
		||||
            console.Markup(markup);
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                console.Output.ShouldBe(expected);
 | 
			
		||||
            }
 | 
			
		||||
            // Then
 | 
			
		||||
            console.Output.ShouldBe(expected);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Output_Expected_Ansi_For_Link_With_Url_And_Text()
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var console = new TestConsole()
 | 
			
		||||
                    .EmitAnsiSequences();
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Output_Expected_Ansi_For_Link_With_Url_And_Text()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole()
 | 
			
		||||
                .EmitAnsiSequences();
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                console.Markup("[link=https://patriksvensson.se]Click to visit my blog[/]");
 | 
			
		||||
            // When
 | 
			
		||||
            console.Markup("[link=https://patriksvensson.se]Click to visit my blog[/]");
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                console.Output.ShouldMatch("]8;id=[0-9]*;https:\\/\\/patriksvensson\\.se\\\\Click to visit my blog]8;;\\\\");
 | 
			
		||||
            }
 | 
			
		||||
            // Then
 | 
			
		||||
            console.Output.ShouldMatch("]8;id=[0-9]*;https:\\/\\/patriksvensson\\.se\\\\Click to visit my blog]8;;\\\\");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Output_Expected_Ansi_For_Link_With_Only_Url()
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var console = new TestConsole()
 | 
			
		||||
                    .EmitAnsiSequences();
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Output_Expected_Ansi_For_Link_With_Only_Url()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole()
 | 
			
		||||
                .EmitAnsiSequences();
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                console.Markup("[link]https://patriksvensson.se[/]");
 | 
			
		||||
            // When
 | 
			
		||||
            console.Markup("[link]https://patriksvensson.se[/]");
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                console.Output.ShouldMatch("]8;id=[0-9]*;https:\\/\\/patriksvensson\\.se\\\\https:\\/\\/patriksvensson\\.se]8;;\\\\");
 | 
			
		||||
            }
 | 
			
		||||
            // Then
 | 
			
		||||
            console.Output.ShouldMatch("]8;id=[0-9]*;https:\\/\\/patriksvensson\\.se\\\\https:\\/\\/patriksvensson\\.se]8;;\\\\");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
            [Theory]
 | 
			
		||||
            [InlineData("[yellow]Hello [[ World[/]", "[93mHello [ World[0m")]
 | 
			
		||||
            public void Should_Be_Able_To_Escape_Tags(string markup, string expected)
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var console = new TestConsole()
 | 
			
		||||
                    .Colors(ColorSystem.Standard)
 | 
			
		||||
                    .EmitAnsiSequences();
 | 
			
		||||
        [Theory]
 | 
			
		||||
        [InlineData("[yellow]Hello [[ World[/]", "[93mHello [ World[0m")]
 | 
			
		||||
        public void Should_Be_Able_To_Escape_Tags(string markup, string expected)
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole()
 | 
			
		||||
                .Colors(ColorSystem.Standard)
 | 
			
		||||
                .EmitAnsiSequences();
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                console.Markup(markup);
 | 
			
		||||
            // When
 | 
			
		||||
            console.Markup(markup);
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                console.Output.ShouldBe(expected);
 | 
			
		||||
            }
 | 
			
		||||
            // Then
 | 
			
		||||
            console.Output.ShouldBe(expected);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
            [Theory]
 | 
			
		||||
            [InlineData("[yellow]Hello[", "Encountered malformed markup tag at position 14.")]
 | 
			
		||||
            [InlineData("[yellow]Hello[/", "Encountered malformed markup tag at position 15.")]
 | 
			
		||||
            [InlineData("[yellow]Hello[/foo", "Encountered malformed markup tag at position 15.")]
 | 
			
		||||
            [InlineData("[yellow Hello", "Encountered malformed markup tag at position 13.")]
 | 
			
		||||
            public void Should_Throw_If_Encounters_Malformed_Tag(string markup, string expected)
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var console = new TestConsole();
 | 
			
		||||
        [Theory]
 | 
			
		||||
        [InlineData("[yellow]Hello[", "Encountered malformed markup tag at position 14.")]
 | 
			
		||||
        [InlineData("[yellow]Hello[/", "Encountered malformed markup tag at position 15.")]
 | 
			
		||||
        [InlineData("[yellow]Hello[/foo", "Encountered malformed markup tag at position 15.")]
 | 
			
		||||
        [InlineData("[yellow Hello", "Encountered malformed markup tag at position 13.")]
 | 
			
		||||
        public void Should_Throw_If_Encounters_Malformed_Tag(string markup, string expected)
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = Record.Exception(() => console.Markup(markup));
 | 
			
		||||
            // When
 | 
			
		||||
            var result = Record.Exception(() => console.Markup(markup));
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ShouldBeOfType<InvalidOperationException>()
 | 
			
		||||
                    .Message.ShouldBe(expected);
 | 
			
		||||
            }
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ShouldBeOfType<InvalidOperationException>()
 | 
			
		||||
                .Message.ShouldBe(expected);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Throw_If_Tags_Are_Unbalanced()
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var console = new TestConsole();
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Throw_If_Tags_Are_Unbalanced()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = Record.Exception(() => console.Markup("[yellow][blue]Hello[/]"));
 | 
			
		||||
            // When
 | 
			
		||||
            var result = Record.Exception(() => console.Markup("[yellow][blue]Hello[/]"));
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ShouldBeOfType<InvalidOperationException>()
 | 
			
		||||
                    .Message.ShouldBe("Unbalanced markup stack. Did you forget to close a tag?");
 | 
			
		||||
            }
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ShouldBeOfType<InvalidOperationException>()
 | 
			
		||||
                .Message.ShouldBe("Unbalanced markup stack. Did you forget to close a tag?");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Throw_If_Encounters_Closing_Tag()
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var console = new TestConsole();
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Throw_If_Encounters_Closing_Tag()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = Record.Exception(() => console.Markup("Hello[/]World"));
 | 
			
		||||
            // When
 | 
			
		||||
            var result = Record.Exception(() => console.Markup("Hello[/]World"));
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ShouldBeOfType<InvalidOperationException>()
 | 
			
		||||
                    .Message.ShouldBe("Encountered closing tag when none was expected near position 5.");
 | 
			
		||||
            }
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ShouldBeOfType<InvalidOperationException>()
 | 
			
		||||
                .Message.ShouldBe("Encountered closing tag when none was expected near position 5.");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,29 +1,23 @@
 | 
			
		||||
using System;
 | 
			
		||||
using Shouldly;
 | 
			
		||||
using Spectre.Console.Testing;
 | 
			
		||||
using Xunit;
 | 
			
		||||
namespace Spectre.Console.Tests.Unit;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Unit
 | 
			
		||||
public partial class AnsiConsoleTests
 | 
			
		||||
{
 | 
			
		||||
    public partial class AnsiConsoleTests
 | 
			
		||||
    public sealed class Prompt
 | 
			
		||||
    {
 | 
			
		||||
        public sealed class Prompt
 | 
			
		||||
        [Theory]
 | 
			
		||||
        [InlineData(true, true)]
 | 
			
		||||
        [InlineData(false, false)]
 | 
			
		||||
        public void Should_Return_Default_Value_If_Nothing_Is_Entered(bool expected, bool defaultValue)
 | 
			
		||||
        {
 | 
			
		||||
            [Theory]
 | 
			
		||||
            [InlineData(true, true)]
 | 
			
		||||
            [InlineData(false, false)]
 | 
			
		||||
            public void Should_Return_Default_Value_If_Nothing_Is_Entered(bool expected, bool defaultValue)
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var console = new TestConsole().EmitAnsiSequences();
 | 
			
		||||
                console.Input.PushKey(ConsoleKey.Enter);
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole().EmitAnsiSequences();
 | 
			
		||||
            console.Input.PushKey(ConsoleKey.Enter);
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = console.Confirm("Want some prompt?", defaultValue);
 | 
			
		||||
            // When
 | 
			
		||||
            var result = console.Confirm("Want some prompt?", defaultValue);
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ShouldBe(expected);
 | 
			
		||||
            }
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ShouldBe(expected);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,48 +1,43 @@
 | 
			
		||||
using Shouldly;
 | 
			
		||||
using Spectre.Console.Testing;
 | 
			
		||||
using Xunit;
 | 
			
		||||
namespace Spectre.Console.Tests.Unit;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Unit
 | 
			
		||||
public partial class AnsiConsoleTests
 | 
			
		||||
{
 | 
			
		||||
    public partial class AnsiConsoleTests
 | 
			
		||||
    [Theory]
 | 
			
		||||
    [InlineData(Decoration.Bold, "\u001b[1mHello World[0m")]
 | 
			
		||||
    [InlineData(Decoration.Dim, "\u001b[2mHello World[0m")]
 | 
			
		||||
    [InlineData(Decoration.Italic, "\u001b[3mHello World[0m")]
 | 
			
		||||
    [InlineData(Decoration.Underline, "\u001b[4mHello World[0m")]
 | 
			
		||||
    [InlineData(Decoration.Invert, "\u001b[7mHello World[0m")]
 | 
			
		||||
    [InlineData(Decoration.Conceal, "\u001b[8mHello World[0m")]
 | 
			
		||||
    [InlineData(Decoration.SlowBlink, "\u001b[5mHello World[0m")]
 | 
			
		||||
    [InlineData(Decoration.RapidBlink, "\u001b[6mHello World[0m")]
 | 
			
		||||
    [InlineData(Decoration.Strikethrough, "\u001b[9mHello World[0m")]
 | 
			
		||||
    public void Should_Write_Decorated_Text_Correctly(Decoration decoration, string expected)
 | 
			
		||||
    {
 | 
			
		||||
        [Theory]
 | 
			
		||||
        [InlineData(Decoration.Bold, "\u001b[1mHello World[0m")]
 | 
			
		||||
        [InlineData(Decoration.Dim, "\u001b[2mHello World[0m")]
 | 
			
		||||
        [InlineData(Decoration.Italic, "\u001b[3mHello World[0m")]
 | 
			
		||||
        [InlineData(Decoration.Underline, "\u001b[4mHello World[0m")]
 | 
			
		||||
        [InlineData(Decoration.Invert, "\u001b[7mHello World[0m")]
 | 
			
		||||
        [InlineData(Decoration.Conceal, "\u001b[8mHello World[0m")]
 | 
			
		||||
        [InlineData(Decoration.SlowBlink, "\u001b[5mHello World[0m")]
 | 
			
		||||
        [InlineData(Decoration.RapidBlink, "\u001b[6mHello World[0m")]
 | 
			
		||||
        [InlineData(Decoration.Strikethrough, "\u001b[9mHello World[0m")]
 | 
			
		||||
        public void Should_Write_Decorated_Text_Correctly(Decoration decoration, string expected)
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole()
 | 
			
		||||
                .EmitAnsiSequences();
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole()
 | 
			
		||||
            .EmitAnsiSequences();
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write("Hello World", new Style().Decoration(decoration));
 | 
			
		||||
        // When
 | 
			
		||||
        console.Write("Hello World", new Style().Decoration(decoration));
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            console.Output.ShouldBe(expected);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Theory]
 | 
			
		||||
        [InlineData(Decoration.Bold | Decoration.Underline, "\u001b[1;4mHello World[0m")]
 | 
			
		||||
        [InlineData(Decoration.Bold | Decoration.Underline | Decoration.Conceal, "\u001b[1;4;8mHello World[0m")]
 | 
			
		||||
        public void Should_Write_Text_With_Multiple_Decorations_Correctly(Decoration decoration, string expected)
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole()
 | 
			
		||||
                .EmitAnsiSequences();
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write("Hello World", new Style().Decoration(decoration));
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            console.Output.ShouldBe(expected);
 | 
			
		||||
        }
 | 
			
		||||
        // Then
 | 
			
		||||
        console.Output.ShouldBe(expected);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    [Theory]
 | 
			
		||||
    [InlineData(Decoration.Bold | Decoration.Underline, "\u001b[1;4mHello World[0m")]
 | 
			
		||||
    [InlineData(Decoration.Bold | Decoration.Underline | Decoration.Conceal, "\u001b[1;4;8mHello World[0m")]
 | 
			
		||||
    public void Should_Write_Text_With_Multiple_Decorations_Correctly(Decoration decoration, string expected)
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole()
 | 
			
		||||
            .EmitAnsiSequences();
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.Write("Hello World", new Style().Decoration(decoration));
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        console.Output.ShouldBe(expected);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,151 +1,145 @@
 | 
			
		||||
using System;
 | 
			
		||||
using Shouldly;
 | 
			
		||||
using Spectre.Console.Testing;
 | 
			
		||||
using Xunit;
 | 
			
		||||
namespace Spectre.Console.Tests.Unit;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Unit
 | 
			
		||||
public partial class AnsiConsoleTests
 | 
			
		||||
{
 | 
			
		||||
    public partial class AnsiConsoleTests
 | 
			
		||||
    public sealed class Clear
 | 
			
		||||
    {
 | 
			
		||||
        public sealed class Clear
 | 
			
		||||
        [Theory]
 | 
			
		||||
        [InlineData(false, "Hello[2J[3JWorld")]
 | 
			
		||||
        [InlineData(true, "Hello[2J[3J[1;1HWorld")]
 | 
			
		||||
        public void Should_Clear_Screen(bool home, string expected)
 | 
			
		||||
        {
 | 
			
		||||
            [Theory]
 | 
			
		||||
            [InlineData(false, "Hello[2J[3JWorld")]
 | 
			
		||||
            [InlineData(true, "Hello[2J[3J[1;1HWorld")]
 | 
			
		||||
            public void Should_Clear_Screen(bool home, string expected)
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var console = new TestConsole()
 | 
			
		||||
                    .Colors(ColorSystem.Standard)
 | 
			
		||||
                    .EmitAnsiSequences();
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole()
 | 
			
		||||
                .Colors(ColorSystem.Standard)
 | 
			
		||||
                .EmitAnsiSequences();
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                console.Write("Hello");
 | 
			
		||||
                console.Clear(home);
 | 
			
		||||
                console.Write("World");
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write("Hello");
 | 
			
		||||
            console.Clear(home);
 | 
			
		||||
            console.Write("World");
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                console.Output.ShouldBe(expected);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public sealed class Write
 | 
			
		||||
        {
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Combine_Decoration_And_Colors()
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var console = new TestConsole()
 | 
			
		||||
                    .Colors(ColorSystem.Standard)
 | 
			
		||||
                    .EmitAnsiSequences();
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                console.Write(
 | 
			
		||||
                    "Hello",
 | 
			
		||||
                    new Style()
 | 
			
		||||
                        .Foreground(Color.RoyalBlue1)
 | 
			
		||||
                        .Background(Color.NavajoWhite1)
 | 
			
		||||
                        .Decoration(Decoration.Italic));
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                console.Output.ShouldBe("\u001b[3;90;47mHello\u001b[0m");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Not_Include_Foreground_If_Set_To_Default_Color()
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var console = new TestConsole()
 | 
			
		||||
                    .Colors(ColorSystem.Standard)
 | 
			
		||||
                    .EmitAnsiSequences();
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                console.Write(
 | 
			
		||||
                    "Hello",
 | 
			
		||||
                    new Style()
 | 
			
		||||
                        .Foreground(Color.Default)
 | 
			
		||||
                        .Background(Color.NavajoWhite1)
 | 
			
		||||
                        .Decoration(Decoration.Italic));
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                console.Output.ShouldBe("\u001b[3;47mHello\u001b[0m");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Not_Include_Background_If_Set_To_Default_Color()
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var console = new TestConsole()
 | 
			
		||||
                    .Colors(ColorSystem.Standard)
 | 
			
		||||
                    .EmitAnsiSequences();
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                console.Write(
 | 
			
		||||
                    "Hello",
 | 
			
		||||
                    new Style()
 | 
			
		||||
                        .Foreground(Color.RoyalBlue1)
 | 
			
		||||
                        .Background(Color.Default)
 | 
			
		||||
                        .Decoration(Decoration.Italic));
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                console.Output.ShouldBe("\u001b[3;90mHello\u001b[0m");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Not_Include_Decoration_If_Set_To_None()
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var console = new TestConsole()
 | 
			
		||||
                    .Colors(ColorSystem.Standard)
 | 
			
		||||
                    .EmitAnsiSequences();
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                console.Write(
 | 
			
		||||
                    "Hello",
 | 
			
		||||
                    new Style()
 | 
			
		||||
                        .Foreground(Color.RoyalBlue1)
 | 
			
		||||
                        .Background(Color.NavajoWhite1)
 | 
			
		||||
                        .Decoration(Decoration.None));
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                console.Output.ShouldBe("\u001b[90;47mHello\u001b[0m");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public sealed class WriteLine
 | 
			
		||||
        {
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Reset_Colors_Correctly_After_Line_Break()
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var console = new TestConsole()
 | 
			
		||||
                    .Colors(ColorSystem.Standard)
 | 
			
		||||
                    .EmitAnsiSequences();
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                console.WriteLine("Hello", new Style().Background(ConsoleColor.Red));
 | 
			
		||||
                console.WriteLine("World", new Style().Background(ConsoleColor.Green));
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                console.Output.NormalizeLineEndings()
 | 
			
		||||
                    .ShouldBe("[101mHello[0m\n[102mWorld[0m\n");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Reset_Colors_Correctly_After_Line_Break_In_Text()
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var console = new TestConsole()
 | 
			
		||||
                    .Colors(ColorSystem.Standard)
 | 
			
		||||
                    .EmitAnsiSequences();
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                console.WriteLine("Hello\nWorld", new Style().Background(ConsoleColor.Red));
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                console.Output.NormalizeLineEndings()
 | 
			
		||||
                    .ShouldBe("[101mHello[0m\n[101mWorld[0m\n");
 | 
			
		||||
            }
 | 
			
		||||
            // Then
 | 
			
		||||
            console.Output.ShouldBe(expected);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    public sealed class Write
 | 
			
		||||
    {
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Combine_Decoration_And_Colors()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole()
 | 
			
		||||
                .Colors(ColorSystem.Standard)
 | 
			
		||||
                .EmitAnsiSequences();
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(
 | 
			
		||||
                "Hello",
 | 
			
		||||
                new Style()
 | 
			
		||||
                    .Foreground(Color.RoyalBlue1)
 | 
			
		||||
                    .Background(Color.NavajoWhite1)
 | 
			
		||||
                    .Decoration(Decoration.Italic));
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            console.Output.ShouldBe("\u001b[3;90;47mHello\u001b[0m");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Not_Include_Foreground_If_Set_To_Default_Color()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole()
 | 
			
		||||
                .Colors(ColorSystem.Standard)
 | 
			
		||||
                .EmitAnsiSequences();
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(
 | 
			
		||||
                "Hello",
 | 
			
		||||
                new Style()
 | 
			
		||||
                    .Foreground(Color.Default)
 | 
			
		||||
                    .Background(Color.NavajoWhite1)
 | 
			
		||||
                    .Decoration(Decoration.Italic));
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            console.Output.ShouldBe("\u001b[3;47mHello\u001b[0m");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Not_Include_Background_If_Set_To_Default_Color()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole()
 | 
			
		||||
                .Colors(ColorSystem.Standard)
 | 
			
		||||
                .EmitAnsiSequences();
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(
 | 
			
		||||
                "Hello",
 | 
			
		||||
                new Style()
 | 
			
		||||
                    .Foreground(Color.RoyalBlue1)
 | 
			
		||||
                    .Background(Color.Default)
 | 
			
		||||
                    .Decoration(Decoration.Italic));
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            console.Output.ShouldBe("\u001b[3;90mHello\u001b[0m");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Not_Include_Decoration_If_Set_To_None()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole()
 | 
			
		||||
                .Colors(ColorSystem.Standard)
 | 
			
		||||
                .EmitAnsiSequences();
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(
 | 
			
		||||
                "Hello",
 | 
			
		||||
                new Style()
 | 
			
		||||
                    .Foreground(Color.RoyalBlue1)
 | 
			
		||||
                    .Background(Color.NavajoWhite1)
 | 
			
		||||
                    .Decoration(Decoration.None));
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            console.Output.ShouldBe("\u001b[90;47mHello\u001b[0m");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public sealed class WriteLine
 | 
			
		||||
    {
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Reset_Colors_Correctly_After_Line_Break()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole()
 | 
			
		||||
                .Colors(ColorSystem.Standard)
 | 
			
		||||
                .EmitAnsiSequences();
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.WriteLine("Hello", new Style().Background(ConsoleColor.Red));
 | 
			
		||||
            console.WriteLine("World", new Style().Background(ConsoleColor.Green));
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            console.Output.NormalizeLineEndings()
 | 
			
		||||
                .ShouldBe("[101mHello[0m\n[102mWorld[0m\n");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Reset_Colors_Correctly_After_Line_Break_In_Text()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole()
 | 
			
		||||
                .Colors(ColorSystem.Standard)
 | 
			
		||||
                .EmitAnsiSequences();
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.WriteLine("Hello\nWorld", new Style().Background(ConsoleColor.Red));
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            console.Output.NormalizeLineEndings()
 | 
			
		||||
                .ShouldBe("[101mHello[0m\n[101mWorld[0m\n");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,97 +1,88 @@
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Spectre.Console.Cli;
 | 
			
		||||
using Spectre.Console.Testing;
 | 
			
		||||
using Spectre.Console.Tests.Data;
 | 
			
		||||
using Spectre.Verify.Extensions;
 | 
			
		||||
using VerifyXunit;
 | 
			
		||||
using Xunit;
 | 
			
		||||
namespace Spectre.Console.Tests.Unit.Cli.Annotations;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Unit.Cli.Annotations
 | 
			
		||||
[ExpectationPath("Cli/Arguments")]
 | 
			
		||||
public sealed partial class CommandArgumentAttributeTests
 | 
			
		||||
{
 | 
			
		||||
    [ExpectationPath("Cli/Arguments")]
 | 
			
		||||
    public sealed partial class CommandArgumentAttributeTests
 | 
			
		||||
    [UsesVerify]
 | 
			
		||||
    public sealed class ArgumentCannotContainOptions
 | 
			
		||||
    {
 | 
			
		||||
        [UsesVerify]
 | 
			
		||||
        public sealed class ArgumentCannotContainOptions
 | 
			
		||||
        public sealed class Settings : CommandSettings
 | 
			
		||||
        {
 | 
			
		||||
            public sealed class Settings : CommandSettings
 | 
			
		||||
            {
 | 
			
		||||
                [CommandArgument(0, "--foo <BAR>")]
 | 
			
		||||
                public string Foo { get; set; }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            [Expectation("ArgumentCannotContainOptions")]
 | 
			
		||||
            public Task Should_Return_Correct_Text()
 | 
			
		||||
            {
 | 
			
		||||
                // Given, When
 | 
			
		||||
                var result = Fixture.Run<Settings>();
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                return Verifier.Verify(result);
 | 
			
		||||
            }
 | 
			
		||||
            [CommandArgument(0, "--foo <BAR>")]
 | 
			
		||||
            public string Foo { get; set; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [UsesVerify]
 | 
			
		||||
        public sealed class MultipleValuesAreNotSupported
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("ArgumentCannotContainOptions")]
 | 
			
		||||
        public Task Should_Return_Correct_Text()
 | 
			
		||||
        {
 | 
			
		||||
            public sealed class Settings : CommandSettings
 | 
			
		||||
            {
 | 
			
		||||
                [CommandArgument(0, "<FOO> <BAR>")]
 | 
			
		||||
                public string Foo { get; set; }
 | 
			
		||||
            }
 | 
			
		||||
            // Given, When
 | 
			
		||||
            var result = Fixture.Run<Settings>();
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            [Expectation("MultipleValuesAreNotSupported")]
 | 
			
		||||
            public Task Should_Return_Correct_Text()
 | 
			
		||||
            {
 | 
			
		||||
                // Given, When
 | 
			
		||||
                var result = Fixture.Run<Settings>();
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(result);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                return Verifier.Verify(result);
 | 
			
		||||
            }
 | 
			
		||||
    [UsesVerify]
 | 
			
		||||
    public sealed class MultipleValuesAreNotSupported
 | 
			
		||||
    {
 | 
			
		||||
        public sealed class Settings : CommandSettings
 | 
			
		||||
        {
 | 
			
		||||
            [CommandArgument(0, "<FOO> <BAR>")]
 | 
			
		||||
            public string Foo { get; set; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [UsesVerify]
 | 
			
		||||
        public sealed class ValuesMustHaveName
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("MultipleValuesAreNotSupported")]
 | 
			
		||||
        public Task Should_Return_Correct_Text()
 | 
			
		||||
        {
 | 
			
		||||
            public sealed class Settings : CommandSettings
 | 
			
		||||
            {
 | 
			
		||||
                [CommandArgument(0, "<>")]
 | 
			
		||||
                public string Foo { get; set; }
 | 
			
		||||
            }
 | 
			
		||||
            // Given, When
 | 
			
		||||
            var result = Fixture.Run<Settings>();
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            [Expectation("ValuesMustHaveName")]
 | 
			
		||||
            public Task Should_Return_Correct_Text()
 | 
			
		||||
            {
 | 
			
		||||
                // Given, When
 | 
			
		||||
                var result = Fixture.Run<Settings>();
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(result);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                return Verifier.Verify(result);
 | 
			
		||||
            }
 | 
			
		||||
    [UsesVerify]
 | 
			
		||||
    public sealed class ValuesMustHaveName
 | 
			
		||||
    {
 | 
			
		||||
        public sealed class Settings : CommandSettings
 | 
			
		||||
        {
 | 
			
		||||
            [CommandArgument(0, "<>")]
 | 
			
		||||
            public string Foo { get; set; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static class Fixture
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("ValuesMustHaveName")]
 | 
			
		||||
        public Task Should_Return_Correct_Text()
 | 
			
		||||
        {
 | 
			
		||||
            public static string Run<TSettings>(params string[] args)
 | 
			
		||||
                where TSettings : CommandSettings
 | 
			
		||||
            {
 | 
			
		||||
                using (var writer = new TestConsole())
 | 
			
		||||
                {
 | 
			
		||||
                    var app = new CommandApp();
 | 
			
		||||
                    app.Configure(c => c.ConfigureConsole(writer));
 | 
			
		||||
                    app.Configure(c => c.AddCommand<GenericCommand<TSettings>>("foo"));
 | 
			
		||||
                    app.Run(args);
 | 
			
		||||
            // Given, When
 | 
			
		||||
            var result = Fixture.Run<Settings>();
 | 
			
		||||
 | 
			
		||||
                    return writer.Output
 | 
			
		||||
                        .NormalizeLineEndings()
 | 
			
		||||
                        .TrimLines()
 | 
			
		||||
                        .Trim();
 | 
			
		||||
                }
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(result);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static class Fixture
 | 
			
		||||
    {
 | 
			
		||||
        public static string Run<TSettings>(params string[] args)
 | 
			
		||||
            where TSettings : CommandSettings
 | 
			
		||||
        {
 | 
			
		||||
            using (var writer = new TestConsole())
 | 
			
		||||
            {
 | 
			
		||||
                var app = new CommandApp();
 | 
			
		||||
                app.Configure(c => c.ConfigureConsole(writer));
 | 
			
		||||
                app.Configure(c => c.AddCommand<GenericCommand<TSettings>>("foo"));
 | 
			
		||||
                app.Run(args);
 | 
			
		||||
 | 
			
		||||
                return writer.Output
 | 
			
		||||
                    .NormalizeLineEndings()
 | 
			
		||||
                    .TrimLines()
 | 
			
		||||
                    .Trim();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,64 +1,59 @@
 | 
			
		||||
using Shouldly;
 | 
			
		||||
using Spectre.Console.Cli;
 | 
			
		||||
using Xunit;
 | 
			
		||||
namespace Spectre.Console.Tests.Unit.Cli.Annotations;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Unit.Cli.Annotations
 | 
			
		||||
public sealed partial class CommandArgumentAttributeTests
 | 
			
		||||
{
 | 
			
		||||
    public sealed partial class CommandArgumentAttributeTests
 | 
			
		||||
    [Fact]
 | 
			
		||||
    public void Should_Not_Contain_Options()
 | 
			
		||||
    {
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Not_Contain_Options()
 | 
			
		||||
        {
 | 
			
		||||
            // Given, When
 | 
			
		||||
            var result = Record.Exception(() => new CommandArgumentAttribute(0, "--foo <BAR>"));
 | 
			
		||||
        // Given, When
 | 
			
		||||
        var result = Record.Exception(() => new CommandArgumentAttribute(0, "--foo <BAR>"));
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ShouldNotBe(null);
 | 
			
		||||
            result.ShouldBeOfType<CommandTemplateException>().And(exception =>
 | 
			
		||||
                exception.Message.ShouldBe("Arguments can not contain options."));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Theory]
 | 
			
		||||
        [InlineData("<FOO> <BAR>")]
 | 
			
		||||
        [InlineData("[FOO] [BAR]")]
 | 
			
		||||
        [InlineData("[FOO] <BAR>")]
 | 
			
		||||
        [InlineData("<FOO> [BAR]")]
 | 
			
		||||
        public void Should_Not_Contain_Multiple_Value_Names(string template)
 | 
			
		||||
        {
 | 
			
		||||
            // Given, When
 | 
			
		||||
            var result = Record.Exception(() => new CommandArgumentAttribute(0, template));
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ShouldNotBe(null);
 | 
			
		||||
            result.ShouldBeOfType<CommandTemplateException>().And(exception =>
 | 
			
		||||
                exception.Message.ShouldBe("Multiple values are not supported."));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Theory]
 | 
			
		||||
        [InlineData("<>")]
 | 
			
		||||
        [InlineData("[]")]
 | 
			
		||||
        public void Should_Not_Contain_Empty_Value_Name(string template)
 | 
			
		||||
        {
 | 
			
		||||
            // Given, When
 | 
			
		||||
            var result = Record.Exception(() => new CommandArgumentAttribute(0, template));
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ShouldNotBe(null);
 | 
			
		||||
            result.ShouldBeOfType<CommandTemplateException>().And(exception =>
 | 
			
		||||
                exception.Message.ShouldBe("Values without name are not allowed."));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Theory]
 | 
			
		||||
        [InlineData("<FOO>", true)]
 | 
			
		||||
        [InlineData("[FOO]", false)]
 | 
			
		||||
        public void Should_Parse_Valid_Options(string template, bool required)
 | 
			
		||||
        {
 | 
			
		||||
            // Given, When
 | 
			
		||||
            var result = new CommandArgumentAttribute(0, template);
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ValueName.ShouldBe("FOO");
 | 
			
		||||
            result.IsRequired.ShouldBe(required);
 | 
			
		||||
        }
 | 
			
		||||
        // Then
 | 
			
		||||
        result.ShouldNotBe(null);
 | 
			
		||||
        result.ShouldBeOfType<CommandTemplateException>().And(exception =>
 | 
			
		||||
            exception.Message.ShouldBe("Arguments can not contain options."));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    [Theory]
 | 
			
		||||
    [InlineData("<FOO> <BAR>")]
 | 
			
		||||
    [InlineData("[FOO] [BAR]")]
 | 
			
		||||
    [InlineData("[FOO] <BAR>")]
 | 
			
		||||
    [InlineData("<FOO> [BAR]")]
 | 
			
		||||
    public void Should_Not_Contain_Multiple_Value_Names(string template)
 | 
			
		||||
    {
 | 
			
		||||
        // Given, When
 | 
			
		||||
        var result = Record.Exception(() => new CommandArgumentAttribute(0, template));
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        result.ShouldNotBe(null);
 | 
			
		||||
        result.ShouldBeOfType<CommandTemplateException>().And(exception =>
 | 
			
		||||
            exception.Message.ShouldBe("Multiple values are not supported."));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Theory]
 | 
			
		||||
    [InlineData("<>")]
 | 
			
		||||
    [InlineData("[]")]
 | 
			
		||||
    public void Should_Not_Contain_Empty_Value_Name(string template)
 | 
			
		||||
    {
 | 
			
		||||
        // Given, When
 | 
			
		||||
        var result = Record.Exception(() => new CommandArgumentAttribute(0, template));
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        result.ShouldNotBe(null);
 | 
			
		||||
        result.ShouldBeOfType<CommandTemplateException>().And(exception =>
 | 
			
		||||
            exception.Message.ShouldBe("Values without name are not allowed."));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Theory]
 | 
			
		||||
    [InlineData("<FOO>", true)]
 | 
			
		||||
    [InlineData("[FOO]", false)]
 | 
			
		||||
    public void Should_Parse_Valid_Options(string template, bool required)
 | 
			
		||||
    {
 | 
			
		||||
        // Given, When
 | 
			
		||||
        var result = new CommandArgumentAttribute(0, template);
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        result.ValueName.ShouldBe("FOO");
 | 
			
		||||
        result.IsRequired.ShouldBe(required);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,250 +1,240 @@
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Shouldly;
 | 
			
		||||
using Spectre.Console.Cli;
 | 
			
		||||
using Spectre.Console.Testing;
 | 
			
		||||
using Spectre.Console.Tests.Data;
 | 
			
		||||
using Spectre.Verify.Extensions;
 | 
			
		||||
using VerifyXunit;
 | 
			
		||||
using Xunit;
 | 
			
		||||
namespace Spectre.Console.Tests.Unit.Cli.Annotations;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Unit.Cli.Annotations
 | 
			
		||||
[ExpectationPath("Cli/Arguments")]
 | 
			
		||||
public sealed partial class CommandOptionAttributeTests
 | 
			
		||||
{
 | 
			
		||||
    [ExpectationPath("Cli/Arguments")]
 | 
			
		||||
    public sealed partial class CommandOptionAttributeTests
 | 
			
		||||
    [UsesVerify]
 | 
			
		||||
    public sealed class UnexpectedCharacter
 | 
			
		||||
    {
 | 
			
		||||
        [UsesVerify]
 | 
			
		||||
        public sealed class UnexpectedCharacter
 | 
			
		||||
        public sealed class Settings : CommandSettings
 | 
			
		||||
        {
 | 
			
		||||
            public sealed class Settings : CommandSettings
 | 
			
		||||
            {
 | 
			
		||||
                [CommandOption("<FOO> $ <BAR>")]
 | 
			
		||||
                public string Foo { get; set; }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            [Expectation("UnexpectedCharacter")]
 | 
			
		||||
            public Task Should_Return_Correct_Text()
 | 
			
		||||
            {
 | 
			
		||||
                // Given, When
 | 
			
		||||
                var result = Fixture.Run<Settings>();
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.Exception.Message.ShouldBe("Encountered unexpected character '$'.");
 | 
			
		||||
                return Verifier.Verify(result.Output);
 | 
			
		||||
            }
 | 
			
		||||
            [CommandOption("<FOO> $ <BAR>")]
 | 
			
		||||
            public string Foo { get; set; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [UsesVerify]
 | 
			
		||||
        public sealed class UnterminatedValueName
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("UnexpectedCharacter")]
 | 
			
		||||
        public Task Should_Return_Correct_Text()
 | 
			
		||||
        {
 | 
			
		||||
            public sealed class Settings : CommandSettings
 | 
			
		||||
            {
 | 
			
		||||
                [CommandOption("--foo|-f <BAR")]
 | 
			
		||||
                public string Foo { get; set; }
 | 
			
		||||
            }
 | 
			
		||||
            // Given, When
 | 
			
		||||
            var result = Fixture.Run<Settings>();
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            [Expectation("UnterminatedValueName")]
 | 
			
		||||
            public Task Should_Return_Correct_Text()
 | 
			
		||||
            {
 | 
			
		||||
                // Given, When
 | 
			
		||||
                var result = Fixture.Run<Settings>();
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.Exception.Message.ShouldBe("Encountered unterminated value name 'BAR'.");
 | 
			
		||||
                return Verifier.Verify(result.Output);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [UsesVerify]
 | 
			
		||||
        public sealed class OptionsMustHaveName
 | 
			
		||||
        {
 | 
			
		||||
            public sealed class Settings : CommandSettings
 | 
			
		||||
            {
 | 
			
		||||
                [CommandOption("--foo|-")]
 | 
			
		||||
                public string Foo { get; set; }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            [Expectation("OptionsMustHaveName")]
 | 
			
		||||
            public Task Should_Return_Correct_Text()
 | 
			
		||||
            {
 | 
			
		||||
                // Given, When
 | 
			
		||||
                var result = Fixture.Run<Settings>();
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.Exception.Message.ShouldBe("Options without name are not allowed.");
 | 
			
		||||
                return Verifier.Verify(result.Output);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [UsesVerify]
 | 
			
		||||
        public sealed class OptionNamesCannotStartWithDigit
 | 
			
		||||
        {
 | 
			
		||||
            public sealed class Settings : CommandSettings
 | 
			
		||||
            {
 | 
			
		||||
                [CommandOption("--1foo")]
 | 
			
		||||
                public string Foo { get; set; }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            [Expectation("OptionNamesCannotStartWithDigit")]
 | 
			
		||||
            public Task Should_Return_Correct_Text()
 | 
			
		||||
            {
 | 
			
		||||
                // Given, When
 | 
			
		||||
                var result = Fixture.Run<Settings>();
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.Exception.Message.ShouldBe("Option names cannot start with a digit.");
 | 
			
		||||
                return Verifier.Verify(result.Output);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [UsesVerify]
 | 
			
		||||
        public sealed class InvalidCharacterInOptionName
 | 
			
		||||
        {
 | 
			
		||||
            public sealed class Settings : CommandSettings
 | 
			
		||||
            {
 | 
			
		||||
                [CommandOption("--f$oo")]
 | 
			
		||||
                public string Foo { get; set; }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            [Expectation("InvalidCharacterInOptionName")]
 | 
			
		||||
            public Task Should_Return_Correct_Text()
 | 
			
		||||
            {
 | 
			
		||||
                // Given, When
 | 
			
		||||
                var result = Fixture.Run<Settings>();
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.Exception.Message.ShouldBe("Encountered invalid character '$' in option name.");
 | 
			
		||||
                return Verifier.Verify(result.Output);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [UsesVerify]
 | 
			
		||||
        public sealed class LongOptionMustHaveMoreThanOneCharacter
 | 
			
		||||
        {
 | 
			
		||||
            public sealed class Settings : CommandSettings
 | 
			
		||||
            {
 | 
			
		||||
                [CommandOption("--f")]
 | 
			
		||||
                public string Foo { get; set; }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            [Expectation("LongOptionMustHaveMoreThanOneCharacter")]
 | 
			
		||||
            public Task Should_Return_Correct_Text()
 | 
			
		||||
            {
 | 
			
		||||
                // Given, When
 | 
			
		||||
                var result = Fixture.Run<Settings>();
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.Exception.Message.ShouldBe("Long option names must consist of more than one character.");
 | 
			
		||||
                return Verifier.Verify(result.Output);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [UsesVerify]
 | 
			
		||||
        public sealed class ShortOptionMustOnlyBeOneCharacter
 | 
			
		||||
        {
 | 
			
		||||
            public sealed class Settings : CommandSettings
 | 
			
		||||
            {
 | 
			
		||||
                [CommandOption("--foo|-bar")]
 | 
			
		||||
                public string Foo { get; set; }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            [Expectation("ShortOptionMustOnlyBeOneCharacter")]
 | 
			
		||||
            public Task Should_Return_Correct_Text()
 | 
			
		||||
            {
 | 
			
		||||
                // Given, When
 | 
			
		||||
                var result = Fixture.Run<Settings>();
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.Exception.Message.ShouldBe("Short option names can not be longer than one character.");
 | 
			
		||||
                return Verifier.Verify(result.Output);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [UsesVerify]
 | 
			
		||||
        public sealed class MultipleOptionValuesAreNotSupported
 | 
			
		||||
        {
 | 
			
		||||
            public sealed class Settings : CommandSettings
 | 
			
		||||
            {
 | 
			
		||||
                [CommandOption("-f|--foo <FOO> <BAR>")]
 | 
			
		||||
                public string Foo { get; set; }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            [Expectation("MultipleOptionValuesAreNotSupported")]
 | 
			
		||||
            public Task Should_Return_Correct_Text()
 | 
			
		||||
            {
 | 
			
		||||
                // Given, When
 | 
			
		||||
                var result = Fixture.Run<Settings>();
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.Exception.Message.ShouldBe("Multiple option values are not supported.");
 | 
			
		||||
                return Verifier.Verify(result.Output);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [UsesVerify]
 | 
			
		||||
        public sealed class InvalidCharacterInValueName
 | 
			
		||||
        {
 | 
			
		||||
            public sealed class Settings : CommandSettings
 | 
			
		||||
            {
 | 
			
		||||
                [CommandOption("-f|--foo <F$OO>")]
 | 
			
		||||
                public string Foo { get; set; }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            [Expectation("InvalidCharacterInValueName")]
 | 
			
		||||
            public Task Should_Return_Correct_Text()
 | 
			
		||||
            {
 | 
			
		||||
                // Given, When
 | 
			
		||||
                var result = Fixture.Run<Settings>();
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.Exception.Message.ShouldBe("Encountered invalid character '$' in value name.");
 | 
			
		||||
                return Verifier.Verify(result.Output);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [UsesVerify]
 | 
			
		||||
        public sealed class MissingLongAndShortName
 | 
			
		||||
        {
 | 
			
		||||
            public sealed class Settings : CommandSettings
 | 
			
		||||
            {
 | 
			
		||||
                [CommandOption("<FOO>")]
 | 
			
		||||
                public string Foo { get; set; }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            [Expectation("MissingLongAndShortName")]
 | 
			
		||||
            public Task Should_Return_Correct_Text()
 | 
			
		||||
            {
 | 
			
		||||
                // Given, When
 | 
			
		||||
                var result = Fixture.Run<Settings>();
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.Exception.Message.ShouldBe("No long or short name for option has been specified.");
 | 
			
		||||
                return Verifier.Verify(result.Output);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static class Fixture
 | 
			
		||||
        {
 | 
			
		||||
            public static CommandAppFailure Run<TSettings>(params string[] args)
 | 
			
		||||
                where TSettings : CommandSettings
 | 
			
		||||
            {
 | 
			
		||||
                var app = new CommandAppTester();
 | 
			
		||||
                app.Configure(c =>
 | 
			
		||||
                {
 | 
			
		||||
                    c.AddCommand<GenericCommand<TSettings>>("foo");
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                return app.RunAndCatch<CommandTemplateException>(args);
 | 
			
		||||
            }
 | 
			
		||||
            // Then
 | 
			
		||||
            result.Exception.Message.ShouldBe("Encountered unexpected character '$'.");
 | 
			
		||||
            return Verifier.Verify(result.Output);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    [UsesVerify]
 | 
			
		||||
    public sealed class UnterminatedValueName
 | 
			
		||||
    {
 | 
			
		||||
        public sealed class Settings : CommandSettings
 | 
			
		||||
        {
 | 
			
		||||
            [CommandOption("--foo|-f <BAR")]
 | 
			
		||||
            public string Foo { get; set; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("UnterminatedValueName")]
 | 
			
		||||
        public Task Should_Return_Correct_Text()
 | 
			
		||||
        {
 | 
			
		||||
            // Given, When
 | 
			
		||||
            var result = Fixture.Run<Settings>();
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.Exception.Message.ShouldBe("Encountered unterminated value name 'BAR'.");
 | 
			
		||||
            return Verifier.Verify(result.Output);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [UsesVerify]
 | 
			
		||||
    public sealed class OptionsMustHaveName
 | 
			
		||||
    {
 | 
			
		||||
        public sealed class Settings : CommandSettings
 | 
			
		||||
        {
 | 
			
		||||
            [CommandOption("--foo|-")]
 | 
			
		||||
            public string Foo { get; set; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("OptionsMustHaveName")]
 | 
			
		||||
        public Task Should_Return_Correct_Text()
 | 
			
		||||
        {
 | 
			
		||||
            // Given, When
 | 
			
		||||
            var result = Fixture.Run<Settings>();
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.Exception.Message.ShouldBe("Options without name are not allowed.");
 | 
			
		||||
            return Verifier.Verify(result.Output);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [UsesVerify]
 | 
			
		||||
    public sealed class OptionNamesCannotStartWithDigit
 | 
			
		||||
    {
 | 
			
		||||
        public sealed class Settings : CommandSettings
 | 
			
		||||
        {
 | 
			
		||||
            [CommandOption("--1foo")]
 | 
			
		||||
            public string Foo { get; set; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("OptionNamesCannotStartWithDigit")]
 | 
			
		||||
        public Task Should_Return_Correct_Text()
 | 
			
		||||
        {
 | 
			
		||||
            // Given, When
 | 
			
		||||
            var result = Fixture.Run<Settings>();
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.Exception.Message.ShouldBe("Option names cannot start with a digit.");
 | 
			
		||||
            return Verifier.Verify(result.Output);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [UsesVerify]
 | 
			
		||||
    public sealed class InvalidCharacterInOptionName
 | 
			
		||||
    {
 | 
			
		||||
        public sealed class Settings : CommandSettings
 | 
			
		||||
        {
 | 
			
		||||
            [CommandOption("--f$oo")]
 | 
			
		||||
            public string Foo { get; set; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("InvalidCharacterInOptionName")]
 | 
			
		||||
        public Task Should_Return_Correct_Text()
 | 
			
		||||
        {
 | 
			
		||||
            // Given, When
 | 
			
		||||
            var result = Fixture.Run<Settings>();
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.Exception.Message.ShouldBe("Encountered invalid character '$' in option name.");
 | 
			
		||||
            return Verifier.Verify(result.Output);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [UsesVerify]
 | 
			
		||||
    public sealed class LongOptionMustHaveMoreThanOneCharacter
 | 
			
		||||
    {
 | 
			
		||||
        public sealed class Settings : CommandSettings
 | 
			
		||||
        {
 | 
			
		||||
            [CommandOption("--f")]
 | 
			
		||||
            public string Foo { get; set; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("LongOptionMustHaveMoreThanOneCharacter")]
 | 
			
		||||
        public Task Should_Return_Correct_Text()
 | 
			
		||||
        {
 | 
			
		||||
            // Given, When
 | 
			
		||||
            var result = Fixture.Run<Settings>();
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.Exception.Message.ShouldBe("Long option names must consist of more than one character.");
 | 
			
		||||
            return Verifier.Verify(result.Output);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [UsesVerify]
 | 
			
		||||
    public sealed class ShortOptionMustOnlyBeOneCharacter
 | 
			
		||||
    {
 | 
			
		||||
        public sealed class Settings : CommandSettings
 | 
			
		||||
        {
 | 
			
		||||
            [CommandOption("--foo|-bar")]
 | 
			
		||||
            public string Foo { get; set; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("ShortOptionMustOnlyBeOneCharacter")]
 | 
			
		||||
        public Task Should_Return_Correct_Text()
 | 
			
		||||
        {
 | 
			
		||||
            // Given, When
 | 
			
		||||
            var result = Fixture.Run<Settings>();
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.Exception.Message.ShouldBe("Short option names can not be longer than one character.");
 | 
			
		||||
            return Verifier.Verify(result.Output);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [UsesVerify]
 | 
			
		||||
    public sealed class MultipleOptionValuesAreNotSupported
 | 
			
		||||
    {
 | 
			
		||||
        public sealed class Settings : CommandSettings
 | 
			
		||||
        {
 | 
			
		||||
            [CommandOption("-f|--foo <FOO> <BAR>")]
 | 
			
		||||
            public string Foo { get; set; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("MultipleOptionValuesAreNotSupported")]
 | 
			
		||||
        public Task Should_Return_Correct_Text()
 | 
			
		||||
        {
 | 
			
		||||
            // Given, When
 | 
			
		||||
            var result = Fixture.Run<Settings>();
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.Exception.Message.ShouldBe("Multiple option values are not supported.");
 | 
			
		||||
            return Verifier.Verify(result.Output);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [UsesVerify]
 | 
			
		||||
    public sealed class InvalidCharacterInValueName
 | 
			
		||||
    {
 | 
			
		||||
        public sealed class Settings : CommandSettings
 | 
			
		||||
        {
 | 
			
		||||
            [CommandOption("-f|--foo <F$OO>")]
 | 
			
		||||
            public string Foo { get; set; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("InvalidCharacterInValueName")]
 | 
			
		||||
        public Task Should_Return_Correct_Text()
 | 
			
		||||
        {
 | 
			
		||||
            // Given, When
 | 
			
		||||
            var result = Fixture.Run<Settings>();
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.Exception.Message.ShouldBe("Encountered invalid character '$' in value name.");
 | 
			
		||||
            return Verifier.Verify(result.Output);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [UsesVerify]
 | 
			
		||||
    public sealed class MissingLongAndShortName
 | 
			
		||||
    {
 | 
			
		||||
        public sealed class Settings : CommandSettings
 | 
			
		||||
        {
 | 
			
		||||
            [CommandOption("<FOO>")]
 | 
			
		||||
            public string Foo { get; set; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("MissingLongAndShortName")]
 | 
			
		||||
        public Task Should_Return_Correct_Text()
 | 
			
		||||
        {
 | 
			
		||||
            // Given, When
 | 
			
		||||
            var result = Fixture.Run<Settings>();
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.Exception.Message.ShouldBe("No long or short name for option has been specified.");
 | 
			
		||||
            return Verifier.Verify(result.Output);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static class Fixture
 | 
			
		||||
    {
 | 
			
		||||
        public static CommandAppFailure Run<TSettings>(params string[] args)
 | 
			
		||||
            where TSettings : CommandSettings
 | 
			
		||||
        {
 | 
			
		||||
            var app = new CommandAppTester();
 | 
			
		||||
            app.Configure(c =>
 | 
			
		||||
            {
 | 
			
		||||
                c.AddCommand<GenericCommand<TSettings>>("foo");
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            return app.RunAndCatch<CommandTemplateException>(args);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,217 +1,212 @@
 | 
			
		||||
using Shouldly;
 | 
			
		||||
using Spectre.Console.Cli;
 | 
			
		||||
using Xunit;
 | 
			
		||||
namespace Spectre.Console.Tests.Unit.Cli.Annotations;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Unit.Cli.Annotations
 | 
			
		||||
public sealed partial class CommandOptionAttributeTests
 | 
			
		||||
{
 | 
			
		||||
    public sealed partial class CommandOptionAttributeTests
 | 
			
		||||
    [Fact]
 | 
			
		||||
    public void Should_Parse_Short_Name_Correctly()
 | 
			
		||||
    {
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Parse_Short_Name_Correctly()
 | 
			
		||||
        {
 | 
			
		||||
            // Given, When
 | 
			
		||||
            var option = new CommandOptionAttribute("-o|--option <VALUE>");
 | 
			
		||||
        // Given, When
 | 
			
		||||
        var option = new CommandOptionAttribute("-o|--option <VALUE>");
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            option.ShortNames.ShouldContain("o");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Parse_Long_Name_Correctly()
 | 
			
		||||
        {
 | 
			
		||||
            // Given, When
 | 
			
		||||
            var option = new CommandOptionAttribute("-o|--option <VALUE>");
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            option.LongNames.ShouldContain("option");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Theory]
 | 
			
		||||
        [InlineData("<VALUE>")]
 | 
			
		||||
        public void Should_Parse_Value_Correctly(string value)
 | 
			
		||||
        {
 | 
			
		||||
            // Given, When
 | 
			
		||||
            var option = new CommandOptionAttribute($"-o|--option {value}");
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            option.ValueName.ShouldBe("VALUE");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Parse_Only_Short_Name()
 | 
			
		||||
        {
 | 
			
		||||
            // Given, When
 | 
			
		||||
            var option = new CommandOptionAttribute("-o");
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            option.ShortNames.ShouldContain("o");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Parse_Only_Long_Name()
 | 
			
		||||
        {
 | 
			
		||||
            // Given, When
 | 
			
		||||
            var option = new CommandOptionAttribute("--option");
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            option.LongNames.ShouldContain("option");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Theory]
 | 
			
		||||
        [InlineData("")]
 | 
			
		||||
        [InlineData("<VALUE>")]
 | 
			
		||||
        public void Should_Throw_If_Template_Is_Empty(string value)
 | 
			
		||||
        {
 | 
			
		||||
            // Given, When
 | 
			
		||||
            var option = Record.Exception(() => new CommandOptionAttribute(value));
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            option.ShouldBeOfType<CommandTemplateException>().And(e =>
 | 
			
		||||
                e.Message.ShouldBe("No long or short name for option has been specified."));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Theory]
 | 
			
		||||
        [InlineData("--bar|-foo")]
 | 
			
		||||
        [InlineData("--bar|-f-b")]
 | 
			
		||||
        public void Should_Throw_If_Short_Name_Is_Invalid(string value)
 | 
			
		||||
        {
 | 
			
		||||
            // Given, When
 | 
			
		||||
            var option = Record.Exception(() => new CommandOptionAttribute(value));
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            option.ShouldBeOfType<CommandTemplateException>().And(e =>
 | 
			
		||||
                e.Message.ShouldBe("Short option names can not be longer than one character."));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Theory]
 | 
			
		||||
        [InlineData("--o")]
 | 
			
		||||
        public void Should_Throw_If_Long_Name_Is_Invalid(string value)
 | 
			
		||||
        {
 | 
			
		||||
            // Given, When
 | 
			
		||||
            var option = Record.Exception(() => new CommandOptionAttribute(value));
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            option.ShouldBeOfType<CommandTemplateException>().And(e =>
 | 
			
		||||
                e.Message.ShouldBe("Long option names must consist of more than one character."));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Theory]
 | 
			
		||||
        [InlineData("-")]
 | 
			
		||||
        [InlineData("--")]
 | 
			
		||||
        public void Should_Throw_If_Option_Have_No_Name(string template)
 | 
			
		||||
        {
 | 
			
		||||
            // Given, When
 | 
			
		||||
            var option = Record.Exception(() => new CommandOptionAttribute(template));
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            option.ShouldBeOfType<CommandTemplateException>().And(e =>
 | 
			
		||||
                e.Message.ShouldBe("Options without name are not allowed."));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Theory]
 | 
			
		||||
        [InlineData("--foo|-foo[b", '[')]
 | 
			
		||||
        [InlineData("--foo|-f€b", '€')]
 | 
			
		||||
        [InlineData("--foo|-foo@b", '@')]
 | 
			
		||||
        public void Should_Throw_If_Option_Contains_Invalid_Name(string template, char invalid)
 | 
			
		||||
        {
 | 
			
		||||
            // Given, When
 | 
			
		||||
            var result = Record.Exception(() => new CommandOptionAttribute(template));
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ShouldBeOfType<CommandTemplateException>().And(e =>
 | 
			
		||||
            {
 | 
			
		||||
                e.Message.ShouldBe($"Encountered invalid character '{invalid}' in option name.");
 | 
			
		||||
                e.Template.ShouldBe(template);
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Theory]
 | 
			
		||||
        [InlineData("--foo <HELLO-WORLD>", "HELLO-WORLD")]
 | 
			
		||||
        [InlineData("--foo <HELLO_WORLD>", "HELLO_WORLD")]
 | 
			
		||||
        public void Should_Accept_Dash_And_Underscore_In_Value_Name(string template, string name)
 | 
			
		||||
        {
 | 
			
		||||
            // Given, When
 | 
			
		||||
            var result = new CommandOptionAttribute(template);
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ValueName.ShouldBe(name);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Theory]
 | 
			
		||||
        [InlineData("--foo|-1")]
 | 
			
		||||
        public void Should_Throw_If_First_Letter_Of_An_Option_Name_Is_A_Digit(string template)
 | 
			
		||||
        {
 | 
			
		||||
            // Given, When
 | 
			
		||||
            var result = Record.Exception(() => new CommandOptionAttribute(template));
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ShouldBeOfType<CommandTemplateException>().And(e =>
 | 
			
		||||
            {
 | 
			
		||||
                e.Message.ShouldBe("Option names cannot start with a digit.");
 | 
			
		||||
                e.Template.ShouldBe(template);
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Multiple_Short_Options_Are_Supported()
 | 
			
		||||
        {
 | 
			
		||||
            // Given, When
 | 
			
		||||
            var result = new CommandOptionAttribute("-f|-b");
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ShortNames.Count.ShouldBe(2);
 | 
			
		||||
            result.ShortNames.ShouldContain("f");
 | 
			
		||||
            result.ShortNames.ShouldContain("b");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Multiple_Long_Options_Are_Supported()
 | 
			
		||||
        {
 | 
			
		||||
            // Given, When
 | 
			
		||||
            var result = new CommandOptionAttribute("--foo|--bar");
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.LongNames.Count.ShouldBe(2);
 | 
			
		||||
            result.LongNames.ShouldContain("foo");
 | 
			
		||||
            result.LongNames.ShouldContain("bar");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Theory]
 | 
			
		||||
        [InlineData("-f|--foo <BAR>")]
 | 
			
		||||
        [InlineData("--foo|-f <BAR>")]
 | 
			
		||||
        [InlineData("<BAR> --foo|-f")]
 | 
			
		||||
        [InlineData("<BAR> -f|--foo")]
 | 
			
		||||
        [InlineData("-f <BAR> --foo")]
 | 
			
		||||
        [InlineData("--foo <BAR> -f")]
 | 
			
		||||
        public void Template_Parts_Can_Appear_In_Any_Order(string template)
 | 
			
		||||
        {
 | 
			
		||||
            // Given, When
 | 
			
		||||
            var result = new CommandOptionAttribute(template);
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.LongNames.ShouldContain("foo");
 | 
			
		||||
            result.ShortNames.ShouldContain("f");
 | 
			
		||||
            result.ValueName.ShouldBe("BAR");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Is_Not_Hidden_From_Help_By_Default()
 | 
			
		||||
        {
 | 
			
		||||
            // Given, When
 | 
			
		||||
            var result = new CommandOptionAttribute("--foo");
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.IsHidden.ShouldBeFalse();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Can_Indicate_That_It_Must_Be_Hidden_From_Help_Text()
 | 
			
		||||
        {
 | 
			
		||||
            // Given, When
 | 
			
		||||
            var result = new CommandOptionAttribute("--foo") { IsHidden = true };
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.IsHidden.ShouldBeTrue();
 | 
			
		||||
        }
 | 
			
		||||
        // Then
 | 
			
		||||
        option.ShortNames.ShouldContain("o");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    public void Should_Parse_Long_Name_Correctly()
 | 
			
		||||
    {
 | 
			
		||||
        // Given, When
 | 
			
		||||
        var option = new CommandOptionAttribute("-o|--option <VALUE>");
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        option.LongNames.ShouldContain("option");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Theory]
 | 
			
		||||
    [InlineData("<VALUE>")]
 | 
			
		||||
    public void Should_Parse_Value_Correctly(string value)
 | 
			
		||||
    {
 | 
			
		||||
        // Given, When
 | 
			
		||||
        var option = new CommandOptionAttribute($"-o|--option {value}");
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        option.ValueName.ShouldBe("VALUE");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    public void Should_Parse_Only_Short_Name()
 | 
			
		||||
    {
 | 
			
		||||
        // Given, When
 | 
			
		||||
        var option = new CommandOptionAttribute("-o");
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        option.ShortNames.ShouldContain("o");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    public void Should_Parse_Only_Long_Name()
 | 
			
		||||
    {
 | 
			
		||||
        // Given, When
 | 
			
		||||
        var option = new CommandOptionAttribute("--option");
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        option.LongNames.ShouldContain("option");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Theory]
 | 
			
		||||
    [InlineData("")]
 | 
			
		||||
    [InlineData("<VALUE>")]
 | 
			
		||||
    public void Should_Throw_If_Template_Is_Empty(string value)
 | 
			
		||||
    {
 | 
			
		||||
        // Given, When
 | 
			
		||||
        var option = Record.Exception(() => new CommandOptionAttribute(value));
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        option.ShouldBeOfType<CommandTemplateException>().And(e =>
 | 
			
		||||
            e.Message.ShouldBe("No long or short name for option has been specified."));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Theory]
 | 
			
		||||
    [InlineData("--bar|-foo")]
 | 
			
		||||
    [InlineData("--bar|-f-b")]
 | 
			
		||||
    public void Should_Throw_If_Short_Name_Is_Invalid(string value)
 | 
			
		||||
    {
 | 
			
		||||
        // Given, When
 | 
			
		||||
        var option = Record.Exception(() => new CommandOptionAttribute(value));
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        option.ShouldBeOfType<CommandTemplateException>().And(e =>
 | 
			
		||||
            e.Message.ShouldBe("Short option names can not be longer than one character."));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Theory]
 | 
			
		||||
    [InlineData("--o")]
 | 
			
		||||
    public void Should_Throw_If_Long_Name_Is_Invalid(string value)
 | 
			
		||||
    {
 | 
			
		||||
        // Given, When
 | 
			
		||||
        var option = Record.Exception(() => new CommandOptionAttribute(value));
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        option.ShouldBeOfType<CommandTemplateException>().And(e =>
 | 
			
		||||
            e.Message.ShouldBe("Long option names must consist of more than one character."));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Theory]
 | 
			
		||||
    [InlineData("-")]
 | 
			
		||||
    [InlineData("--")]
 | 
			
		||||
    public void Should_Throw_If_Option_Have_No_Name(string template)
 | 
			
		||||
    {
 | 
			
		||||
        // Given, When
 | 
			
		||||
        var option = Record.Exception(() => new CommandOptionAttribute(template));
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        option.ShouldBeOfType<CommandTemplateException>().And(e =>
 | 
			
		||||
            e.Message.ShouldBe("Options without name are not allowed."));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Theory]
 | 
			
		||||
    [InlineData("--foo|-foo[b", '[')]
 | 
			
		||||
    [InlineData("--foo|-f€b", '€')]
 | 
			
		||||
    [InlineData("--foo|-foo@b", '@')]
 | 
			
		||||
    public void Should_Throw_If_Option_Contains_Invalid_Name(string template, char invalid)
 | 
			
		||||
    {
 | 
			
		||||
        // Given, When
 | 
			
		||||
        var result = Record.Exception(() => new CommandOptionAttribute(template));
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        result.ShouldBeOfType<CommandTemplateException>().And(e =>
 | 
			
		||||
        {
 | 
			
		||||
            e.Message.ShouldBe($"Encountered invalid character '{invalid}' in option name.");
 | 
			
		||||
            e.Template.ShouldBe(template);
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Theory]
 | 
			
		||||
    [InlineData("--foo <HELLO-WORLD>", "HELLO-WORLD")]
 | 
			
		||||
    [InlineData("--foo <HELLO_WORLD>", "HELLO_WORLD")]
 | 
			
		||||
    public void Should_Accept_Dash_And_Underscore_In_Value_Name(string template, string name)
 | 
			
		||||
    {
 | 
			
		||||
        // Given, When
 | 
			
		||||
        var result = new CommandOptionAttribute(template);
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        result.ValueName.ShouldBe(name);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Theory]
 | 
			
		||||
    [InlineData("--foo|-1")]
 | 
			
		||||
    public void Should_Throw_If_First_Letter_Of_An_Option_Name_Is_A_Digit(string template)
 | 
			
		||||
    {
 | 
			
		||||
        // Given, When
 | 
			
		||||
        var result = Record.Exception(() => new CommandOptionAttribute(template));
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        result.ShouldBeOfType<CommandTemplateException>().And(e =>
 | 
			
		||||
        {
 | 
			
		||||
            e.Message.ShouldBe("Option names cannot start with a digit.");
 | 
			
		||||
            e.Template.ShouldBe(template);
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    public void Multiple_Short_Options_Are_Supported()
 | 
			
		||||
    {
 | 
			
		||||
        // Given, When
 | 
			
		||||
        var result = new CommandOptionAttribute("-f|-b");
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        result.ShortNames.Count.ShouldBe(2);
 | 
			
		||||
        result.ShortNames.ShouldContain("f");
 | 
			
		||||
        result.ShortNames.ShouldContain("b");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    public void Multiple_Long_Options_Are_Supported()
 | 
			
		||||
    {
 | 
			
		||||
        // Given, When
 | 
			
		||||
        var result = new CommandOptionAttribute("--foo|--bar");
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        result.LongNames.Count.ShouldBe(2);
 | 
			
		||||
        result.LongNames.ShouldContain("foo");
 | 
			
		||||
        result.LongNames.ShouldContain("bar");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Theory]
 | 
			
		||||
    [InlineData("-f|--foo <BAR>")]
 | 
			
		||||
    [InlineData("--foo|-f <BAR>")]
 | 
			
		||||
    [InlineData("<BAR> --foo|-f")]
 | 
			
		||||
    [InlineData("<BAR> -f|--foo")]
 | 
			
		||||
    [InlineData("-f <BAR> --foo")]
 | 
			
		||||
    [InlineData("--foo <BAR> -f")]
 | 
			
		||||
    public void Template_Parts_Can_Appear_In_Any_Order(string template)
 | 
			
		||||
    {
 | 
			
		||||
        // Given, When
 | 
			
		||||
        var result = new CommandOptionAttribute(template);
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        result.LongNames.ShouldContain("foo");
 | 
			
		||||
        result.ShortNames.ShouldContain("f");
 | 
			
		||||
        result.ValueName.ShouldBe("BAR");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    public void Is_Not_Hidden_From_Help_By_Default()
 | 
			
		||||
    {
 | 
			
		||||
        // Given, When
 | 
			
		||||
        var result = new CommandOptionAttribute("--foo");
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        result.IsHidden.ShouldBeFalse();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    public void Can_Indicate_That_It_Must_Be_Hidden_From_Help_Text()
 | 
			
		||||
    {
 | 
			
		||||
        // Given, When
 | 
			
		||||
        var result = new CommandOptionAttribute("--foo") { IsHidden = true };
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        result.IsHidden.ShouldBeTrue();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,110 +1,104 @@
 | 
			
		||||
using Shouldly;
 | 
			
		||||
using Spectre.Console.Cli;
 | 
			
		||||
using Spectre.Console.Testing;
 | 
			
		||||
using Xunit;
 | 
			
		||||
namespace Spectre.Console.Tests.Unit.Cli;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Unit.Cli
 | 
			
		||||
public sealed partial class CommandAppTests
 | 
			
		||||
{
 | 
			
		||||
    public sealed partial class CommandAppTests
 | 
			
		||||
    public class NullableSettings : CommandSettings
 | 
			
		||||
    {
 | 
			
		||||
        public class NullableSettings : CommandSettings
 | 
			
		||||
        public NullableSettings(bool? detailed, string[] extra)
 | 
			
		||||
        {
 | 
			
		||||
            public NullableSettings(bool? detailed, string[] extra)
 | 
			
		||||
            {
 | 
			
		||||
                Detailed = detailed;
 | 
			
		||||
                Extra = extra;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [CommandOption("-d")]
 | 
			
		||||
            public bool? Detailed { get; }
 | 
			
		||||
 | 
			
		||||
            [CommandArgument(0, "[extra]")]
 | 
			
		||||
            public string[] Extra { get; }
 | 
			
		||||
            Detailed = detailed;
 | 
			
		||||
            Extra = extra;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public class NullableWithInitSettings : CommandSettings
 | 
			
		||||
        {
 | 
			
		||||
            [CommandOption("-d")]
 | 
			
		||||
            public bool? Detailed { get; init; }
 | 
			
		||||
        [CommandOption("-d")]
 | 
			
		||||
        public bool? Detailed { get; }
 | 
			
		||||
 | 
			
		||||
            [CommandArgument(0, "[extra]")]
 | 
			
		||||
            public string[] Extra { get; init; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public class NullableCommand : Command<NullableSettings>
 | 
			
		||||
        {
 | 
			
		||||
            public override int Execute(CommandContext context, NullableSettings settings) => 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public class NullableWithInitCommand : Command<NullableWithInitSettings>
 | 
			
		||||
        {
 | 
			
		||||
            public override int Execute(CommandContext context, NullableWithInitSettings settings) => 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Populate_Nullable_Objects_In_Settings()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var fixture = new CommandAppTester();
 | 
			
		||||
            fixture.Configure(configurator =>
 | 
			
		||||
            {
 | 
			
		||||
                configurator.SetApplicationName("myapp");
 | 
			
		||||
                configurator.AddCommand<NullableCommand>("null");
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            var result = fixture.Run("null");
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.Settings.ShouldBeOfType<NullableSettings>().And(settings =>
 | 
			
		||||
            {
 | 
			
		||||
                settings.Detailed.ShouldBeNull();
 | 
			
		||||
                settings.Extra.ShouldBeNull();
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Populate_Nullable_Objects_With_Init_In_Settings()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var fixture = new CommandAppTester();
 | 
			
		||||
            fixture.Configure(configurator =>
 | 
			
		||||
            {
 | 
			
		||||
                configurator.SetApplicationName("myapp");
 | 
			
		||||
                configurator.AddCommand<NullableWithInitCommand>("null");
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            var result = fixture.Run("null");
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.Settings.ShouldBeOfType<NullableWithInitSettings>().And(settings =>
 | 
			
		||||
            {
 | 
			
		||||
                settings.Detailed.ShouldBeNull();
 | 
			
		||||
                settings.Extra.ShouldBeNull();
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Populate_Regular_Settings()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var fixture = new CommandAppTester();
 | 
			
		||||
            fixture.Configure(configurator =>
 | 
			
		||||
            {
 | 
			
		||||
                configurator.SetApplicationName("myapp");
 | 
			
		||||
                configurator.AddCommand<NullableCommand>("null");
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            var result = fixture.Run("null", "-d", "true", "first-item");
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.Settings.ShouldBeOfType<NullableSettings>().And(settings =>
 | 
			
		||||
            {
 | 
			
		||||
                settings.Detailed.ShouldBe(true);
 | 
			
		||||
                settings.Extra.ShouldBe(new[] { "first-item" });
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
        [CommandArgument(0, "[extra]")]
 | 
			
		||||
        public string[] Extra { get; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    public class NullableWithInitSettings : CommandSettings
 | 
			
		||||
    {
 | 
			
		||||
        [CommandOption("-d")]
 | 
			
		||||
        public bool? Detailed { get; init; }
 | 
			
		||||
 | 
			
		||||
        [CommandArgument(0, "[extra]")]
 | 
			
		||||
        public string[] Extra { get; init; }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public class NullableCommand : Command<NullableSettings>
 | 
			
		||||
    {
 | 
			
		||||
        public override int Execute(CommandContext context, NullableSettings settings) => 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public class NullableWithInitCommand : Command<NullableWithInitSettings>
 | 
			
		||||
    {
 | 
			
		||||
        public override int Execute(CommandContext context, NullableWithInitSettings settings) => 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    public void Should_Populate_Nullable_Objects_In_Settings()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var fixture = new CommandAppTester();
 | 
			
		||||
        fixture.Configure(configurator =>
 | 
			
		||||
        {
 | 
			
		||||
            configurator.SetApplicationName("myapp");
 | 
			
		||||
            configurator.AddCommand<NullableCommand>("null");
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        var result = fixture.Run("null");
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        result.Settings.ShouldBeOfType<NullableSettings>().And(settings =>
 | 
			
		||||
        {
 | 
			
		||||
            settings.Detailed.ShouldBeNull();
 | 
			
		||||
            settings.Extra.ShouldBeNull();
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    public void Should_Populate_Nullable_Objects_With_Init_In_Settings()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var fixture = new CommandAppTester();
 | 
			
		||||
        fixture.Configure(configurator =>
 | 
			
		||||
        {
 | 
			
		||||
            configurator.SetApplicationName("myapp");
 | 
			
		||||
            configurator.AddCommand<NullableWithInitCommand>("null");
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        var result = fixture.Run("null");
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        result.Settings.ShouldBeOfType<NullableWithInitSettings>().And(settings =>
 | 
			
		||||
        {
 | 
			
		||||
            settings.Detailed.ShouldBeNull();
 | 
			
		||||
            settings.Extra.ShouldBeNull();
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    public void Should_Populate_Regular_Settings()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var fixture = new CommandAppTester();
 | 
			
		||||
        fixture.Configure(configurator =>
 | 
			
		||||
        {
 | 
			
		||||
            configurator.SetApplicationName("myapp");
 | 
			
		||||
            configurator.AddCommand<NullableCommand>("null");
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        var result = fixture.Run("null", "-d", "true", "first-item");
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        result.Settings.ShouldBeOfType<NullableSettings>().And(settings =>
 | 
			
		||||
        {
 | 
			
		||||
            settings.Detailed.ShouldBe(true);
 | 
			
		||||
            settings.Extra.ShouldBe(new[] { "first-item" });
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,100 +1,92 @@
 | 
			
		||||
using System;
 | 
			
		||||
using Shouldly;
 | 
			
		||||
using Spectre.Console.Cli;
 | 
			
		||||
using Spectre.Console.Testing;
 | 
			
		||||
using Spectre.Console.Tests.Data;
 | 
			
		||||
using Xunit;
 | 
			
		||||
namespace Spectre.Console.Tests.Unit.Cli;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Unit.Cli
 | 
			
		||||
public sealed partial class CommandAppTests
 | 
			
		||||
{
 | 
			
		||||
    public sealed partial class CommandAppTests
 | 
			
		||||
    public sealed class Exception_Handling
 | 
			
		||||
    {
 | 
			
		||||
        public sealed class Exception_Handling
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Not_Propagate_Runtime_Exceptions_If_Not_Explicitly_Told_To_Do_So()
 | 
			
		||||
        {
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Not_Propagate_Runtime_Exceptions_If_Not_Explicitly_Told_To_Do_So()
 | 
			
		||||
            // Given
 | 
			
		||||
            var app = new CommandAppTester();
 | 
			
		||||
            app.Configure(config =>
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var app = new CommandAppTester();
 | 
			
		||||
                app.Configure(config =>
 | 
			
		||||
                config.AddBranch<AnimalSettings>("animal", animal =>
 | 
			
		||||
                {
 | 
			
		||||
                    config.AddBranch<AnimalSettings>("animal", animal =>
 | 
			
		||||
                    {
 | 
			
		||||
                        animal.AddCommand<DogCommand>("dog");
 | 
			
		||||
                        animal.AddCommand<HorseCommand>("horse");
 | 
			
		||||
                    });
 | 
			
		||||
                    animal.AddCommand<DogCommand>("dog");
 | 
			
		||||
                    animal.AddCommand<HorseCommand>("horse");
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = app.Run(new[] { "animal", "4", "dog", "101", "--name", "Rufus" });
 | 
			
		||||
            // When
 | 
			
		||||
            var result = app.Run(new[] { "animal", "4", "dog", "101", "--name", "Rufus" });
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ExitCode.ShouldBe(-1);
 | 
			
		||||
            }
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ExitCode.ShouldBe(-1);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Not_Propagate_Exceptions_If_Not_Explicitly_Told_To_Do_So()
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Not_Propagate_Exceptions_If_Not_Explicitly_Told_To_Do_So()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var app = new CommandAppTester();
 | 
			
		||||
            app.Configure(config =>
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var app = new CommandAppTester();
 | 
			
		||||
                app.Configure(config =>
 | 
			
		||||
                {
 | 
			
		||||
                    config.AddCommand<ThrowingCommand>("throw");
 | 
			
		||||
                });
 | 
			
		||||
                config.AddCommand<ThrowingCommand>("throw");
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = app.Run(new[] { "throw" });
 | 
			
		||||
            // When
 | 
			
		||||
            var result = app.Run(new[] { "throw" });
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ExitCode.ShouldBe(-1);
 | 
			
		||||
            }
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ExitCode.ShouldBe(-1);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Handle_Exceptions_If_ExceptionHandler_Is_Set_Using_Action()
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Handle_Exceptions_If_ExceptionHandler_Is_Set_Using_Action()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var exceptionHandled = false;
 | 
			
		||||
            var app = new CommandAppTester();
 | 
			
		||||
            app.Configure(config =>
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var exceptionHandled = false;
 | 
			
		||||
                var app = new CommandAppTester();
 | 
			
		||||
                app.Configure(config =>
 | 
			
		||||
                config.AddCommand<ThrowingCommand>("throw");
 | 
			
		||||
                config.SetExceptionHandler(_ =>
 | 
			
		||||
                {
 | 
			
		||||
                    config.AddCommand<ThrowingCommand>("throw");
 | 
			
		||||
                    config.SetExceptionHandler(_ =>
 | 
			
		||||
                    {
 | 
			
		||||
                        exceptionHandled = true;
 | 
			
		||||
                    });
 | 
			
		||||
                    exceptionHandled = true;
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = app.Run(new[] { "throw" });
 | 
			
		||||
            // When
 | 
			
		||||
            var result = app.Run(new[] { "throw" });
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ExitCode.ShouldBe(-1);
 | 
			
		||||
                exceptionHandled.ShouldBeTrue();
 | 
			
		||||
            }
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ExitCode.ShouldBe(-1);
 | 
			
		||||
            exceptionHandled.ShouldBeTrue();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Handle_Exceptions_If_ExceptionHandler_Is_Set_Using_Function()
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Handle_Exceptions_If_ExceptionHandler_Is_Set_Using_Function()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var exceptionHandled = false;
 | 
			
		||||
            var app = new CommandAppTester();
 | 
			
		||||
            app.Configure(config =>
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var exceptionHandled = false;
 | 
			
		||||
                var app = new CommandAppTester();
 | 
			
		||||
                app.Configure(config =>
 | 
			
		||||
                config.AddCommand<ThrowingCommand>("throw");
 | 
			
		||||
                config.SetExceptionHandler(_ =>
 | 
			
		||||
                {
 | 
			
		||||
                    config.AddCommand<ThrowingCommand>("throw");
 | 
			
		||||
                    config.SetExceptionHandler(_ =>
 | 
			
		||||
                    {
 | 
			
		||||
                        exceptionHandled = true;
 | 
			
		||||
                        return -99;
 | 
			
		||||
                    });
 | 
			
		||||
                    exceptionHandled = true;
 | 
			
		||||
                    return -99;
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = app.Run(new[] { "throw" });
 | 
			
		||||
            // When
 | 
			
		||||
            var result = app.Run(new[] { "throw" });
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ExitCode.ShouldBe(-99);
 | 
			
		||||
                exceptionHandled.ShouldBeTrue();
 | 
			
		||||
            }
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ExitCode.ShouldBe(-99);
 | 
			
		||||
            exceptionHandled.ShouldBeTrue();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,223 +1,214 @@
 | 
			
		||||
using System.ComponentModel;
 | 
			
		||||
using System.Diagnostics.CodeAnalysis;
 | 
			
		||||
using Shouldly;
 | 
			
		||||
using Spectre.Console.Cli;
 | 
			
		||||
using Spectre.Console.Testing;
 | 
			
		||||
using Spectre.Console.Tests.Data;
 | 
			
		||||
using Xunit;
 | 
			
		||||
namespace Spectre.Console.Tests.Unit.Cli;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Unit.Cli
 | 
			
		||||
public sealed partial class CommandAppTests
 | 
			
		||||
{
 | 
			
		||||
    public sealed partial class CommandAppTests
 | 
			
		||||
    public sealed class FlagValues
 | 
			
		||||
    {
 | 
			
		||||
        public sealed class FlagValues
 | 
			
		||||
        [SuppressMessage("Performance", "CA1812", Justification = "It's OK")]
 | 
			
		||||
        private sealed class FlagSettings : CommandSettings
 | 
			
		||||
        {
 | 
			
		||||
            [SuppressMessage("Performance", "CA1812", Justification = "It's OK")]
 | 
			
		||||
            private sealed class FlagSettings : CommandSettings
 | 
			
		||||
            [CommandOption("--serve [PORT]")]
 | 
			
		||||
            public FlagValue<int> Serve { get; set; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [SuppressMessage("Performance", "CA1812", Justification = "It's OK")]
 | 
			
		||||
        private sealed class FlagSettingsWithNullableValueType : CommandSettings
 | 
			
		||||
        {
 | 
			
		||||
            [CommandOption("--serve [PORT]")]
 | 
			
		||||
            public FlagValue<int?> Serve { get; set; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [SuppressMessage("Performance", "CA1812", Justification = "It's OK")]
 | 
			
		||||
        private sealed class FlagSettingsWithOptionalOptionButNoFlagValue : CommandSettings
 | 
			
		||||
        {
 | 
			
		||||
            [CommandOption("--serve [PORT]")]
 | 
			
		||||
            public int Serve { get; set; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [SuppressMessage("Performance", "CA1812", Justification = "It's OK")]
 | 
			
		||||
        private sealed class FlagSettingsWithDefaultValue : CommandSettings
 | 
			
		||||
        {
 | 
			
		||||
            [CommandOption("--serve [PORT]")]
 | 
			
		||||
            [DefaultValue(987)]
 | 
			
		||||
            public FlagValue<int> Serve { get; set; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Throw_If_Command_Option_Value_Is_Optional_But_Type_Is_Not_A_Flag_Value()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var app = new CommandApp();
 | 
			
		||||
            app.Configure(config =>
 | 
			
		||||
            {
 | 
			
		||||
                [CommandOption("--serve [PORT]")]
 | 
			
		||||
                public FlagValue<int> Serve { get; set; }
 | 
			
		||||
            }
 | 
			
		||||
                config.PropagateExceptions();
 | 
			
		||||
                config.AddCommand<GenericCommand<FlagSettingsWithOptionalOptionButNoFlagValue>>("foo");
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            [SuppressMessage("Performance", "CA1812", Justification = "It's OK")]
 | 
			
		||||
            private sealed class FlagSettingsWithNullableValueType : CommandSettings
 | 
			
		||||
            // When
 | 
			
		||||
            var result = Record.Exception(() => app.Run(new[] { "foo", "--serve", "123" }));
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ShouldBeOfType<CommandConfigurationException>().And(ex =>
 | 
			
		||||
            {
 | 
			
		||||
                [CommandOption("--serve [PORT]")]
 | 
			
		||||
                public FlagValue<int?> Serve { get; set; }
 | 
			
		||||
            }
 | 
			
		||||
                ex.Message.ShouldBe("The option 'serve' has an optional value but does not implement IFlagValue.");
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
            [SuppressMessage("Performance", "CA1812", Justification = "It's OK")]
 | 
			
		||||
            private sealed class FlagSettingsWithOptionalOptionButNoFlagValue : CommandSettings
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Set_Flag_And_Value_If_Both_Were_Provided()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var app = new CommandAppTester();
 | 
			
		||||
            app.Configure(config =>
 | 
			
		||||
            {
 | 
			
		||||
                [CommandOption("--serve [PORT]")]
 | 
			
		||||
                public int Serve { get; set; }
 | 
			
		||||
            }
 | 
			
		||||
                config.PropagateExceptions();
 | 
			
		||||
                config.AddCommand<GenericCommand<FlagSettings>>("foo");
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            [SuppressMessage("Performance", "CA1812", Justification = "It's OK")]
 | 
			
		||||
            private sealed class FlagSettingsWithDefaultValue : CommandSettings
 | 
			
		||||
            // When
 | 
			
		||||
            var result = app.Run(new[] { "foo", "--serve", "123", });
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ExitCode.ShouldBe(0);
 | 
			
		||||
            result.Settings.ShouldBeOfType<FlagSettings>().And(flag =>
 | 
			
		||||
            {
 | 
			
		||||
                [CommandOption("--serve [PORT]")]
 | 
			
		||||
                [DefaultValue(987)]
 | 
			
		||||
                public FlagValue<int> Serve { get; set; }
 | 
			
		||||
            }
 | 
			
		||||
                flag.Serve.IsSet.ShouldBeTrue();
 | 
			
		||||
                flag.Serve.Value.ShouldBe(123);
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Throw_If_Command_Option_Value_Is_Optional_But_Type_Is_Not_A_Flag_Value()
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Only_Set_Flag_If_No_Value_Was_Provided()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var app = new CommandAppTester();
 | 
			
		||||
            app.Configure(config =>
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var app = new CommandApp();
 | 
			
		||||
                app.Configure(config =>
 | 
			
		||||
                {
 | 
			
		||||
                    config.PropagateExceptions();
 | 
			
		||||
                    config.AddCommand<GenericCommand<FlagSettingsWithOptionalOptionButNoFlagValue>>("foo");
 | 
			
		||||
                });
 | 
			
		||||
                config.PropagateExceptions();
 | 
			
		||||
                config.AddCommand<GenericCommand<FlagSettings>>("foo");
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = Record.Exception(() => app.Run(new[] { "foo", "--serve", "123" }));
 | 
			
		||||
            // When
 | 
			
		||||
            var result = app.Run(new[] { "foo", "--serve" });
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ShouldBeOfType<CommandConfigurationException>().And(ex =>
 | 
			
		||||
                {
 | 
			
		||||
                    ex.Message.ShouldBe("The option 'serve' has an optional value but does not implement IFlagValue.");
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Set_Flag_And_Value_If_Both_Were_Provided()
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ExitCode.ShouldBe(0);
 | 
			
		||||
            result.Settings.ShouldBeOfType<FlagSettings>().And(flag =>
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var app = new CommandAppTester();
 | 
			
		||||
                app.Configure(config =>
 | 
			
		||||
                {
 | 
			
		||||
                    config.PropagateExceptions();
 | 
			
		||||
                    config.AddCommand<GenericCommand<FlagSettings>>("foo");
 | 
			
		||||
                });
 | 
			
		||||
                flag.Serve.IsSet.ShouldBeTrue();
 | 
			
		||||
                flag.Serve.Value.ShouldBe(0);
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = app.Run(new[] { "foo", "--serve", "123", });
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ExitCode.ShouldBe(0);
 | 
			
		||||
                result.Settings.ShouldBeOfType<FlagSettings>().And(flag =>
 | 
			
		||||
                {
 | 
			
		||||
                    flag.Serve.IsSet.ShouldBeTrue();
 | 
			
		||||
                    flag.Serve.Value.ShouldBe(123);
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Only_Set_Flag_If_No_Value_Was_Provided()
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Set_Value_To_Default_Value_If_None_Was_Explicitly_Set()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var app = new CommandAppTester();
 | 
			
		||||
            app.Configure(config =>
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var app = new CommandAppTester();
 | 
			
		||||
                app.Configure(config =>
 | 
			
		||||
                {
 | 
			
		||||
                    config.PropagateExceptions();
 | 
			
		||||
                    config.AddCommand<GenericCommand<FlagSettings>>("foo");
 | 
			
		||||
                });
 | 
			
		||||
                config.PropagateExceptions();
 | 
			
		||||
                config.AddCommand<GenericCommand<FlagSettingsWithDefaultValue>>("foo");
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = app.Run(new[] { "foo", "--serve" });
 | 
			
		||||
            // When
 | 
			
		||||
            var result = app.Run(new[] { "foo", "--serve" });
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ExitCode.ShouldBe(0);
 | 
			
		||||
                result.Settings.ShouldBeOfType<FlagSettings>().And(flag =>
 | 
			
		||||
                {
 | 
			
		||||
                    flag.Serve.IsSet.ShouldBeTrue();
 | 
			
		||||
                    flag.Serve.Value.ShouldBe(0);
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Set_Value_To_Default_Value_If_None_Was_Explicitly_Set()
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ExitCode.ShouldBe(0);
 | 
			
		||||
            result.Settings.ShouldBeOfType<FlagSettingsWithDefaultValue>().And(flag =>
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var app = new CommandAppTester();
 | 
			
		||||
                app.Configure(config =>
 | 
			
		||||
                {
 | 
			
		||||
                    config.PropagateExceptions();
 | 
			
		||||
                    config.AddCommand<GenericCommand<FlagSettingsWithDefaultValue>>("foo");
 | 
			
		||||
                });
 | 
			
		||||
                flag.Serve.IsSet.ShouldBeTrue();
 | 
			
		||||
                flag.Serve.Value.ShouldBe(987);
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = app.Run(new[] { "foo", "--serve" });
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ExitCode.ShouldBe(0);
 | 
			
		||||
                result.Settings.ShouldBeOfType<FlagSettingsWithDefaultValue>().And(flag =>
 | 
			
		||||
                {
 | 
			
		||||
                    flag.Serve.IsSet.ShouldBeTrue();
 | 
			
		||||
                    flag.Serve.Value.ShouldBe(987);
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Create_Unset_Instance_If_Flag_Was_Not_Set()
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Create_Unset_Instance_If_Flag_Was_Not_Set()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var app = new CommandAppTester();
 | 
			
		||||
            app.Configure(config =>
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var app = new CommandAppTester();
 | 
			
		||||
                app.Configure(config =>
 | 
			
		||||
                {
 | 
			
		||||
                    config.PropagateExceptions();
 | 
			
		||||
                    config.AddCommand<GenericCommand<FlagSettings>>("foo");
 | 
			
		||||
                });
 | 
			
		||||
                config.PropagateExceptions();
 | 
			
		||||
                config.AddCommand<GenericCommand<FlagSettings>>("foo");
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = app.Run(new[] { "foo" });
 | 
			
		||||
            // When
 | 
			
		||||
            var result = app.Run(new[] { "foo" });
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ExitCode.ShouldBe(0);
 | 
			
		||||
                result.Settings.ShouldBeOfType<FlagSettings>().And(flag =>
 | 
			
		||||
                {
 | 
			
		||||
                    flag.Serve.IsSet.ShouldBeFalse();
 | 
			
		||||
                    flag.Serve.Value.ShouldBe(0);
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Create_Unset_Instance_With_Null_For_Nullable_Value_Type_If_Flag_Was_Not_Set()
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ExitCode.ShouldBe(0);
 | 
			
		||||
            result.Settings.ShouldBeOfType<FlagSettings>().And(flag =>
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var app = new CommandAppTester();
 | 
			
		||||
                app.Configure(config =>
 | 
			
		||||
                {
 | 
			
		||||
                    config.PropagateExceptions();
 | 
			
		||||
                    config.AddCommand<GenericCommand<FlagSettingsWithNullableValueType>>("foo");
 | 
			
		||||
                });
 | 
			
		||||
                flag.Serve.IsSet.ShouldBeFalse();
 | 
			
		||||
                flag.Serve.Value.ShouldBe(0);
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = app.Run(new[] { "foo" });
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ExitCode.ShouldBe(0);
 | 
			
		||||
                result.Settings.ShouldBeOfType<FlagSettingsWithNullableValueType>().And(flag =>
 | 
			
		||||
                {
 | 
			
		||||
                    flag.Serve.IsSet.ShouldBeFalse();
 | 
			
		||||
                    flag.Serve.Value.ShouldBeNull();
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Theory]
 | 
			
		||||
            [InlineData("Foo", true, "Set=True, Value=Foo")]
 | 
			
		||||
            [InlineData("Bar", false, "Set=False, Value=Bar")]
 | 
			
		||||
            public void Should_Return_Correct_String_Representation_From_ToString(
 | 
			
		||||
                string value,
 | 
			
		||||
                bool isSet,
 | 
			
		||||
                string expected)
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Create_Unset_Instance_With_Null_For_Nullable_Value_Type_If_Flag_Was_Not_Set()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var app = new CommandAppTester();
 | 
			
		||||
            app.Configure(config =>
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var flag = new FlagValue<string>
 | 
			
		||||
                {
 | 
			
		||||
                    Value = value,
 | 
			
		||||
                    IsSet = isSet,
 | 
			
		||||
                };
 | 
			
		||||
                config.PropagateExceptions();
 | 
			
		||||
                config.AddCommand<GenericCommand<FlagSettingsWithNullableValueType>>("foo");
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = flag.ToString();
 | 
			
		||||
            // When
 | 
			
		||||
            var result = app.Run(new[] { "foo" });
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ShouldBe(expected);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Theory]
 | 
			
		||||
            [InlineData(true, "Set=True")]
 | 
			
		||||
            [InlineData(false, "Set=False")]
 | 
			
		||||
            public void Should_Return_Correct_String_Representation_From_ToString_If_Value_Is_Not_Set(
 | 
			
		||||
                bool isSet,
 | 
			
		||||
                string expected)
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ExitCode.ShouldBe(0);
 | 
			
		||||
            result.Settings.ShouldBeOfType<FlagSettingsWithNullableValueType>().And(flag =>
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var flag = new FlagValue<string>
 | 
			
		||||
                {
 | 
			
		||||
                    IsSet = isSet,
 | 
			
		||||
                };
 | 
			
		||||
                flag.Serve.IsSet.ShouldBeFalse();
 | 
			
		||||
                flag.Serve.Value.ShouldBeNull();
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = flag.ToString();
 | 
			
		||||
        [Theory]
 | 
			
		||||
        [InlineData("Foo", true, "Set=True, Value=Foo")]
 | 
			
		||||
        [InlineData("Bar", false, "Set=False, Value=Bar")]
 | 
			
		||||
        public void Should_Return_Correct_String_Representation_From_ToString(
 | 
			
		||||
            string value,
 | 
			
		||||
            bool isSet,
 | 
			
		||||
            string expected)
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var flag = new FlagValue<string>
 | 
			
		||||
            {
 | 
			
		||||
                Value = value,
 | 
			
		||||
                IsSet = isSet,
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ShouldBe(expected);
 | 
			
		||||
            }
 | 
			
		||||
            // When
 | 
			
		||||
            var result = flag.ToString();
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ShouldBe(expected);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Theory]
 | 
			
		||||
        [InlineData(true, "Set=True")]
 | 
			
		||||
        [InlineData(false, "Set=False")]
 | 
			
		||||
        public void Should_Return_Correct_String_Representation_From_ToString_If_Value_Is_Not_Set(
 | 
			
		||||
            bool isSet,
 | 
			
		||||
            string expected)
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var flag = new FlagValue<string>
 | 
			
		||||
            {
 | 
			
		||||
                IsSet = isSet,
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            var result = flag.ToString();
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ShouldBe(expected);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,302 +1,293 @@
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Spectre.Console.Cli;
 | 
			
		||||
using Spectre.Console.Testing;
 | 
			
		||||
using Spectre.Console.Tests.Data;
 | 
			
		||||
using Spectre.Verify.Extensions;
 | 
			
		||||
using VerifyXunit;
 | 
			
		||||
using Xunit;
 | 
			
		||||
namespace Spectre.Console.Tests.Unit.Cli;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Unit.Cli
 | 
			
		||||
public sealed partial class CommandAppTests
 | 
			
		||||
{
 | 
			
		||||
    public sealed partial class CommandAppTests
 | 
			
		||||
    [UsesVerify]
 | 
			
		||||
    [ExpectationPath("Cli/Help")]
 | 
			
		||||
    public class Help
 | 
			
		||||
    {
 | 
			
		||||
        [UsesVerify]
 | 
			
		||||
        [ExpectationPath("Cli/Help")]
 | 
			
		||||
        public class Help
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Root")]
 | 
			
		||||
        public Task Should_Output_Root_Correctly()
 | 
			
		||||
        {
 | 
			
		||||
            [Fact]
 | 
			
		||||
            [Expectation("Root")]
 | 
			
		||||
            public Task Should_Output_Root_Correctly()
 | 
			
		||||
            // Given
 | 
			
		||||
            var fixture = new CommandAppTester();
 | 
			
		||||
            fixture.Configure(configurator =>
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var fixture = new CommandAppTester();
 | 
			
		||||
                fixture.Configure(configurator =>
 | 
			
		||||
                {
 | 
			
		||||
                    configurator.SetApplicationName("myapp");
 | 
			
		||||
                    configurator.AddCommand<DogCommand>("dog");
 | 
			
		||||
                    configurator.AddCommand<HorseCommand>("horse");
 | 
			
		||||
                    configurator.AddCommand<GiraffeCommand>("giraffe");
 | 
			
		||||
                });
 | 
			
		||||
                configurator.SetApplicationName("myapp");
 | 
			
		||||
                configurator.AddCommand<DogCommand>("dog");
 | 
			
		||||
                configurator.AddCommand<HorseCommand>("horse");
 | 
			
		||||
                configurator.AddCommand<GiraffeCommand>("giraffe");
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = fixture.Run("--help");
 | 
			
		||||
            // When
 | 
			
		||||
            var result = fixture.Run("--help");
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                return Verifier.Verify(result.Output);
 | 
			
		||||
            }
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(result.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            [Expectation("Hidden_Commands")]
 | 
			
		||||
            public Task Should_Skip_Hidden_Commands()
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Hidden_Commands")]
 | 
			
		||||
        public Task Should_Skip_Hidden_Commands()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var fixture = new CommandAppTester();
 | 
			
		||||
            fixture.Configure(configurator =>
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var fixture = new CommandAppTester();
 | 
			
		||||
                fixture.Configure(configurator =>
 | 
			
		||||
                {
 | 
			
		||||
                    configurator.SetApplicationName("myapp");
 | 
			
		||||
                    configurator.AddCommand<DogCommand>("dog");
 | 
			
		||||
                    configurator.AddCommand<HorseCommand>("horse");
 | 
			
		||||
                    configurator.AddCommand<GiraffeCommand>("giraffe")
 | 
			
		||||
                        .WithExample(new[] { "giraffe", "123" })
 | 
			
		||||
                        .IsHidden();
 | 
			
		||||
                });
 | 
			
		||||
                configurator.SetApplicationName("myapp");
 | 
			
		||||
                configurator.AddCommand<DogCommand>("dog");
 | 
			
		||||
                configurator.AddCommand<HorseCommand>("horse");
 | 
			
		||||
                configurator.AddCommand<GiraffeCommand>("giraffe")
 | 
			
		||||
                    .WithExample(new[] { "giraffe", "123" })
 | 
			
		||||
                    .IsHidden();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = fixture.Run("--help");
 | 
			
		||||
            // When
 | 
			
		||||
            var result = fixture.Run("--help");
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                return Verifier.Verify(result.Output);
 | 
			
		||||
            }
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(result.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            [Expectation("Command")]
 | 
			
		||||
            public Task Should_Output_Command_Correctly()
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Command")]
 | 
			
		||||
        public Task Should_Output_Command_Correctly()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var fixture = new CommandAppTester();
 | 
			
		||||
            fixture.Configure(configurator =>
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var fixture = new CommandAppTester();
 | 
			
		||||
                fixture.Configure(configurator =>
 | 
			
		||||
                configurator.SetApplicationName("myapp");
 | 
			
		||||
                configurator.AddBranch<CatSettings>("cat", animal =>
 | 
			
		||||
                {
 | 
			
		||||
                    configurator.SetApplicationName("myapp");
 | 
			
		||||
                    configurator.AddBranch<CatSettings>("cat", animal =>
 | 
			
		||||
                    {
 | 
			
		||||
                        animal.SetDescription("Contains settings for a cat.");
 | 
			
		||||
                        animal.AddCommand<LionCommand>("lion");
 | 
			
		||||
                    });
 | 
			
		||||
                    animal.SetDescription("Contains settings for a cat.");
 | 
			
		||||
                    animal.AddCommand<LionCommand>("lion");
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = fixture.Run("cat", "--help");
 | 
			
		||||
            // When
 | 
			
		||||
            var result = fixture.Run("cat", "--help");
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                return Verifier.Verify(result.Output);
 | 
			
		||||
            }
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(result.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            [Expectation("Leaf")]
 | 
			
		||||
            public Task Should_Output_Leaf_Correctly()
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Leaf")]
 | 
			
		||||
        public Task Should_Output_Leaf_Correctly()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var fixture = new CommandAppTester();
 | 
			
		||||
            fixture.Configure(configurator =>
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var fixture = new CommandAppTester();
 | 
			
		||||
                fixture.Configure(configurator =>
 | 
			
		||||
                configurator.SetApplicationName("myapp");
 | 
			
		||||
                configurator.AddBranch<CatSettings>("cat", animal =>
 | 
			
		||||
                {
 | 
			
		||||
                    configurator.SetApplicationName("myapp");
 | 
			
		||||
                    configurator.AddBranch<CatSettings>("cat", animal =>
 | 
			
		||||
                    {
 | 
			
		||||
                        animal.SetDescription("Contains settings for a cat.");
 | 
			
		||||
                        animal.AddCommand<LionCommand>("lion");
 | 
			
		||||
                    });
 | 
			
		||||
                    animal.SetDescription("Contains settings for a cat.");
 | 
			
		||||
                    animal.AddCommand<LionCommand>("lion");
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = fixture.Run("cat", "lion", "--help");
 | 
			
		||||
            // When
 | 
			
		||||
            var result = fixture.Run("cat", "lion", "--help");
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                return Verifier.Verify(result.Output);
 | 
			
		||||
            }
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(result.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            [Expectation("Default")]
 | 
			
		||||
            public Task Should_Output_Default_Command_Correctly()
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Default")]
 | 
			
		||||
        public Task Should_Output_Default_Command_Correctly()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var fixture = new CommandAppTester();
 | 
			
		||||
            fixture.SetDefaultCommand<LionCommand>();
 | 
			
		||||
            fixture.Configure(configurator =>
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var fixture = new CommandAppTester();
 | 
			
		||||
                fixture.SetDefaultCommand<LionCommand>();
 | 
			
		||||
                fixture.Configure(configurator =>
 | 
			
		||||
                {
 | 
			
		||||
                    configurator.SetApplicationName("myapp");
 | 
			
		||||
                });
 | 
			
		||||
                configurator.SetApplicationName("myapp");
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = fixture.Run("--help");
 | 
			
		||||
            // When
 | 
			
		||||
            var result = fixture.Run("--help");
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                return Verifier.Verify(result.Output);
 | 
			
		||||
            }
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(result.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            [Expectation("RootExamples")]
 | 
			
		||||
            public Task Should_Output_Root_Examples_Defined_On_Root()
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("RootExamples")]
 | 
			
		||||
        public Task Should_Output_Root_Examples_Defined_On_Root()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var fixture = new CommandAppTester();
 | 
			
		||||
            fixture.Configure(configurator =>
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var fixture = new CommandAppTester();
 | 
			
		||||
                fixture.Configure(configurator =>
 | 
			
		||||
                {
 | 
			
		||||
                    configurator.SetApplicationName("myapp");
 | 
			
		||||
                    configurator.AddExample(new[] { "dog", "--name", "Rufus", "--age", "12", "--good-boy" });
 | 
			
		||||
                    configurator.AddExample(new[] { "horse", "--name", "Brutus" });
 | 
			
		||||
                    configurator.AddCommand<DogCommand>("dog");
 | 
			
		||||
                    configurator.AddCommand<HorseCommand>("horse");
 | 
			
		||||
                });
 | 
			
		||||
                configurator.SetApplicationName("myapp");
 | 
			
		||||
                configurator.AddExample(new[] { "dog", "--name", "Rufus", "--age", "12", "--good-boy" });
 | 
			
		||||
                configurator.AddExample(new[] { "horse", "--name", "Brutus" });
 | 
			
		||||
                configurator.AddCommand<DogCommand>("dog");
 | 
			
		||||
                configurator.AddCommand<HorseCommand>("horse");
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = fixture.Run("--help");
 | 
			
		||||
            // When
 | 
			
		||||
            var result = fixture.Run("--help");
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                return Verifier.Verify(result.Output);
 | 
			
		||||
            }
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(result.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            [Expectation("RootExamples_Children")]
 | 
			
		||||
            public Task Should_Output_Root_Examples_Defined_On_Direct_Children_If_Root_Have_No_Examples()
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("RootExamples_Children")]
 | 
			
		||||
        public Task Should_Output_Root_Examples_Defined_On_Direct_Children_If_Root_Have_No_Examples()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var fixture = new CommandAppTester();
 | 
			
		||||
            fixture.Configure(configurator =>
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var fixture = new CommandAppTester();
 | 
			
		||||
                fixture.Configure(configurator =>
 | 
			
		||||
                {
 | 
			
		||||
                    configurator.SetApplicationName("myapp");
 | 
			
		||||
                    configurator.AddCommand<DogCommand>("dog")
 | 
			
		||||
                        .WithExample(new[] { "dog", "--name", "Rufus", "--age", "12", "--good-boy" });
 | 
			
		||||
                    configurator.AddCommand<HorseCommand>("horse")
 | 
			
		||||
                        .WithExample(new[] { "horse", "--name", "Brutus" });
 | 
			
		||||
                });
 | 
			
		||||
                configurator.SetApplicationName("myapp");
 | 
			
		||||
                configurator.AddCommand<DogCommand>("dog")
 | 
			
		||||
                    .WithExample(new[] { "dog", "--name", "Rufus", "--age", "12", "--good-boy" });
 | 
			
		||||
                configurator.AddCommand<HorseCommand>("horse")
 | 
			
		||||
                    .WithExample(new[] { "horse", "--name", "Brutus" });
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = fixture.Run("--help");
 | 
			
		||||
            // When
 | 
			
		||||
            var result = fixture.Run("--help");
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                return Verifier.Verify(result.Output);
 | 
			
		||||
            }
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(result.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            [Expectation("RootExamples_Leafs")]
 | 
			
		||||
            public Task Should_Output_Root_Examples_Defined_On_Leaves_If_No_Other_Examples_Are_Found()
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("RootExamples_Leafs")]
 | 
			
		||||
        public Task Should_Output_Root_Examples_Defined_On_Leaves_If_No_Other_Examples_Are_Found()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var fixture = new CommandAppTester();
 | 
			
		||||
            fixture.Configure(configurator =>
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var fixture = new CommandAppTester();
 | 
			
		||||
                fixture.Configure(configurator =>
 | 
			
		||||
                configurator.SetApplicationName("myapp");
 | 
			
		||||
                configurator.AddBranch<AnimalSettings>("animal", animal =>
 | 
			
		||||
                {
 | 
			
		||||
                    configurator.SetApplicationName("myapp");
 | 
			
		||||
                    configurator.AddBranch<AnimalSettings>("animal", animal =>
 | 
			
		||||
                    {
 | 
			
		||||
                        animal.SetDescription("The animal command.");
 | 
			
		||||
                        animal.AddCommand<DogCommand>("dog")
 | 
			
		||||
                            .WithExample(new[] { "animal", "dog", "--name", "Rufus", "--age", "12", "--good-boy" });
 | 
			
		||||
                        animal.AddCommand<HorseCommand>("horse")
 | 
			
		||||
                            .WithExample(new[] { "animal", "horse", "--name", "Brutus" });
 | 
			
		||||
                    });
 | 
			
		||||
                    animal.SetDescription("The animal command.");
 | 
			
		||||
                    animal.AddCommand<DogCommand>("dog")
 | 
			
		||||
                        .WithExample(new[] { "animal", "dog", "--name", "Rufus", "--age", "12", "--good-boy" });
 | 
			
		||||
                    animal.AddCommand<HorseCommand>("horse")
 | 
			
		||||
                        .WithExample(new[] { "animal", "horse", "--name", "Brutus" });
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = fixture.Run("--help");
 | 
			
		||||
            // When
 | 
			
		||||
            var result = fixture.Run("--help");
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                return Verifier.Verify(result.Output);
 | 
			
		||||
            }
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(result.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            [Expectation("CommandExamples")]
 | 
			
		||||
            public Task Should_Only_Output_Command_Examples_Defined_On_Command()
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("CommandExamples")]
 | 
			
		||||
        public Task Should_Only_Output_Command_Examples_Defined_On_Command()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var fixture = new CommandAppTester();
 | 
			
		||||
            fixture.Configure(configurator =>
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var fixture = new CommandAppTester();
 | 
			
		||||
                fixture.Configure(configurator =>
 | 
			
		||||
                configurator.SetApplicationName("myapp");
 | 
			
		||||
                configurator.AddBranch<AnimalSettings>("animal", animal =>
 | 
			
		||||
                {
 | 
			
		||||
                    configurator.SetApplicationName("myapp");
 | 
			
		||||
                    configurator.AddBranch<AnimalSettings>("animal", animal =>
 | 
			
		||||
                    {
 | 
			
		||||
                        animal.SetDescription("The animal command.");
 | 
			
		||||
                        animal.AddExample(new[] { "animal", "--help" });
 | 
			
		||||
                    animal.SetDescription("The animal command.");
 | 
			
		||||
                    animal.AddExample(new[] { "animal", "--help" });
 | 
			
		||||
 | 
			
		||||
                        animal.AddCommand<DogCommand>("dog")
 | 
			
		||||
                            .WithExample(new[] { "animal", "dog", "--name", "Rufus", "--age", "12", "--good-boy" });
 | 
			
		||||
                        animal.AddCommand<HorseCommand>("horse")
 | 
			
		||||
                            .WithExample(new[] { "animal", "horse", "--name", "Brutus" });
 | 
			
		||||
                    });
 | 
			
		||||
                    animal.AddCommand<DogCommand>("dog")
 | 
			
		||||
                        .WithExample(new[] { "animal", "dog", "--name", "Rufus", "--age", "12", "--good-boy" });
 | 
			
		||||
                    animal.AddCommand<HorseCommand>("horse")
 | 
			
		||||
                        .WithExample(new[] { "animal", "horse", "--name", "Brutus" });
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = fixture.Run("animal", "--help");
 | 
			
		||||
            // When
 | 
			
		||||
            var result = fixture.Run("animal", "--help");
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                return Verifier.Verify(result.Output);
 | 
			
		||||
            }
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(result.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            [Expectation("DefaultExamples")]
 | 
			
		||||
            public Task Should_Output_Root_Examples_If_Default_Command_Is_Specified()
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("DefaultExamples")]
 | 
			
		||||
        public Task Should_Output_Root_Examples_If_Default_Command_Is_Specified()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var fixture = new CommandAppTester();
 | 
			
		||||
            fixture.SetDefaultCommand<LionCommand>();
 | 
			
		||||
            fixture.Configure(configurator =>
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var fixture = new CommandAppTester();
 | 
			
		||||
                fixture.SetDefaultCommand<LionCommand>();
 | 
			
		||||
                fixture.Configure(configurator =>
 | 
			
		||||
                {
 | 
			
		||||
                    configurator.SetApplicationName("myapp");
 | 
			
		||||
                    configurator.AddExample(new[] { "12", "-c", "3" });
 | 
			
		||||
                });
 | 
			
		||||
                configurator.SetApplicationName("myapp");
 | 
			
		||||
                configurator.AddExample(new[] { "12", "-c", "3" });
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = fixture.Run("--help");
 | 
			
		||||
            // When
 | 
			
		||||
            var result = fixture.Run("--help");
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                return Verifier.Verify(result.Output);
 | 
			
		||||
            }
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(result.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            [Expectation("NoDescription")]
 | 
			
		||||
            public Task Should_Not_Show_Truncated_Command_Table_If_Commands_Are_Missing_Description()
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("NoDescription")]
 | 
			
		||||
        public Task Should_Not_Show_Truncated_Command_Table_If_Commands_Are_Missing_Description()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var fixture = new CommandAppTester();
 | 
			
		||||
            fixture.Configure(configurator =>
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var fixture = new CommandAppTester();
 | 
			
		||||
                fixture.Configure(configurator =>
 | 
			
		||||
                {
 | 
			
		||||
                    configurator.SetApplicationName("myapp");
 | 
			
		||||
                    configurator.AddCommand<NoDescriptionCommand>("bar");
 | 
			
		||||
                });
 | 
			
		||||
                configurator.SetApplicationName("myapp");
 | 
			
		||||
                configurator.AddCommand<NoDescriptionCommand>("bar");
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = fixture.Run("--help");
 | 
			
		||||
            // When
 | 
			
		||||
            var result = fixture.Run("--help");
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                return Verifier.Verify(result.Output);
 | 
			
		||||
            }
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(result.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            [Expectation("ArgumentOrder")]
 | 
			
		||||
            public Task Should_List_Arguments_In_Correct_Order()
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("ArgumentOrder")]
 | 
			
		||||
        public Task Should_List_Arguments_In_Correct_Order()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var fixture = new CommandAppTester();
 | 
			
		||||
            fixture.SetDefaultCommand<GenericCommand<ArgumentOrderSettings>>();
 | 
			
		||||
            fixture.Configure(configurator =>
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var fixture = new CommandAppTester();
 | 
			
		||||
                fixture.SetDefaultCommand<GenericCommand<ArgumentOrderSettings>>();
 | 
			
		||||
                fixture.Configure(configurator =>
 | 
			
		||||
                {
 | 
			
		||||
                    configurator.SetApplicationName("myapp");
 | 
			
		||||
                });
 | 
			
		||||
                configurator.SetApplicationName("myapp");
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = fixture.Run("--help");
 | 
			
		||||
            // When
 | 
			
		||||
            var result = fixture.Run("--help");
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                return Verifier.Verify(result.Output);
 | 
			
		||||
            }
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(result.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            [Expectation("Hidden_Command_Options")]
 | 
			
		||||
            public Task Should_Not_Show_Hidden_Command_Options()
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Hidden_Command_Options")]
 | 
			
		||||
        public Task Should_Not_Show_Hidden_Command_Options()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var fixture = new CommandAppTester();
 | 
			
		||||
            fixture.SetDefaultCommand<GenericCommand<HiddenOptionSettings>>();
 | 
			
		||||
            fixture.Configure(configurator =>
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var fixture = new CommandAppTester();
 | 
			
		||||
                fixture.SetDefaultCommand<GenericCommand<HiddenOptionSettings>>();
 | 
			
		||||
                fixture.Configure(configurator =>
 | 
			
		||||
                {
 | 
			
		||||
                    configurator.SetApplicationName("myapp");
 | 
			
		||||
                });
 | 
			
		||||
                configurator.SetApplicationName("myapp");
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = fixture.Run("--help");
 | 
			
		||||
            // When
 | 
			
		||||
            var result = fixture.Run("--help");
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                return Verifier.Verify(result.Output);
 | 
			
		||||
            }
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(result.Output);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,97 +1,90 @@
 | 
			
		||||
using Shouldly;
 | 
			
		||||
using Spectre.Console.Cli;
 | 
			
		||||
using Spectre.Console.Testing;
 | 
			
		||||
using Spectre.Console.Tests.Data;
 | 
			
		||||
using Xunit;
 | 
			
		||||
namespace Spectre.Console.Tests.Unit.Cli;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Unit.Cli
 | 
			
		||||
public sealed partial class CommandAppTests
 | 
			
		||||
{
 | 
			
		||||
    public sealed partial class CommandAppTests
 | 
			
		||||
    public sealed class Injection
 | 
			
		||||
    {
 | 
			
		||||
        public sealed class Injection
 | 
			
		||||
        public sealed class FakeDependency
 | 
			
		||||
        {
 | 
			
		||||
            public sealed class FakeDependency
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public sealed class InjectSettings : CommandSettings
 | 
			
		||||
        {
 | 
			
		||||
            public FakeDependency Fake { get; set; }
 | 
			
		||||
 | 
			
		||||
            [CommandOption("--name <NAME>")]
 | 
			
		||||
            public string Name { get; }
 | 
			
		||||
 | 
			
		||||
            [CommandOption("--age <AGE>")]
 | 
			
		||||
            public int Age { get; set; }
 | 
			
		||||
 | 
			
		||||
            public InjectSettings(FakeDependency fake, string name)
 | 
			
		||||
            {
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            public sealed class InjectSettings : CommandSettings
 | 
			
		||||
            {
 | 
			
		||||
                public FakeDependency Fake { get; set; }
 | 
			
		||||
 | 
			
		||||
                [CommandOption("--name <NAME>")]
 | 
			
		||||
                public string Name { get; }
 | 
			
		||||
 | 
			
		||||
                [CommandOption("--age <AGE>")]
 | 
			
		||||
                public int Age { get; set; }
 | 
			
		||||
 | 
			
		||||
                public InjectSettings(FakeDependency fake, string name)
 | 
			
		||||
                {
 | 
			
		||||
                    Fake = fake;
 | 
			
		||||
                    Name = "Hello " + name;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Inject_Parameters()
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var app = new CommandAppTester();
 | 
			
		||||
                var dependency = new FakeDependency();
 | 
			
		||||
 | 
			
		||||
                app.SetDefaultCommand<GenericCommand<InjectSettings>>();
 | 
			
		||||
                app.Configure(config =>
 | 
			
		||||
                {
 | 
			
		||||
                    config.Settings.Registrar.RegisterInstance(dependency);
 | 
			
		||||
                    config.PropagateExceptions();
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = app.Run(new[]
 | 
			
		||||
                {
 | 
			
		||||
                    "--name", "foo",
 | 
			
		||||
                    "--age", "35",
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ExitCode.ShouldBe(0);
 | 
			
		||||
                result.Settings.ShouldBeOfType<InjectSettings>().And(injected =>
 | 
			
		||||
                {
 | 
			
		||||
                    injected.ShouldNotBeNull();
 | 
			
		||||
                    injected.Fake.ShouldBeSameAs(dependency);
 | 
			
		||||
                    injected.Name.ShouldBe("Hello foo");
 | 
			
		||||
                    injected.Age.ShouldBe(35);
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Inject_Dependency_Using_A_Given_Registrar()
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var dependency = new FakeDependency();
 | 
			
		||||
                var registrar = new FakeTypeRegistrar { TypeResolverFactory = FakeTypeResolver.Factory };
 | 
			
		||||
                registrar.RegisterInstance(typeof(FakeDependency), dependency);
 | 
			
		||||
                var app = new CommandAppTester(registrar);
 | 
			
		||||
 | 
			
		||||
                app.SetDefaultCommand<GenericCommand<InjectSettings>>();
 | 
			
		||||
                app.Configure(config => config.PropagateExceptions());
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = app.Run(new[]
 | 
			
		||||
                {
 | 
			
		||||
                    "--name", "foo",
 | 
			
		||||
                    "--age", "35",
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ExitCode.ShouldBe(0);
 | 
			
		||||
                result.Settings.ShouldBeOfType<InjectSettings>().And(injected =>
 | 
			
		||||
                {
 | 
			
		||||
                    injected.ShouldNotBeNull();
 | 
			
		||||
                    injected.Fake.ShouldBeSameAs(dependency);
 | 
			
		||||
                    injected.Name.ShouldBe("Hello foo");
 | 
			
		||||
                    injected.Age.ShouldBe(35);
 | 
			
		||||
                });
 | 
			
		||||
                Fake = fake;
 | 
			
		||||
                Name = "Hello " + name;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Inject_Parameters()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var app = new CommandAppTester();
 | 
			
		||||
            var dependency = new FakeDependency();
 | 
			
		||||
 | 
			
		||||
            app.SetDefaultCommand<GenericCommand<InjectSettings>>();
 | 
			
		||||
            app.Configure(config =>
 | 
			
		||||
            {
 | 
			
		||||
                config.Settings.Registrar.RegisterInstance(dependency);
 | 
			
		||||
                config.PropagateExceptions();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            var result = app.Run(new[]
 | 
			
		||||
            {
 | 
			
		||||
                "--name", "foo",
 | 
			
		||||
                "--age", "35",
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ExitCode.ShouldBe(0);
 | 
			
		||||
            result.Settings.ShouldBeOfType<InjectSettings>().And(injected =>
 | 
			
		||||
            {
 | 
			
		||||
                injected.ShouldNotBeNull();
 | 
			
		||||
                injected.Fake.ShouldBeSameAs(dependency);
 | 
			
		||||
                injected.Name.ShouldBe("Hello foo");
 | 
			
		||||
                injected.Age.ShouldBe(35);
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Inject_Dependency_Using_A_Given_Registrar()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var dependency = new FakeDependency();
 | 
			
		||||
            var registrar = new FakeTypeRegistrar { TypeResolverFactory = FakeTypeResolver.Factory };
 | 
			
		||||
            registrar.RegisterInstance(typeof(FakeDependency), dependency);
 | 
			
		||||
            var app = new CommandAppTester(registrar);
 | 
			
		||||
 | 
			
		||||
            app.SetDefaultCommand<GenericCommand<InjectSettings>>();
 | 
			
		||||
            app.Configure(config => config.PropagateExceptions());
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            var result = app.Run(new[]
 | 
			
		||||
            {
 | 
			
		||||
                "--name", "foo",
 | 
			
		||||
                "--age", "35",
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ExitCode.ShouldBe(0);
 | 
			
		||||
            result.Settings.ShouldBeOfType<InjectSettings>().And(injected =>
 | 
			
		||||
            {
 | 
			
		||||
                injected.ShouldNotBeNull();
 | 
			
		||||
                injected.Fake.ShouldBeSameAs(dependency);
 | 
			
		||||
                injected.Name.ShouldBe("Hello foo");
 | 
			
		||||
                injected.Age.ShouldBe(35);
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,327 +1,316 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.ComponentModel;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using Shouldly;
 | 
			
		||||
using Spectre.Console.Cli;
 | 
			
		||||
using Spectre.Console.Testing;
 | 
			
		||||
using Spectre.Console.Tests.Data;
 | 
			
		||||
using Xunit;
 | 
			
		||||
namespace Spectre.Console.Tests.Unit.Cli;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Unit.Cli
 | 
			
		||||
public sealed partial class CommandAppTests
 | 
			
		||||
{
 | 
			
		||||
    public sealed partial class CommandAppTests
 | 
			
		||||
    public sealed class Pairs
 | 
			
		||||
    {
 | 
			
		||||
        public sealed class Pairs
 | 
			
		||||
        public sealed class AmbiguousSettings : CommandSettings
 | 
			
		||||
        {
 | 
			
		||||
            public sealed class AmbiguousSettings : CommandSettings
 | 
			
		||||
            {
 | 
			
		||||
                [CommandOption("--var <VALUE>")]
 | 
			
		||||
                [PairDeconstructor(typeof(StringIntDeconstructor))]
 | 
			
		||||
                [TypeConverter(typeof(CatAgilityConverter))]
 | 
			
		||||
                public ILookup<string, string> Values { get; set; }
 | 
			
		||||
            }
 | 
			
		||||
            [CommandOption("--var <VALUE>")]
 | 
			
		||||
            [PairDeconstructor(typeof(StringIntDeconstructor))]
 | 
			
		||||
            [TypeConverter(typeof(CatAgilityConverter))]
 | 
			
		||||
            public ILookup<string, string> Values { get; set; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
            public sealed class NotDeconstructableSettings : CommandSettings
 | 
			
		||||
            {
 | 
			
		||||
                [CommandOption("--var <VALUE>")]
 | 
			
		||||
                [PairDeconstructor(typeof(StringIntDeconstructor))]
 | 
			
		||||
                public string Values { get; set; }
 | 
			
		||||
            }
 | 
			
		||||
        public sealed class NotDeconstructableSettings : CommandSettings
 | 
			
		||||
        {
 | 
			
		||||
            [CommandOption("--var <VALUE>")]
 | 
			
		||||
            [PairDeconstructor(typeof(StringIntDeconstructor))]
 | 
			
		||||
            public string Values { get; set; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
            public sealed class DefaultPairDeconstructorSettings : CommandSettings
 | 
			
		||||
            {
 | 
			
		||||
                [CommandOption("--var <VALUE>")]
 | 
			
		||||
                public IDictionary<string, int> Values { get; set; }
 | 
			
		||||
            }
 | 
			
		||||
        public sealed class DefaultPairDeconstructorSettings : CommandSettings
 | 
			
		||||
        {
 | 
			
		||||
            [CommandOption("--var <VALUE>")]
 | 
			
		||||
            public IDictionary<string, int> Values { get; set; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
            public sealed class DefaultPairDeconstructorEnumValueSettings : CommandSettings
 | 
			
		||||
            {
 | 
			
		||||
                [CommandOption("--var <VALUE>")]
 | 
			
		||||
                public IDictionary<string, DayOfWeek> Values { get; set; }
 | 
			
		||||
            }
 | 
			
		||||
        public sealed class DefaultPairDeconstructorEnumValueSettings : CommandSettings
 | 
			
		||||
        {
 | 
			
		||||
            [CommandOption("--var <VALUE>")]
 | 
			
		||||
            public IDictionary<string, DayOfWeek> Values { get; set; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
            public sealed class LookupSettings : CommandSettings
 | 
			
		||||
            {
 | 
			
		||||
                [CommandOption("--var <VALUE>")]
 | 
			
		||||
                [PairDeconstructor(typeof(StringIntDeconstructor))]
 | 
			
		||||
                public ILookup<string, string> Values { get; set; }
 | 
			
		||||
            }
 | 
			
		||||
        public sealed class LookupSettings : CommandSettings
 | 
			
		||||
        {
 | 
			
		||||
            [CommandOption("--var <VALUE>")]
 | 
			
		||||
            [PairDeconstructor(typeof(StringIntDeconstructor))]
 | 
			
		||||
            public ILookup<string, string> Values { get; set; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
            public sealed class DictionarySettings : CommandSettings
 | 
			
		||||
            {
 | 
			
		||||
                [CommandOption("--var <VALUE>")]
 | 
			
		||||
                [PairDeconstructor(typeof(StringIntDeconstructor))]
 | 
			
		||||
                public IDictionary<string, string> Values { get; set; }
 | 
			
		||||
            }
 | 
			
		||||
        public sealed class DictionarySettings : CommandSettings
 | 
			
		||||
        {
 | 
			
		||||
            [CommandOption("--var <VALUE>")]
 | 
			
		||||
            [PairDeconstructor(typeof(StringIntDeconstructor))]
 | 
			
		||||
            public IDictionary<string, string> Values { get; set; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
            public sealed class ReadOnlyDictionarySettings : CommandSettings
 | 
			
		||||
            {
 | 
			
		||||
                [CommandOption("--var <VALUE>")]
 | 
			
		||||
                [PairDeconstructor(typeof(StringIntDeconstructor))]
 | 
			
		||||
                public IReadOnlyDictionary<string, string> Values { get; set; }
 | 
			
		||||
            }
 | 
			
		||||
        public sealed class ReadOnlyDictionarySettings : CommandSettings
 | 
			
		||||
        {
 | 
			
		||||
            [CommandOption("--var <VALUE>")]
 | 
			
		||||
            [PairDeconstructor(typeof(StringIntDeconstructor))]
 | 
			
		||||
            public IReadOnlyDictionary<string, string> Values { get; set; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
            public sealed class StringIntDeconstructor : PairDeconstructor<string, string>
 | 
			
		||||
        public sealed class StringIntDeconstructor : PairDeconstructor<string, string>
 | 
			
		||||
        {
 | 
			
		||||
            protected override (string Key, string Value) Deconstruct(string value)
 | 
			
		||||
            {
 | 
			
		||||
                protected override (string Key, string Value) Deconstruct(string value)
 | 
			
		||||
                if (value == null)
 | 
			
		||||
                {
 | 
			
		||||
                    if (value == null)
 | 
			
		||||
                    {
 | 
			
		||||
                        throw new ArgumentNullException(nameof(value));
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    var parts = value.Split(new[] { '=' });
 | 
			
		||||
                    if (parts.Length != 2)
 | 
			
		||||
                    {
 | 
			
		||||
                        throw new InvalidOperationException("Could not parse pair");
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    return (parts[0], parts[1]);
 | 
			
		||||
                    throw new ArgumentNullException(nameof(value));
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Throw_If_Option_Has_Pair_Deconstructor_And_Type_Converter()
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var app = new CommandApp<GenericCommand<AmbiguousSettings>>();
 | 
			
		||||
                app.Configure(config =>
 | 
			
		||||
                var parts = value.Split(new[] { '=' });
 | 
			
		||||
                if (parts.Length != 2)
 | 
			
		||||
                {
 | 
			
		||||
                    config.PropagateExceptions();
 | 
			
		||||
                });
 | 
			
		||||
                    throw new InvalidOperationException("Could not parse pair");
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = Record.Exception(() => app.Run(new[]
 | 
			
		||||
                {
 | 
			
		||||
                    "--var", "foo=bar",
 | 
			
		||||
                    "--var", "foo=qux",
 | 
			
		||||
                }));
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ShouldBeOfType<CommandConfigurationException>().And(ex =>
 | 
			
		||||
                {
 | 
			
		||||
                    ex.Message.ShouldBe("The option 'var' is both marked as pair deconstructable and convertable.");
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Throw_If_Option_Has_Pair_Deconstructor_But_Type_Is_Not_Deconstructable()
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var app = new CommandApp<GenericCommand<NotDeconstructableSettings>>();
 | 
			
		||||
                app.Configure(config =>
 | 
			
		||||
                {
 | 
			
		||||
                    config.PropagateExceptions();
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = Record.Exception(() => app.Run(new[]
 | 
			
		||||
                {
 | 
			
		||||
                    "--var", "foo=bar",
 | 
			
		||||
                    "--var", "foo=qux",
 | 
			
		||||
                }));
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ShouldBeOfType<CommandConfigurationException>().And(ex =>
 | 
			
		||||
                {
 | 
			
		||||
                    ex.Message.ShouldBe("The option 'var' is marked as pair deconstructable, but the underlying type does not support that.");
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Map_Pairs_To_Pair_Deconstructable_Collection_Using_Default_Deconstructort()
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var app = new CommandAppTester();
 | 
			
		||||
                app.SetDefaultCommand<GenericCommand<DefaultPairDeconstructorSettings>>();
 | 
			
		||||
                app.Configure(config =>
 | 
			
		||||
                {
 | 
			
		||||
                    config.PropagateExceptions();
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = app.Run(new[]
 | 
			
		||||
                {
 | 
			
		||||
                    "--var", "foo=1",
 | 
			
		||||
                    "--var", "foo=3",
 | 
			
		||||
                    "--var", "bar=4",
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ExitCode.ShouldBe(0);
 | 
			
		||||
                result.Settings.ShouldBeOfType<DefaultPairDeconstructorSettings>().And(pair =>
 | 
			
		||||
                {
 | 
			
		||||
                    pair.Values.ShouldNotBeNull();
 | 
			
		||||
                    pair.Values.Count.ShouldBe(2);
 | 
			
		||||
                    pair.Values["foo"].ShouldBe(3);
 | 
			
		||||
                    pair.Values["bar"].ShouldBe(4);
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Map_Pairs_With_Enum_Value_To_Pair_Deconstructable_Collection_Using_Default_Deconstructor()
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var app = new CommandAppTester();
 | 
			
		||||
                app.SetDefaultCommand<GenericCommand<DefaultPairDeconstructorEnumValueSettings>>();
 | 
			
		||||
                app.Configure(config =>
 | 
			
		||||
                {
 | 
			
		||||
                    config.PropagateExceptions();
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = app.Run(new[]
 | 
			
		||||
                {
 | 
			
		||||
                    "--var", "foo=Monday",
 | 
			
		||||
                    "--var", "bar=Tuesday",
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ExitCode.ShouldBe(0);
 | 
			
		||||
                result.Settings.ShouldBeOfType<DefaultPairDeconstructorEnumValueSettings>().And(pair =>
 | 
			
		||||
                {
 | 
			
		||||
                    pair.Values.ShouldNotBeNull();
 | 
			
		||||
                    pair.Values.Count.ShouldBe(2);
 | 
			
		||||
                    pair.Values["foo"].ShouldBe(DayOfWeek.Monday);
 | 
			
		||||
                    pair.Values["bar"].ShouldBe(DayOfWeek.Tuesday);
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Theory]
 | 
			
		||||
            [InlineData("foo=1=2", "Error: The value 'foo=1=2' is not in a correct format")]
 | 
			
		||||
            [InlineData("foo=1=2=3", "Error: The value 'foo=1=2=3' is not in a correct format")]
 | 
			
		||||
            public void Should_Throw_If_Value_Is_Not_In_A_Valid_Format_Using_Default_Deconstructor(
 | 
			
		||||
                string input, string expected)
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var app = new CommandAppTester();
 | 
			
		||||
                app.SetDefaultCommand<GenericCommand<DefaultPairDeconstructorSettings>>();
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = app.Run(new[]
 | 
			
		||||
                {
 | 
			
		||||
                    "--var", input,
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ExitCode.ShouldBe(-1);
 | 
			
		||||
                result.Output.ShouldBe(expected);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Map_Lookup_Values()
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var app = new CommandAppTester();
 | 
			
		||||
                app.SetDefaultCommand<GenericCommand<LookupSettings>>();
 | 
			
		||||
                app.Configure(config =>
 | 
			
		||||
                {
 | 
			
		||||
                    config.PropagateExceptions();
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = app.Run(new[]
 | 
			
		||||
                {
 | 
			
		||||
                    "--var", "foo=bar",
 | 
			
		||||
                    "--var", "foo=qux",
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ExitCode.ShouldBe(0);
 | 
			
		||||
                result.Settings.ShouldBeOfType<LookupSettings>().And(pair =>
 | 
			
		||||
                {
 | 
			
		||||
                    pair.Values.ShouldNotBeNull();
 | 
			
		||||
                    pair.Values.Count.ShouldBe(1);
 | 
			
		||||
                    pair.Values["foo"].ToList().Count.ShouldBe(2);
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Map_Dictionary_Values()
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var app = new CommandAppTester();
 | 
			
		||||
                app.SetDefaultCommand<GenericCommand<DictionarySettings>>();
 | 
			
		||||
                app.Configure(config =>
 | 
			
		||||
                {
 | 
			
		||||
                    config.PropagateExceptions();
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = app.Run(new[]
 | 
			
		||||
                {
 | 
			
		||||
                    "--var", "foo=bar",
 | 
			
		||||
                    "--var", "baz=qux",
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ExitCode.ShouldBe(0);
 | 
			
		||||
                result.Settings.ShouldBeOfType<DictionarySettings>().And(pair =>
 | 
			
		||||
                {
 | 
			
		||||
                    pair.Values.ShouldNotBeNull();
 | 
			
		||||
                    pair.Values.Count.ShouldBe(2);
 | 
			
		||||
                    pair.Values["foo"].ShouldBe("bar");
 | 
			
		||||
                    pair.Values["baz"].ShouldBe("qux");
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Map_Latest_Value_Of_Same_Key_When_Mapping_To_Dictionary()
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var app = new CommandAppTester();
 | 
			
		||||
                app.SetDefaultCommand<GenericCommand<DictionarySettings>>();
 | 
			
		||||
                app.Configure(config =>
 | 
			
		||||
                {
 | 
			
		||||
                    config.PropagateExceptions();
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = app.Run(new[]
 | 
			
		||||
                {
 | 
			
		||||
                    "--var", "foo=bar",
 | 
			
		||||
                    "--var", "foo=qux",
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ExitCode.ShouldBe(0);
 | 
			
		||||
                result.Settings.ShouldBeOfType<DictionarySettings>().And(pair =>
 | 
			
		||||
                {
 | 
			
		||||
                    pair.Values.ShouldNotBeNull();
 | 
			
		||||
                    pair.Values.Count.ShouldBe(1);
 | 
			
		||||
                    pair.Values["foo"].ShouldBe("qux");
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Map_ReadOnly_Dictionary_Values()
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var app = new CommandAppTester();
 | 
			
		||||
                app.SetDefaultCommand<GenericCommand<ReadOnlyDictionarySettings>>();
 | 
			
		||||
                app.Configure(config =>
 | 
			
		||||
                {
 | 
			
		||||
                    config.PropagateExceptions();
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = app.Run(new[]
 | 
			
		||||
                {
 | 
			
		||||
                    "--var", "foo=bar",
 | 
			
		||||
                    "--var", "baz=qux",
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ExitCode.ShouldBe(0);
 | 
			
		||||
                result.Settings.ShouldBeOfType<ReadOnlyDictionarySettings>().And(pair =>
 | 
			
		||||
                {
 | 
			
		||||
                    pair.Values.ShouldNotBeNull();
 | 
			
		||||
                    pair.Values.Count.ShouldBe(2);
 | 
			
		||||
                    pair.Values["foo"].ShouldBe("bar");
 | 
			
		||||
                    pair.Values["baz"].ShouldBe("qux");
 | 
			
		||||
                });
 | 
			
		||||
                return (parts[0], parts[1]);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Throw_If_Option_Has_Pair_Deconstructor_And_Type_Converter()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var app = new CommandApp<GenericCommand<AmbiguousSettings>>();
 | 
			
		||||
            app.Configure(config =>
 | 
			
		||||
            {
 | 
			
		||||
                config.PropagateExceptions();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            var result = Record.Exception(() => app.Run(new[]
 | 
			
		||||
            {
 | 
			
		||||
                "--var", "foo=bar",
 | 
			
		||||
                "--var", "foo=qux",
 | 
			
		||||
            }));
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ShouldBeOfType<CommandConfigurationException>().And(ex =>
 | 
			
		||||
            {
 | 
			
		||||
                ex.Message.ShouldBe("The option 'var' is both marked as pair deconstructable and convertable.");
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Throw_If_Option_Has_Pair_Deconstructor_But_Type_Is_Not_Deconstructable()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var app = new CommandApp<GenericCommand<NotDeconstructableSettings>>();
 | 
			
		||||
            app.Configure(config =>
 | 
			
		||||
            {
 | 
			
		||||
                config.PropagateExceptions();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            var result = Record.Exception(() => app.Run(new[]
 | 
			
		||||
            {
 | 
			
		||||
                "--var", "foo=bar",
 | 
			
		||||
                "--var", "foo=qux",
 | 
			
		||||
            }));
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ShouldBeOfType<CommandConfigurationException>().And(ex =>
 | 
			
		||||
            {
 | 
			
		||||
                ex.Message.ShouldBe("The option 'var' is marked as pair deconstructable, but the underlying type does not support that.");
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Map_Pairs_To_Pair_Deconstructable_Collection_Using_Default_Deconstructort()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var app = new CommandAppTester();
 | 
			
		||||
            app.SetDefaultCommand<GenericCommand<DefaultPairDeconstructorSettings>>();
 | 
			
		||||
            app.Configure(config =>
 | 
			
		||||
            {
 | 
			
		||||
                config.PropagateExceptions();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            var result = app.Run(new[]
 | 
			
		||||
            {
 | 
			
		||||
                "--var", "foo=1",
 | 
			
		||||
                "--var", "foo=3",
 | 
			
		||||
                "--var", "bar=4",
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ExitCode.ShouldBe(0);
 | 
			
		||||
            result.Settings.ShouldBeOfType<DefaultPairDeconstructorSettings>().And(pair =>
 | 
			
		||||
            {
 | 
			
		||||
                pair.Values.ShouldNotBeNull();
 | 
			
		||||
                pair.Values.Count.ShouldBe(2);
 | 
			
		||||
                pair.Values["foo"].ShouldBe(3);
 | 
			
		||||
                pair.Values["bar"].ShouldBe(4);
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Map_Pairs_With_Enum_Value_To_Pair_Deconstructable_Collection_Using_Default_Deconstructor()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var app = new CommandAppTester();
 | 
			
		||||
            app.SetDefaultCommand<GenericCommand<DefaultPairDeconstructorEnumValueSettings>>();
 | 
			
		||||
            app.Configure(config =>
 | 
			
		||||
            {
 | 
			
		||||
                config.PropagateExceptions();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            var result = app.Run(new[]
 | 
			
		||||
            {
 | 
			
		||||
                "--var", "foo=Monday",
 | 
			
		||||
                "--var", "bar=Tuesday",
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ExitCode.ShouldBe(0);
 | 
			
		||||
            result.Settings.ShouldBeOfType<DefaultPairDeconstructorEnumValueSettings>().And(pair =>
 | 
			
		||||
            {
 | 
			
		||||
                pair.Values.ShouldNotBeNull();
 | 
			
		||||
                pair.Values.Count.ShouldBe(2);
 | 
			
		||||
                pair.Values["foo"].ShouldBe(DayOfWeek.Monday);
 | 
			
		||||
                pair.Values["bar"].ShouldBe(DayOfWeek.Tuesday);
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Theory]
 | 
			
		||||
        [InlineData("foo=1=2", "Error: The value 'foo=1=2' is not in a correct format")]
 | 
			
		||||
        [InlineData("foo=1=2=3", "Error: The value 'foo=1=2=3' is not in a correct format")]
 | 
			
		||||
        public void Should_Throw_If_Value_Is_Not_In_A_Valid_Format_Using_Default_Deconstructor(
 | 
			
		||||
            string input, string expected)
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var app = new CommandAppTester();
 | 
			
		||||
            app.SetDefaultCommand<GenericCommand<DefaultPairDeconstructorSettings>>();
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            var result = app.Run(new[]
 | 
			
		||||
            {
 | 
			
		||||
                "--var", input,
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ExitCode.ShouldBe(-1);
 | 
			
		||||
            result.Output.ShouldBe(expected);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Map_Lookup_Values()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var app = new CommandAppTester();
 | 
			
		||||
            app.SetDefaultCommand<GenericCommand<LookupSettings>>();
 | 
			
		||||
            app.Configure(config =>
 | 
			
		||||
            {
 | 
			
		||||
                config.PropagateExceptions();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            var result = app.Run(new[]
 | 
			
		||||
            {
 | 
			
		||||
                "--var", "foo=bar",
 | 
			
		||||
                "--var", "foo=qux",
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ExitCode.ShouldBe(0);
 | 
			
		||||
            result.Settings.ShouldBeOfType<LookupSettings>().And(pair =>
 | 
			
		||||
            {
 | 
			
		||||
                pair.Values.ShouldNotBeNull();
 | 
			
		||||
                pair.Values.Count.ShouldBe(1);
 | 
			
		||||
                pair.Values["foo"].ToList().Count.ShouldBe(2);
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Map_Dictionary_Values()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var app = new CommandAppTester();
 | 
			
		||||
            app.SetDefaultCommand<GenericCommand<DictionarySettings>>();
 | 
			
		||||
            app.Configure(config =>
 | 
			
		||||
            {
 | 
			
		||||
                config.PropagateExceptions();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            var result = app.Run(new[]
 | 
			
		||||
            {
 | 
			
		||||
                "--var", "foo=bar",
 | 
			
		||||
                "--var", "baz=qux",
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ExitCode.ShouldBe(0);
 | 
			
		||||
            result.Settings.ShouldBeOfType<DictionarySettings>().And(pair =>
 | 
			
		||||
            {
 | 
			
		||||
                pair.Values.ShouldNotBeNull();
 | 
			
		||||
                pair.Values.Count.ShouldBe(2);
 | 
			
		||||
                pair.Values["foo"].ShouldBe("bar");
 | 
			
		||||
                pair.Values["baz"].ShouldBe("qux");
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Map_Latest_Value_Of_Same_Key_When_Mapping_To_Dictionary()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var app = new CommandAppTester();
 | 
			
		||||
            app.SetDefaultCommand<GenericCommand<DictionarySettings>>();
 | 
			
		||||
            app.Configure(config =>
 | 
			
		||||
            {
 | 
			
		||||
                config.PropagateExceptions();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            var result = app.Run(new[]
 | 
			
		||||
            {
 | 
			
		||||
                "--var", "foo=bar",
 | 
			
		||||
                "--var", "foo=qux",
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ExitCode.ShouldBe(0);
 | 
			
		||||
            result.Settings.ShouldBeOfType<DictionarySettings>().And(pair =>
 | 
			
		||||
            {
 | 
			
		||||
                pair.Values.ShouldNotBeNull();
 | 
			
		||||
                pair.Values.Count.ShouldBe(1);
 | 
			
		||||
                pair.Values["foo"].ShouldBe("qux");
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Map_ReadOnly_Dictionary_Values()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var app = new CommandAppTester();
 | 
			
		||||
            app.SetDefaultCommand<GenericCommand<ReadOnlyDictionarySettings>>();
 | 
			
		||||
            app.Configure(config =>
 | 
			
		||||
            {
 | 
			
		||||
                config.PropagateExceptions();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            var result = app.Run(new[]
 | 
			
		||||
            {
 | 
			
		||||
                "--var", "foo=bar",
 | 
			
		||||
                "--var", "baz=qux",
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ExitCode.ShouldBe(0);
 | 
			
		||||
            result.Settings.ShouldBeOfType<ReadOnlyDictionarySettings>().And(pair =>
 | 
			
		||||
            {
 | 
			
		||||
                pair.Values.ShouldNotBeNull();
 | 
			
		||||
                pair.Values.Count.ShouldBe(2);
 | 
			
		||||
                pair.Values["foo"].ShouldBe("bar");
 | 
			
		||||
                pair.Values["baz"].ShouldBe("qux");
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -1,77 +1,70 @@
 | 
			
		||||
using Shouldly;
 | 
			
		||||
using Spectre.Console.Cli;
 | 
			
		||||
using Spectre.Console.Testing;
 | 
			
		||||
using Spectre.Console.Tests.Data;
 | 
			
		||||
using Xunit;
 | 
			
		||||
namespace Spectre.Console.Tests.Unit.Cli;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Unit.Cli
 | 
			
		||||
public sealed partial class CommandAppTests
 | 
			
		||||
{
 | 
			
		||||
    public sealed partial class CommandAppTests
 | 
			
		||||
    public sealed class Remaining
 | 
			
		||||
    {
 | 
			
		||||
        public sealed class Remaining
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Register_Remaining_Parsed_Arguments_With_Context()
 | 
			
		||||
        {
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Register_Remaining_Parsed_Arguments_With_Context()
 | 
			
		||||
            // Given
 | 
			
		||||
            var app = new CommandAppTester();
 | 
			
		||||
            app.Configure(config =>
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var app = new CommandAppTester();
 | 
			
		||||
                app.Configure(config =>
 | 
			
		||||
                config.PropagateExceptions();
 | 
			
		||||
                config.AddBranch<AnimalSettings>("animal", animal =>
 | 
			
		||||
                {
 | 
			
		||||
                    config.PropagateExceptions();
 | 
			
		||||
                    config.AddBranch<AnimalSettings>("animal", animal =>
 | 
			
		||||
                    {
 | 
			
		||||
                        animal.AddCommand<DogCommand>("dog");
 | 
			
		||||
                    });
 | 
			
		||||
                    animal.AddCommand<DogCommand>("dog");
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = app.Run(new[]
 | 
			
		||||
                {
 | 
			
		||||
                    "animal", "4", "dog", "12", "--",
 | 
			
		||||
                    "--foo", "bar", "--foo", "baz",
 | 
			
		||||
                    "-bar", "\"baz\"", "qux",
 | 
			
		||||
                    "foo bar baz qux",
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.Context.Remaining.Parsed.Count.ShouldBe(4);
 | 
			
		||||
                result.Context.ShouldHaveRemainingArgument("foo", values: new[] { "bar", "baz" });
 | 
			
		||||
                result.Context.ShouldHaveRemainingArgument("b", values: new[] { (string)null });
 | 
			
		||||
                result.Context.ShouldHaveRemainingArgument("a", values: new[] { (string)null });
 | 
			
		||||
                result.Context.ShouldHaveRemainingArgument("r", values: new[] { (string)null });
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Register_Remaining_Raw_Arguments_With_Context()
 | 
			
		||||
            // When
 | 
			
		||||
            var result = app.Run(new[]
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var app = new CommandAppTester();
 | 
			
		||||
                app.Configure(config =>
 | 
			
		||||
                {
 | 
			
		||||
                    config.PropagateExceptions();
 | 
			
		||||
                    config.AddBranch<AnimalSettings>("animal", animal =>
 | 
			
		||||
                    {
 | 
			
		||||
                        animal.AddCommand<DogCommand>("dog");
 | 
			
		||||
                    });
 | 
			
		||||
                });
 | 
			
		||||
                "animal", "4", "dog", "12", "--",
 | 
			
		||||
                "--foo", "bar", "--foo", "baz",
 | 
			
		||||
                "-bar", "\"baz\"", "qux",
 | 
			
		||||
                "foo bar baz qux",
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = app.Run(new[]
 | 
			
		||||
                {
 | 
			
		||||
                    "animal", "4", "dog", "12", "--",
 | 
			
		||||
                    "--foo", "bar", "-bar", "\"baz\"", "qux",
 | 
			
		||||
                    "foo bar baz qux",
 | 
			
		||||
                });
 | 
			
		||||
            // Then
 | 
			
		||||
            result.Context.Remaining.Parsed.Count.ShouldBe(4);
 | 
			
		||||
            result.Context.ShouldHaveRemainingArgument("foo", values: new[] { "bar", "baz" });
 | 
			
		||||
            result.Context.ShouldHaveRemainingArgument("b", values: new[] { (string)null });
 | 
			
		||||
            result.Context.ShouldHaveRemainingArgument("a", values: new[] { (string)null });
 | 
			
		||||
            result.Context.ShouldHaveRemainingArgument("r", values: new[] { (string)null });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.Context.Remaining.Raw.Count.ShouldBe(6);
 | 
			
		||||
                result.Context.Remaining.Raw[0].ShouldBe("--foo");
 | 
			
		||||
                result.Context.Remaining.Raw[1].ShouldBe("bar");
 | 
			
		||||
                result.Context.Remaining.Raw[2].ShouldBe("-bar");
 | 
			
		||||
                result.Context.Remaining.Raw[3].ShouldBe("baz");
 | 
			
		||||
                result.Context.Remaining.Raw[4].ShouldBe("qux");
 | 
			
		||||
                result.Context.Remaining.Raw[5].ShouldBe("foo bar baz qux");
 | 
			
		||||
            }
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Register_Remaining_Raw_Arguments_With_Context()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var app = new CommandAppTester();
 | 
			
		||||
            app.Configure(config =>
 | 
			
		||||
            {
 | 
			
		||||
                config.PropagateExceptions();
 | 
			
		||||
                config.AddBranch<AnimalSettings>("animal", animal =>
 | 
			
		||||
                {
 | 
			
		||||
                    animal.AddCommand<DogCommand>("dog");
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            var result = app.Run(new[]
 | 
			
		||||
            {
 | 
			
		||||
                "animal", "4", "dog", "12", "--",
 | 
			
		||||
                "--foo", "bar", "-bar", "\"baz\"", "qux",
 | 
			
		||||
                "foo bar baz qux",
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.Context.Remaining.Raw.Count.ShouldBe(6);
 | 
			
		||||
            result.Context.Remaining.Raw[0].ShouldBe("--foo");
 | 
			
		||||
            result.Context.Remaining.Raw[1].ShouldBe("bar");
 | 
			
		||||
            result.Context.Remaining.Raw[2].ShouldBe("-bar");
 | 
			
		||||
            result.Context.Remaining.Raw[3].ShouldBe("baz");
 | 
			
		||||
            result.Context.Remaining.Raw[4].ShouldBe("qux");
 | 
			
		||||
            result.Context.Remaining.Raw[5].ShouldBe("foo bar baz qux");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,118 +1,111 @@
 | 
			
		||||
using Shouldly;
 | 
			
		||||
using Spectre.Console.Cli;
 | 
			
		||||
using Spectre.Console.Testing;
 | 
			
		||||
using Spectre.Console.Tests.Data;
 | 
			
		||||
using Xunit;
 | 
			
		||||
namespace Spectre.Console.Tests.Unit.Cli;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Unit.Cli
 | 
			
		||||
public sealed partial class CommandApptests
 | 
			
		||||
{
 | 
			
		||||
    public sealed partial class CommandApptests
 | 
			
		||||
    [Fact]
 | 
			
		||||
    public void Should_Treat_Commands_As_Case_Sensitive_If_Specified()
 | 
			
		||||
    {
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Treat_Commands_As_Case_Sensitive_If_Specified()
 | 
			
		||||
        // Given
 | 
			
		||||
        var app = new CommandApp();
 | 
			
		||||
        app.Configure(config =>
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var app = new CommandApp();
 | 
			
		||||
            app.Configure(config =>
 | 
			
		||||
            {
 | 
			
		||||
                config.UseStrictParsing();
 | 
			
		||||
                config.PropagateExceptions();
 | 
			
		||||
                config.CaseSensitivity(CaseSensitivity.Commands);
 | 
			
		||||
                config.AddCommand<GenericCommand<StringOptionSettings>>("command");
 | 
			
		||||
            });
 | 
			
		||||
            config.UseStrictParsing();
 | 
			
		||||
            config.PropagateExceptions();
 | 
			
		||||
            config.CaseSensitivity(CaseSensitivity.Commands);
 | 
			
		||||
            config.AddCommand<GenericCommand<StringOptionSettings>>("command");
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            var result = Record.Exception(() => app.Run(new[]
 | 
			
		||||
            {
 | 
			
		||||
                "Command", "--foo", "bar",
 | 
			
		||||
            }));
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ShouldNotBeNull();
 | 
			
		||||
            result.ShouldBeOfType<CommandParseException>().And(ex =>
 | 
			
		||||
            {
 | 
			
		||||
                ex.Message.ShouldBe("Unknown command 'Command'.");
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Treat_Long_Options_As_Case_Sensitive_If_Specified()
 | 
			
		||||
        // When
 | 
			
		||||
        var result = Record.Exception(() => app.Run(new[]
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var app = new CommandApp();
 | 
			
		||||
            app.Configure(config =>
 | 
			
		||||
            {
 | 
			
		||||
                config.UseStrictParsing();
 | 
			
		||||
                config.PropagateExceptions();
 | 
			
		||||
                config.CaseSensitivity(CaseSensitivity.LongOptions);
 | 
			
		||||
                config.AddCommand<GenericCommand<StringOptionSettings>>("command");
 | 
			
		||||
            });
 | 
			
		||||
            "Command", "--foo", "bar",
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            var result = Record.Exception(() => app.Run(new[]
 | 
			
		||||
            {
 | 
			
		||||
                "command", "--Foo", "bar",
 | 
			
		||||
            }));
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ShouldNotBeNull();
 | 
			
		||||
            result.ShouldBeOfType<CommandParseException>().And(ex =>
 | 
			
		||||
            {
 | 
			
		||||
                ex.Message.ShouldBe("Unknown option 'Foo'.");
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Treat_Short_Options_As_Case_Sensitive()
 | 
			
		||||
        // Then
 | 
			
		||||
        result.ShouldNotBeNull();
 | 
			
		||||
        result.ShouldBeOfType<CommandParseException>().And(ex =>
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var app = new CommandApp();
 | 
			
		||||
            app.Configure(config =>
 | 
			
		||||
            {
 | 
			
		||||
                config.UseStrictParsing();
 | 
			
		||||
                config.PropagateExceptions();
 | 
			
		||||
                config.AddCommand<GenericCommand<StringOptionSettings>>("command");
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            var result = Record.Exception(() => app.Run(new[]
 | 
			
		||||
            {
 | 
			
		||||
                "command", "-F", "bar",
 | 
			
		||||
            }));
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ShouldNotBeNull();
 | 
			
		||||
            result.ShouldBeOfType<CommandParseException>().And(ex =>
 | 
			
		||||
            {
 | 
			
		||||
                ex.Message.ShouldBe("Unknown option 'F'.");
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Suppress_Case_Sensitivity_If_Specified()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var app = new CommandAppTester();
 | 
			
		||||
            app.Configure(config =>
 | 
			
		||||
            {
 | 
			
		||||
                config.UseStrictParsing();
 | 
			
		||||
                config.PropagateExceptions();
 | 
			
		||||
                config.CaseSensitivity(CaseSensitivity.None);
 | 
			
		||||
                config.AddCommand<GenericCommand<StringOptionSettings>>("command");
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            var result = app.Run(new[]
 | 
			
		||||
            {
 | 
			
		||||
                "Command", "--Foo", "bar",
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ExitCode.ShouldBe(0);
 | 
			
		||||
            result.Settings.ShouldBeOfType<StringOptionSettings>().And(vec =>
 | 
			
		||||
            {
 | 
			
		||||
                vec.Foo.ShouldBe("bar");
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
            ex.Message.ShouldBe("Unknown command 'Command'.");
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    public void Should_Treat_Long_Options_As_Case_Sensitive_If_Specified()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var app = new CommandApp();
 | 
			
		||||
        app.Configure(config =>
 | 
			
		||||
        {
 | 
			
		||||
            config.UseStrictParsing();
 | 
			
		||||
            config.PropagateExceptions();
 | 
			
		||||
            config.CaseSensitivity(CaseSensitivity.LongOptions);
 | 
			
		||||
            config.AddCommand<GenericCommand<StringOptionSettings>>("command");
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        var result = Record.Exception(() => app.Run(new[]
 | 
			
		||||
        {
 | 
			
		||||
            "command", "--Foo", "bar",
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        result.ShouldNotBeNull();
 | 
			
		||||
        result.ShouldBeOfType<CommandParseException>().And(ex =>
 | 
			
		||||
        {
 | 
			
		||||
            ex.Message.ShouldBe("Unknown option 'Foo'.");
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    public void Should_Treat_Short_Options_As_Case_Sensitive()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var app = new CommandApp();
 | 
			
		||||
        app.Configure(config =>
 | 
			
		||||
        {
 | 
			
		||||
            config.UseStrictParsing();
 | 
			
		||||
            config.PropagateExceptions();
 | 
			
		||||
            config.AddCommand<GenericCommand<StringOptionSettings>>("command");
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        var result = Record.Exception(() => app.Run(new[]
 | 
			
		||||
        {
 | 
			
		||||
            "command", "-F", "bar",
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        result.ShouldNotBeNull();
 | 
			
		||||
        result.ShouldBeOfType<CommandParseException>().And(ex =>
 | 
			
		||||
        {
 | 
			
		||||
            ex.Message.ShouldBe("Unknown option 'F'.");
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    public void Should_Suppress_Case_Sensitivity_If_Specified()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var app = new CommandAppTester();
 | 
			
		||||
        app.Configure(config =>
 | 
			
		||||
        {
 | 
			
		||||
            config.UseStrictParsing();
 | 
			
		||||
            config.PropagateExceptions();
 | 
			
		||||
            config.CaseSensitivity(CaseSensitivity.None);
 | 
			
		||||
            config.AddCommand<GenericCommand<StringOptionSettings>>("command");
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        var result = app.Run(new[]
 | 
			
		||||
        {
 | 
			
		||||
            "Command", "--Foo", "bar",
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        result.ExitCode.ShouldBe(0);
 | 
			
		||||
        result.Settings.ShouldBeOfType<StringOptionSettings>().And(vec =>
 | 
			
		||||
        {
 | 
			
		||||
            vec.Foo.ShouldBe("bar");
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,26 +1,21 @@
 | 
			
		||||
using Shouldly;
 | 
			
		||||
using Spectre.Console.Cli;
 | 
			
		||||
using Xunit;
 | 
			
		||||
namespace Spectre.Console.Tests.Unit.Cli;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Unit.Cli
 | 
			
		||||
public sealed partial class CommandAppTests
 | 
			
		||||
{
 | 
			
		||||
    public sealed partial class CommandAppTests
 | 
			
		||||
    [Fact]
 | 
			
		||||
    public void Should_Apply_Case_Sensitivity_For_Everything_By_Default()
 | 
			
		||||
    {
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Apply_Case_Sensitivity_For_Everything_By_Default()
 | 
			
		||||
        // Given
 | 
			
		||||
        var app = new CommandApp();
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        var defaultSensitivity = CaseSensitivity.None;
 | 
			
		||||
        app.Configure(config =>
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var app = new CommandApp();
 | 
			
		||||
            defaultSensitivity = config.Settings.CaseSensitivity;
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            var defaultSensitivity = CaseSensitivity.None;
 | 
			
		||||
            app.Configure(config =>
 | 
			
		||||
            {
 | 
			
		||||
                defaultSensitivity = config.Settings.CaseSensitivity;
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            defaultSensitivity.ShouldBe(CaseSensitivity.All);
 | 
			
		||||
        }
 | 
			
		||||
        // Then
 | 
			
		||||
        defaultSensitivity.ShouldBe(CaseSensitivity.All);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,40 +1,33 @@
 | 
			
		||||
using Shouldly;
 | 
			
		||||
using Spectre.Console.Cli;
 | 
			
		||||
using Spectre.Console.Testing;
 | 
			
		||||
using Spectre.Console.Tests.Data;
 | 
			
		||||
using Xunit;
 | 
			
		||||
namespace Spectre.Console.Tests.Unit.Cli;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Unit.Cli
 | 
			
		||||
public sealed partial class CommandAppTests
 | 
			
		||||
{
 | 
			
		||||
    public sealed partial class CommandAppTests
 | 
			
		||||
    public sealed class TypeConverters
 | 
			
		||||
    {
 | 
			
		||||
        public sealed class TypeConverters
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Bind_Using_Custom_Type_Converter_If_Specified()
 | 
			
		||||
        {
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Bind_Using_Custom_Type_Converter_If_Specified()
 | 
			
		||||
            // Given
 | 
			
		||||
            var app = new CommandAppTester();
 | 
			
		||||
            app.Configure(config =>
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var app = new CommandAppTester();
 | 
			
		||||
                app.Configure(config =>
 | 
			
		||||
                {
 | 
			
		||||
                    config.PropagateExceptions();
 | 
			
		||||
                    config.AddCommand<CatCommand>("cat");
 | 
			
		||||
                });
 | 
			
		||||
                config.PropagateExceptions();
 | 
			
		||||
                config.AddCommand<CatCommand>("cat");
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = app.Run(new[]
 | 
			
		||||
                {
 | 
			
		||||
                     "cat", "--name", "Tiger",
 | 
			
		||||
                     "--agility", "FOOBAR",
 | 
			
		||||
                });
 | 
			
		||||
            // When
 | 
			
		||||
            var result = app.Run(new[]
 | 
			
		||||
            {
 | 
			
		||||
                    "cat", "--name", "Tiger",
 | 
			
		||||
                    "--agility", "FOOBAR",
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ExitCode.ShouldBe(0);
 | 
			
		||||
                result.Settings.ShouldBeOfType<CatSettings>().And(cat =>
 | 
			
		||||
                {
 | 
			
		||||
                    cat.Agility.ShouldBe(6);
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ExitCode.ShouldBe(0);
 | 
			
		||||
            result.Settings.ShouldBeOfType<CatSettings>().And(cat =>
 | 
			
		||||
            {
 | 
			
		||||
                cat.Agility.ShouldBe(6);
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,299 +1,291 @@
 | 
			
		||||
using Shouldly;
 | 
			
		||||
using Spectre.Console.Cli;
 | 
			
		||||
using Spectre.Console.Cli.Unsafe;
 | 
			
		||||
using Spectre.Console.Testing;
 | 
			
		||||
using Spectre.Console.Tests.Data;
 | 
			
		||||
using Xunit;
 | 
			
		||||
namespace Spectre.Console.Tests.Unit.Cli;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Unit.Cli
 | 
			
		||||
public sealed partial class CommandAppTests
 | 
			
		||||
{
 | 
			
		||||
    public sealed partial class CommandAppTests
 | 
			
		||||
    public sealed class SafetyOff
 | 
			
		||||
    {
 | 
			
		||||
        public sealed class SafetyOff
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Can_Mix_Safe_And_Unsafe_Configurators()
 | 
			
		||||
        {
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Can_Mix_Safe_And_Unsafe_Configurators()
 | 
			
		||||
            // Given
 | 
			
		||||
            var app = new CommandAppTester();
 | 
			
		||||
            app.Configure(config =>
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var app = new CommandAppTester();
 | 
			
		||||
                app.Configure(config =>
 | 
			
		||||
                {
 | 
			
		||||
                    config.PropagateExceptions();
 | 
			
		||||
                config.PropagateExceptions();
 | 
			
		||||
 | 
			
		||||
                    config.AddBranch<AnimalSettings>("animal", animal =>
 | 
			
		||||
                config.AddBranch<AnimalSettings>("animal", animal =>
 | 
			
		||||
                {
 | 
			
		||||
                    animal.SafetyOff().AddBranch("mammal", typeof(MammalSettings), mammal =>
 | 
			
		||||
                    {
 | 
			
		||||
                        animal.SafetyOff().AddBranch("mammal", typeof(MammalSettings), mammal =>
 | 
			
		||||
                        {
 | 
			
		||||
                            mammal.AddCommand("dog", typeof(DogCommand));
 | 
			
		||||
                            mammal.AddCommand("horse", typeof(HorseCommand));
 | 
			
		||||
                        });
 | 
			
		||||
                        mammal.AddCommand("dog", typeof(DogCommand));
 | 
			
		||||
                        mammal.AddCommand("horse", typeof(HorseCommand));
 | 
			
		||||
                    });
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = app.Run(new[]
 | 
			
		||||
                {
 | 
			
		||||
                    "animal", "--alive", "mammal", "--name",
 | 
			
		||||
                    "Rufus", "dog", "12", "--good-boy",
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ExitCode.ShouldBe(0);
 | 
			
		||||
                result.Settings.ShouldBeOfType<DogSettings>().And(dog =>
 | 
			
		||||
                {
 | 
			
		||||
                    dog.Age.ShouldBe(12);
 | 
			
		||||
                    dog.GoodBoy.ShouldBe(true);
 | 
			
		||||
                    dog.Name.ShouldBe("Rufus");
 | 
			
		||||
                    dog.IsAlive.ShouldBe(true);
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Can_Turn_Safety_On_After_Turning_It_Off_For_Branch()
 | 
			
		||||
            // When
 | 
			
		||||
            var result = app.Run(new[]
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var app = new CommandAppTester();
 | 
			
		||||
                app.Configure(config =>
 | 
			
		||||
                {
 | 
			
		||||
                    config.PropagateExceptions();
 | 
			
		||||
                "animal", "--alive", "mammal", "--name",
 | 
			
		||||
                "Rufus", "dog", "12", "--good-boy",
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
                    config.SafetyOff().AddBranch("animal", typeof(AnimalSettings), animal =>
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ExitCode.ShouldBe(0);
 | 
			
		||||
            result.Settings.ShouldBeOfType<DogSettings>().And(dog =>
 | 
			
		||||
            {
 | 
			
		||||
                dog.Age.ShouldBe(12);
 | 
			
		||||
                dog.GoodBoy.ShouldBe(true);
 | 
			
		||||
                dog.Name.ShouldBe("Rufus");
 | 
			
		||||
                dog.IsAlive.ShouldBe(true);
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Can_Turn_Safety_On_After_Turning_It_Off_For_Branch()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var app = new CommandAppTester();
 | 
			
		||||
            app.Configure(config =>
 | 
			
		||||
            {
 | 
			
		||||
                config.PropagateExceptions();
 | 
			
		||||
 | 
			
		||||
                config.SafetyOff().AddBranch("animal", typeof(AnimalSettings), animal =>
 | 
			
		||||
                {
 | 
			
		||||
                    animal.SafetyOn<AnimalSettings>()
 | 
			
		||||
                        .AddBranch<MammalSettings>("mammal", mammal =>
 | 
			
		||||
                    {
 | 
			
		||||
                        animal.SafetyOn<AnimalSettings>()
 | 
			
		||||
                            .AddBranch<MammalSettings>("mammal", mammal =>
 | 
			
		||||
                        {
 | 
			
		||||
                            mammal.SafetyOff().AddCommand("dog", typeof(DogCommand));
 | 
			
		||||
                            mammal.AddCommand<HorseCommand>("horse");
 | 
			
		||||
                        });
 | 
			
		||||
                        mammal.SafetyOff().AddCommand("dog", typeof(DogCommand));
 | 
			
		||||
                        mammal.AddCommand<HorseCommand>("horse");
 | 
			
		||||
                    });
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = app.Run(new[]
 | 
			
		||||
                {
 | 
			
		||||
                    "animal", "--alive", "mammal", "--name",
 | 
			
		||||
                    "Rufus", "dog", "12", "--good-boy",
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ExitCode.ShouldBe(0);
 | 
			
		||||
                result.Settings.ShouldBeOfType<DogSettings>().And(dog =>
 | 
			
		||||
                {
 | 
			
		||||
                    dog.Age.ShouldBe(12);
 | 
			
		||||
                    dog.GoodBoy.ShouldBe(true);
 | 
			
		||||
                    dog.Name.ShouldBe("Rufus");
 | 
			
		||||
                    dog.IsAlive.ShouldBe(true);
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Throw_If_Trying_To_Convert_Unsafe_Branch_Configurator_To_Safe_Version_With_Wrong_Type()
 | 
			
		||||
            // When
 | 
			
		||||
            var result = app.Run(new[]
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var app = new CommandApp();
 | 
			
		||||
                "animal", "--alive", "mammal", "--name",
 | 
			
		||||
                "Rufus", "dog", "12", "--good-boy",
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = Record.Exception(() => app.Configure(config =>
 | 
			
		||||
                {
 | 
			
		||||
                    config.PropagateExceptions();
 | 
			
		||||
 | 
			
		||||
                    config.SafetyOff().AddBranch("animal", typeof(AnimalSettings), animal =>
 | 
			
		||||
                    {
 | 
			
		||||
                        animal.SafetyOn<MammalSettings>().AddCommand<DogCommand>("dog");
 | 
			
		||||
                    });
 | 
			
		||||
                }));
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ShouldBeOfType<CommandConfigurationException>();
 | 
			
		||||
                result.Message.ShouldBe("Configurator cannot be converted to a safe configurator of type 'MammalSettings'.");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Pass_Case_1()
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ExitCode.ShouldBe(0);
 | 
			
		||||
            result.Settings.ShouldBeOfType<DogSettings>().And(dog =>
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var app = new CommandAppTester();
 | 
			
		||||
                app.Configure(config =>
 | 
			
		||||
                {
 | 
			
		||||
                    config.PropagateExceptions();
 | 
			
		||||
                dog.Age.ShouldBe(12);
 | 
			
		||||
                dog.GoodBoy.ShouldBe(true);
 | 
			
		||||
                dog.Name.ShouldBe("Rufus");
 | 
			
		||||
                dog.IsAlive.ShouldBe(true);
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
                    config.SafetyOff().AddBranch("animal", typeof(AnimalSettings), animal =>
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Throw_If_Trying_To_Convert_Unsafe_Branch_Configurator_To_Safe_Version_With_Wrong_Type()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var app = new CommandApp();
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            var result = Record.Exception(() => app.Configure(config =>
 | 
			
		||||
            {
 | 
			
		||||
                config.PropagateExceptions();
 | 
			
		||||
 | 
			
		||||
                config.SafetyOff().AddBranch("animal", typeof(AnimalSettings), animal =>
 | 
			
		||||
                {
 | 
			
		||||
                    animal.SafetyOn<MammalSettings>().AddCommand<DogCommand>("dog");
 | 
			
		||||
                });
 | 
			
		||||
            }));
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ShouldBeOfType<CommandConfigurationException>();
 | 
			
		||||
            result.Message.ShouldBe("Configurator cannot be converted to a safe configurator of type 'MammalSettings'.");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Pass_Case_1()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var app = new CommandAppTester();
 | 
			
		||||
            app.Configure(config =>
 | 
			
		||||
            {
 | 
			
		||||
                config.PropagateExceptions();
 | 
			
		||||
 | 
			
		||||
                config.SafetyOff().AddBranch("animal", typeof(AnimalSettings), animal =>
 | 
			
		||||
                {
 | 
			
		||||
                    animal.AddBranch("mammal", typeof(MammalSettings), mammal =>
 | 
			
		||||
                    {
 | 
			
		||||
                        animal.AddBranch("mammal", typeof(MammalSettings), mammal =>
 | 
			
		||||
                        {
 | 
			
		||||
                            mammal.AddCommand("dog", typeof(DogCommand));
 | 
			
		||||
                            mammal.AddCommand("horse", typeof(HorseCommand));
 | 
			
		||||
                        });
 | 
			
		||||
                        mammal.AddCommand("dog", typeof(DogCommand));
 | 
			
		||||
                        mammal.AddCommand("horse", typeof(HorseCommand));
 | 
			
		||||
                    });
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = app.Run(new[]
 | 
			
		||||
                {
 | 
			
		||||
                    "animal", "--alive", "mammal", "--name",
 | 
			
		||||
                    "Rufus", "dog", "12", "--good-boy",
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ExitCode.ShouldBe(0);
 | 
			
		||||
                result.Settings.ShouldBeOfType<DogSettings>().And(dog =>
 | 
			
		||||
                {
 | 
			
		||||
                    dog.Age.ShouldBe(12);
 | 
			
		||||
                    dog.GoodBoy.ShouldBe(true);
 | 
			
		||||
                    dog.Name.ShouldBe("Rufus");
 | 
			
		||||
                    dog.IsAlive.ShouldBe(true);
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Pass_Case_2()
 | 
			
		||||
            // When
 | 
			
		||||
            var result = app.Run(new[]
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var app = new CommandAppTester();
 | 
			
		||||
                app.Configure(config =>
 | 
			
		||||
                {
 | 
			
		||||
                    config.PropagateExceptions();
 | 
			
		||||
                    config.SafetyOff().AddCommand("dog", typeof(DogCommand));
 | 
			
		||||
                });
 | 
			
		||||
                "animal", "--alive", "mammal", "--name",
 | 
			
		||||
                "Rufus", "dog", "12", "--good-boy",
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = app.Run(new[]
 | 
			
		||||
                {
 | 
			
		||||
                    "dog", "12", "4", "--good-boy",
 | 
			
		||||
                    "--name", "Rufus", "--alive",
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ExitCode.ShouldBe(0);
 | 
			
		||||
                result.Settings.ShouldBeOfType<DogSettings>().And(dog =>
 | 
			
		||||
                {
 | 
			
		||||
                    dog.Legs.ShouldBe(12);
 | 
			
		||||
                    dog.Age.ShouldBe(4);
 | 
			
		||||
                    dog.GoodBoy.ShouldBe(true);
 | 
			
		||||
                    dog.Name.ShouldBe("Rufus");
 | 
			
		||||
                    dog.IsAlive.ShouldBe(true);
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Pass_Case_3()
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ExitCode.ShouldBe(0);
 | 
			
		||||
            result.Settings.ShouldBeOfType<DogSettings>().And(dog =>
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var app = new CommandAppTester();
 | 
			
		||||
                app.Configure(config =>
 | 
			
		||||
                {
 | 
			
		||||
                    config.PropagateExceptions();
 | 
			
		||||
                    config.SafetyOff().AddBranch("animal", typeof(AnimalSettings), animal =>
 | 
			
		||||
                    {
 | 
			
		||||
                        animal.AddCommand("dog", typeof(DogCommand));
 | 
			
		||||
                        animal.AddCommand("horse", typeof(HorseCommand));
 | 
			
		||||
                    });
 | 
			
		||||
                });
 | 
			
		||||
                dog.Age.ShouldBe(12);
 | 
			
		||||
                dog.GoodBoy.ShouldBe(true);
 | 
			
		||||
                dog.Name.ShouldBe("Rufus");
 | 
			
		||||
                dog.IsAlive.ShouldBe(true);
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = app.Run(new[]
 | 
			
		||||
                {
 | 
			
		||||
                    "animal", "dog", "12", "--good-boy",
 | 
			
		||||
                    "--name", "Rufus",
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ExitCode.ShouldBe(0);
 | 
			
		||||
                result.Settings.ShouldBeOfType<DogSettings>().And(dog =>
 | 
			
		||||
                {
 | 
			
		||||
                    dog.Age.ShouldBe(12);
 | 
			
		||||
                    dog.GoodBoy.ShouldBe(true);
 | 
			
		||||
                    dog.Name.ShouldBe("Rufus");
 | 
			
		||||
                    dog.IsAlive.ShouldBe(false);
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Pass_Case_4()
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Pass_Case_2()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var app = new CommandAppTester();
 | 
			
		||||
            app.Configure(config =>
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var app = new CommandAppTester();
 | 
			
		||||
                app.Configure(config =>
 | 
			
		||||
                {
 | 
			
		||||
                    config.PropagateExceptions();
 | 
			
		||||
                    config.SafetyOff().AddBranch("animal", typeof(AnimalSettings), animal =>
 | 
			
		||||
                    {
 | 
			
		||||
                        animal.AddCommand("dog", typeof(DogCommand));
 | 
			
		||||
                    });
 | 
			
		||||
                });
 | 
			
		||||
                config.PropagateExceptions();
 | 
			
		||||
                config.SafetyOff().AddCommand("dog", typeof(DogCommand));
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = app.Run(new[]
 | 
			
		||||
                {
 | 
			
		||||
                    "animal", "4", "dog", "12",
 | 
			
		||||
                    "--good-boy", "--name", "Rufus",
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ExitCode.ShouldBe(0);
 | 
			
		||||
                result.Settings.ShouldBeOfType<DogSettings>().And(dog =>
 | 
			
		||||
                {
 | 
			
		||||
                    dog.Legs.ShouldBe(4);
 | 
			
		||||
                    dog.Age.ShouldBe(12);
 | 
			
		||||
                    dog.GoodBoy.ShouldBe(true);
 | 
			
		||||
                    dog.IsAlive.ShouldBe(false);
 | 
			
		||||
                    dog.Name.ShouldBe("Rufus");
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Pass_Case_5()
 | 
			
		||||
            // When
 | 
			
		||||
            var result = app.Run(new[]
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var app = new CommandAppTester();
 | 
			
		||||
                app.Configure(config =>
 | 
			
		||||
                {
 | 
			
		||||
                    config.PropagateExceptions();
 | 
			
		||||
                    config.SafetyOff().AddCommand("multi", typeof(OptionVectorCommand));
 | 
			
		||||
                });
 | 
			
		||||
                "dog", "12", "4", "--good-boy",
 | 
			
		||||
                "--name", "Rufus", "--alive",
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = app.Run(new[]
 | 
			
		||||
                {
 | 
			
		||||
                    "multi", "--foo", "a", "--foo", "b", "--bar", "1", "--foo", "c", "--bar", "2",
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ExitCode.ShouldBe(0);
 | 
			
		||||
                result.Settings.ShouldBeOfType<OptionVectorSettings>().And(vec =>
 | 
			
		||||
                {
 | 
			
		||||
                    vec.Foo.Length.ShouldBe(3);
 | 
			
		||||
                    vec.Foo.ShouldBe(new[] { "a", "b", "c" });
 | 
			
		||||
                    vec.Bar.Length.ShouldBe(2);
 | 
			
		||||
                    vec.Bar.ShouldBe(new[] { 1, 2 });
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Pass_Case_6()
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ExitCode.ShouldBe(0);
 | 
			
		||||
            result.Settings.ShouldBeOfType<DogSettings>().And(dog =>
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var app = new CommandAppTester();
 | 
			
		||||
                app.Configure(config =>
 | 
			
		||||
                {
 | 
			
		||||
                    config.PropagateExceptions();
 | 
			
		||||
                    config.AddCommand<GenericCommand<ArgumentVectorSettings>>("multi");
 | 
			
		||||
                });
 | 
			
		||||
                dog.Legs.ShouldBe(12);
 | 
			
		||||
                dog.Age.ShouldBe(4);
 | 
			
		||||
                dog.GoodBoy.ShouldBe(true);
 | 
			
		||||
                dog.Name.ShouldBe("Rufus");
 | 
			
		||||
                dog.IsAlive.ShouldBe(true);
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = app.Run(new[]
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Pass_Case_3()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var app = new CommandAppTester();
 | 
			
		||||
            app.Configure(config =>
 | 
			
		||||
            {
 | 
			
		||||
                config.PropagateExceptions();
 | 
			
		||||
                config.SafetyOff().AddBranch("animal", typeof(AnimalSettings), animal =>
 | 
			
		||||
                {
 | 
			
		||||
                    "multi", "a", "b", "c",
 | 
			
		||||
                    animal.AddCommand("dog", typeof(DogCommand));
 | 
			
		||||
                    animal.AddCommand("horse", typeof(HorseCommand));
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ExitCode.ShouldBe(0);
 | 
			
		||||
                result.Settings.ShouldBeOfType<ArgumentVectorSettings>().And(vec =>
 | 
			
		||||
            // When
 | 
			
		||||
            var result = app.Run(new[]
 | 
			
		||||
            {
 | 
			
		||||
                "animal", "dog", "12", "--good-boy",
 | 
			
		||||
                "--name", "Rufus",
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ExitCode.ShouldBe(0);
 | 
			
		||||
            result.Settings.ShouldBeOfType<DogSettings>().And(dog =>
 | 
			
		||||
            {
 | 
			
		||||
                dog.Age.ShouldBe(12);
 | 
			
		||||
                dog.GoodBoy.ShouldBe(true);
 | 
			
		||||
                dog.Name.ShouldBe("Rufus");
 | 
			
		||||
                dog.IsAlive.ShouldBe(false);
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Pass_Case_4()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var app = new CommandAppTester();
 | 
			
		||||
            app.Configure(config =>
 | 
			
		||||
            {
 | 
			
		||||
                config.PropagateExceptions();
 | 
			
		||||
                config.SafetyOff().AddBranch("animal", typeof(AnimalSettings), animal =>
 | 
			
		||||
                {
 | 
			
		||||
                    vec.Foo.Length.ShouldBe(3);
 | 
			
		||||
                    vec.Foo.ShouldBe(new[] { "a", "b", "c" });
 | 
			
		||||
                    animal.AddCommand("dog", typeof(DogCommand));
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            var result = app.Run(new[]
 | 
			
		||||
            {
 | 
			
		||||
                "animal", "4", "dog", "12",
 | 
			
		||||
                "--good-boy", "--name", "Rufus",
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ExitCode.ShouldBe(0);
 | 
			
		||||
            result.Settings.ShouldBeOfType<DogSettings>().And(dog =>
 | 
			
		||||
            {
 | 
			
		||||
                dog.Legs.ShouldBe(4);
 | 
			
		||||
                dog.Age.ShouldBe(12);
 | 
			
		||||
                dog.GoodBoy.ShouldBe(true);
 | 
			
		||||
                dog.IsAlive.ShouldBe(false);
 | 
			
		||||
                dog.Name.ShouldBe("Rufus");
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Pass_Case_5()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var app = new CommandAppTester();
 | 
			
		||||
            app.Configure(config =>
 | 
			
		||||
            {
 | 
			
		||||
                config.PropagateExceptions();
 | 
			
		||||
                config.SafetyOff().AddCommand("multi", typeof(OptionVectorCommand));
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            var result = app.Run(new[]
 | 
			
		||||
            {
 | 
			
		||||
                "multi", "--foo", "a", "--foo", "b", "--bar", "1", "--foo", "c", "--bar", "2",
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ExitCode.ShouldBe(0);
 | 
			
		||||
            result.Settings.ShouldBeOfType<OptionVectorSettings>().And(vec =>
 | 
			
		||||
            {
 | 
			
		||||
                vec.Foo.Length.ShouldBe(3);
 | 
			
		||||
                vec.Foo.ShouldBe(new[] { "a", "b", "c" });
 | 
			
		||||
                vec.Bar.Length.ShouldBe(2);
 | 
			
		||||
                vec.Bar.ShouldBe(new[] { 1, 2 });
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Pass_Case_6()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var app = new CommandAppTester();
 | 
			
		||||
            app.Configure(config =>
 | 
			
		||||
            {
 | 
			
		||||
                config.PropagateExceptions();
 | 
			
		||||
                config.AddCommand<GenericCommand<ArgumentVectorSettings>>("multi");
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            var result = app.Run(new[]
 | 
			
		||||
            {
 | 
			
		||||
                "multi", "a", "b", "c",
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ExitCode.ShouldBe(0);
 | 
			
		||||
            result.Settings.ShouldBeOfType<ArgumentVectorSettings>().And(vec =>
 | 
			
		||||
            {
 | 
			
		||||
                vec.Foo.Length.ShouldBe(3);
 | 
			
		||||
                vec.Foo.ShouldBe(new[] { "a", "b", "c" });
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,88 +1,82 @@
 | 
			
		||||
using Shouldly;
 | 
			
		||||
using Spectre.Console.Cli;
 | 
			
		||||
using Spectre.Console.Tests.Data;
 | 
			
		||||
using Xunit;
 | 
			
		||||
namespace Spectre.Console.Tests.Unit.Cli;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Unit.Cli
 | 
			
		||||
public sealed partial class CommandAppTests
 | 
			
		||||
{
 | 
			
		||||
    public sealed partial class CommandAppTests
 | 
			
		||||
    public sealed class Validation
 | 
			
		||||
    {
 | 
			
		||||
        public sealed class Validation
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Throw_If_Attribute_Validation_Fails()
 | 
			
		||||
        {
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Throw_If_Attribute_Validation_Fails()
 | 
			
		||||
            // Given
 | 
			
		||||
            var app = new CommandApp();
 | 
			
		||||
            app.Configure(config =>
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var app = new CommandApp();
 | 
			
		||||
                app.Configure(config =>
 | 
			
		||||
                config.PropagateExceptions();
 | 
			
		||||
                config.AddBranch<AnimalSettings>("animal", animal =>
 | 
			
		||||
                {
 | 
			
		||||
                    config.PropagateExceptions();
 | 
			
		||||
                    config.AddBranch<AnimalSettings>("animal", animal =>
 | 
			
		||||
                    {
 | 
			
		||||
                        animal.AddCommand<DogCommand>("dog");
 | 
			
		||||
                        animal.AddCommand<HorseCommand>("horse");
 | 
			
		||||
                    });
 | 
			
		||||
                    animal.AddCommand<DogCommand>("dog");
 | 
			
		||||
                    animal.AddCommand<HorseCommand>("horse");
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = Record.Exception(() => app.Run(new[] { "animal", "3", "dog", "7", "--name", "Rufus" }));
 | 
			
		||||
            // When
 | 
			
		||||
            var result = Record.Exception(() => app.Run(new[] { "animal", "3", "dog", "7", "--name", "Rufus" }));
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ShouldBeOfType<CommandRuntimeException>().And(e =>
 | 
			
		||||
                {
 | 
			
		||||
                    e.Message.ShouldBe("Animals must have an even number of legs.");
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Throw_If_Settings_Validation_Fails()
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ShouldBeOfType<CommandRuntimeException>().And(e =>
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var app = new CommandApp();
 | 
			
		||||
                app.Configure(config =>
 | 
			
		||||
                {
 | 
			
		||||
                    config.PropagateExceptions();
 | 
			
		||||
                    config.AddBranch<AnimalSettings>("animal", animal =>
 | 
			
		||||
                    {
 | 
			
		||||
                        animal.AddCommand<DogCommand>("dog");
 | 
			
		||||
                        animal.AddCommand<HorseCommand>("horse");
 | 
			
		||||
                    });
 | 
			
		||||
                });
 | 
			
		||||
                e.Message.ShouldBe("Animals must have an even number of legs.");
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = Record.Exception(() => app.Run(new[] { "animal", "4", "dog", "7", "--name", "Tiger" }));
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ShouldBeOfType<CommandRuntimeException>().And(e =>
 | 
			
		||||
                {
 | 
			
		||||
                    e.Message.ShouldBe("Tiger is not a dog name!");
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Throw_If_Command_Validation_Fails()
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Throw_If_Settings_Validation_Fails()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var app = new CommandApp();
 | 
			
		||||
            app.Configure(config =>
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var app = new CommandApp();
 | 
			
		||||
                app.Configure(config =>
 | 
			
		||||
                config.PropagateExceptions();
 | 
			
		||||
                config.AddBranch<AnimalSettings>("animal", animal =>
 | 
			
		||||
                {
 | 
			
		||||
                    config.PropagateExceptions();
 | 
			
		||||
                    config.AddBranch<AnimalSettings>("animal", animal =>
 | 
			
		||||
                    {
 | 
			
		||||
                        animal.AddCommand<DogCommand>("dog");
 | 
			
		||||
                        animal.AddCommand<HorseCommand>("horse");
 | 
			
		||||
                    });
 | 
			
		||||
                    animal.AddCommand<DogCommand>("dog");
 | 
			
		||||
                    animal.AddCommand<HorseCommand>("horse");
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = Record.Exception(() => app.Run(new[] { "animal", "4", "dog", "101", "--name", "Rufus" }));
 | 
			
		||||
            // When
 | 
			
		||||
            var result = Record.Exception(() => app.Run(new[] { "animal", "4", "dog", "7", "--name", "Tiger" }));
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ShouldBeOfType<CommandRuntimeException>().And(e =>
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ShouldBeOfType<CommandRuntimeException>().And(e =>
 | 
			
		||||
            {
 | 
			
		||||
                e.Message.ShouldBe("Tiger is not a dog name!");
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Throw_If_Command_Validation_Fails()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var app = new CommandApp();
 | 
			
		||||
            app.Configure(config =>
 | 
			
		||||
            {
 | 
			
		||||
                config.PropagateExceptions();
 | 
			
		||||
                config.AddBranch<AnimalSettings>("animal", animal =>
 | 
			
		||||
                {
 | 
			
		||||
                    e.Message.ShouldBe("Dog is too old...");
 | 
			
		||||
                    animal.AddCommand<DogCommand>("dog");
 | 
			
		||||
                    animal.AddCommand<HorseCommand>("horse");
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            var result = Record.Exception(() => app.Run(new[] { "animal", "4", "dog", "101", "--name", "Rufus" }));
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ShouldBeOfType<CommandRuntimeException>().And(e =>
 | 
			
		||||
            {
 | 
			
		||||
                e.Message.ShouldBe("Dog is too old...");
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,97 +1,88 @@
 | 
			
		||||
using System.ComponentModel;
 | 
			
		||||
using System.Globalization;
 | 
			
		||||
using Shouldly;
 | 
			
		||||
using Spectre.Console.Cli;
 | 
			
		||||
using Spectre.Console.Testing;
 | 
			
		||||
using Spectre.Console.Tests.Data;
 | 
			
		||||
using Xunit;
 | 
			
		||||
namespace Spectre.Console.Tests.Unit.Cli;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Unit.Cli
 | 
			
		||||
public sealed partial class CommandAppTests
 | 
			
		||||
{
 | 
			
		||||
    public sealed partial class CommandAppTests
 | 
			
		||||
    public sealed class ValueProviders
 | 
			
		||||
    {
 | 
			
		||||
        public sealed class ValueProviders
 | 
			
		||||
        public sealed class ValueProviderSettings : CommandSettings
 | 
			
		||||
        {
 | 
			
		||||
            public sealed class ValueProviderSettings : CommandSettings
 | 
			
		||||
            [CommandOption("-f|--foo <VALUE>")]
 | 
			
		||||
            [IntegerValueProvider(32)]
 | 
			
		||||
            [TypeConverter(typeof(HexConverter))]
 | 
			
		||||
            public string Foo { get; set; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public sealed class IntegerValueProvider : ParameterValueProviderAttribute
 | 
			
		||||
        {
 | 
			
		||||
            private readonly int _value;
 | 
			
		||||
 | 
			
		||||
            public IntegerValueProvider(int value)
 | 
			
		||||
            {
 | 
			
		||||
                [CommandOption("-f|--foo <VALUE>")]
 | 
			
		||||
                [IntegerValueProvider(32)]
 | 
			
		||||
                [TypeConverter(typeof(HexConverter))]
 | 
			
		||||
                public string Foo { get; set; }
 | 
			
		||||
                _value = value;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            public sealed class IntegerValueProvider : ParameterValueProviderAttribute
 | 
			
		||||
            public override bool TryGetValue(CommandParameterContext context, out object result)
 | 
			
		||||
            {
 | 
			
		||||
                private readonly int _value;
 | 
			
		||||
 | 
			
		||||
                public IntegerValueProvider(int value)
 | 
			
		||||
                if (context.Value == null)
 | 
			
		||||
                {
 | 
			
		||||
                    _value = value;
 | 
			
		||||
                    result = _value;
 | 
			
		||||
                    return true;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                public override bool TryGetValue(CommandParameterContext context, out object result)
 | 
			
		||||
                {
 | 
			
		||||
                    if (context.Value == null)
 | 
			
		||||
                    {
 | 
			
		||||
                        result = _value;
 | 
			
		||||
                        return true;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    result = null;
 | 
			
		||||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            public sealed class HexConverter : TypeConverter
 | 
			
		||||
            {
 | 
			
		||||
                public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
 | 
			
		||||
                {
 | 
			
		||||
                    if (value is int integer)
 | 
			
		||||
                    {
 | 
			
		||||
                        return integer.ToString("X");
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    return value is string stringValue && int.TryParse(stringValue, out var intValue)
 | 
			
		||||
                        ? intValue.ToString("X")
 | 
			
		||||
                        : base.ConvertFrom(context, culture, value);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Use_Provided_Value_If_No_Value_Was_Specified()
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var app = new CommandAppTester();
 | 
			
		||||
                app.SetDefaultCommand<GenericCommand<ValueProviderSettings>>();
 | 
			
		||||
                app.Configure(config => config.PropagateExceptions());
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = app.Run();
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.Settings.ShouldBeOfType<ValueProviderSettings>().And(settings =>
 | 
			
		||||
                {
 | 
			
		||||
                    settings.Foo.ShouldBe("20"); // 32 is 0x20
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Not_Override_Value_If_Value_Was_Specified()
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var app = new CommandAppTester();
 | 
			
		||||
                app.SetDefaultCommand<GenericCommand<ValueProviderSettings>>();
 | 
			
		||||
                app.Configure(config => config.PropagateExceptions());
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = app.Run("--foo", "12");
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.Settings.ShouldBeOfType<ValueProviderSettings>().And(settings =>
 | 
			
		||||
                {
 | 
			
		||||
                    settings.Foo.ShouldBe("C"); // 12 is 0xC
 | 
			
		||||
                });
 | 
			
		||||
                result = null;
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public sealed class HexConverter : TypeConverter
 | 
			
		||||
        {
 | 
			
		||||
            public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
 | 
			
		||||
            {
 | 
			
		||||
                if (value is int integer)
 | 
			
		||||
                {
 | 
			
		||||
                    return integer.ToString("X");
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                return value is string stringValue && int.TryParse(stringValue, out var intValue)
 | 
			
		||||
                    ? intValue.ToString("X")
 | 
			
		||||
                    : base.ConvertFrom(context, culture, value);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Use_Provided_Value_If_No_Value_Was_Specified()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var app = new CommandAppTester();
 | 
			
		||||
            app.SetDefaultCommand<GenericCommand<ValueProviderSettings>>();
 | 
			
		||||
            app.Configure(config => config.PropagateExceptions());
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            var result = app.Run();
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.Settings.ShouldBeOfType<ValueProviderSettings>().And(settings =>
 | 
			
		||||
            {
 | 
			
		||||
                settings.Foo.ShouldBe("20"); // 32 is 0x20
 | 
			
		||||
                });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Not_Override_Value_If_Value_Was_Specified()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var app = new CommandAppTester();
 | 
			
		||||
            app.SetDefaultCommand<GenericCommand<ValueProviderSettings>>();
 | 
			
		||||
            app.Configure(config => config.PropagateExceptions());
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            var result = app.Run("--foo", "12");
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.Settings.ShouldBeOfType<ValueProviderSettings>().And(settings =>
 | 
			
		||||
            {
 | 
			
		||||
                settings.Foo.ShouldBe("C"); // 12 is 0xC
 | 
			
		||||
                });
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,111 +1,104 @@
 | 
			
		||||
using Shouldly;
 | 
			
		||||
using Spectre.Console.Cli;
 | 
			
		||||
using Spectre.Console.Testing;
 | 
			
		||||
using Spectre.Console.Tests.Data;
 | 
			
		||||
using Xunit;
 | 
			
		||||
namespace Spectre.Console.Tests.Unit.Cli;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Unit.Cli
 | 
			
		||||
public sealed partial class CommandAppTests
 | 
			
		||||
{
 | 
			
		||||
    public sealed partial class CommandAppTests
 | 
			
		||||
    public sealed class Vectors
 | 
			
		||||
    {
 | 
			
		||||
        public sealed class Vectors
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Throw_If_A_Single_Command_Has_Multiple_Argument_Vectors()
 | 
			
		||||
        {
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Throw_If_A_Single_Command_Has_Multiple_Argument_Vectors()
 | 
			
		||||
            // Given
 | 
			
		||||
            var app = new CommandApp();
 | 
			
		||||
            app.Configure(config =>
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var app = new CommandApp();
 | 
			
		||||
                app.Configure(config =>
 | 
			
		||||
                {
 | 
			
		||||
                    config.PropagateExceptions();
 | 
			
		||||
                    config.AddCommand<GenericCommand<MultipleArgumentVectorSettings>>("multi");
 | 
			
		||||
                });
 | 
			
		||||
                config.PropagateExceptions();
 | 
			
		||||
                config.AddCommand<GenericCommand<MultipleArgumentVectorSettings>>("multi");
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = Record.Exception(() => app.Run(new[] { "multi", "a", "b", "c" }));
 | 
			
		||||
            // When
 | 
			
		||||
            var result = Record.Exception(() => app.Run(new[] { "multi", "a", "b", "c" }));
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ShouldBeOfType<CommandConfigurationException>().And(ex =>
 | 
			
		||||
                {
 | 
			
		||||
                    ex.Message.ShouldBe("The command 'multi' specifies more than one vector argument.");
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Throw_If_An_Argument_Vector_Is_Not_Specified_Last()
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ShouldBeOfType<CommandConfigurationException>().And(ex =>
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var app = new CommandApp();
 | 
			
		||||
                app.Configure(config =>
 | 
			
		||||
                {
 | 
			
		||||
                    config.PropagateExceptions();
 | 
			
		||||
                    config.AddCommand<GenericCommand<MultipleArgumentVectorSpecifiedFirstSettings>>("multi");
 | 
			
		||||
                });
 | 
			
		||||
                ex.Message.ShouldBe("The command 'multi' specifies more than one vector argument.");
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = Record.Exception(() => app.Run(new[] { "multi", "a", "b", "c" }));
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ShouldBeOfType<CommandConfigurationException>().And(ex =>
 | 
			
		||||
                {
 | 
			
		||||
                    ex.Message.ShouldBe("The command 'multi' specifies an argument vector that is not the last argument.");
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Assign_Values_To_Argument_Vector()
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Throw_If_An_Argument_Vector_Is_Not_Specified_Last()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var app = new CommandApp();
 | 
			
		||||
            app.Configure(config =>
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var app = new CommandAppTester();
 | 
			
		||||
                app.Configure(config =>
 | 
			
		||||
                {
 | 
			
		||||
                    config.PropagateExceptions();
 | 
			
		||||
                    config.AddCommand<GenericCommand<ArgumentVectorSettings>>("multi");
 | 
			
		||||
                });
 | 
			
		||||
                config.PropagateExceptions();
 | 
			
		||||
                config.AddCommand<GenericCommand<MultipleArgumentVectorSpecifiedFirstSettings>>("multi");
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = app.Run(new[]
 | 
			
		||||
                {
 | 
			
		||||
                    "multi", "a", "b", "c",
 | 
			
		||||
                });
 | 
			
		||||
            // When
 | 
			
		||||
            var result = Record.Exception(() => app.Run(new[] { "multi", "a", "b", "c" }));
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ExitCode.ShouldBe(0);
 | 
			
		||||
                result.Settings.ShouldBeOfType<ArgumentVectorSettings>().And(vec =>
 | 
			
		||||
                {
 | 
			
		||||
                    vec.Foo.Length.ShouldBe(3);
 | 
			
		||||
                    vec.Foo[0].ShouldBe("a");
 | 
			
		||||
                    vec.Foo[1].ShouldBe("b");
 | 
			
		||||
                    vec.Foo[2].ShouldBe("c");
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Assign_Values_To_Option_Vector()
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ShouldBeOfType<CommandConfigurationException>().And(ex =>
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var app = new CommandAppTester();
 | 
			
		||||
                app.Configure(config =>
 | 
			
		||||
                {
 | 
			
		||||
                    config.PropagateExceptions();
 | 
			
		||||
                    config.AddCommand<OptionVectorCommand>("cmd");
 | 
			
		||||
                });
 | 
			
		||||
                ex.Message.ShouldBe("The command 'multi' specifies an argument vector that is not the last argument.");
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = app.Run(new[]
 | 
			
		||||
                {
 | 
			
		||||
                    "cmd", "--foo", "red",
 | 
			
		||||
                    "--bar", "4", "--foo", "blue",
 | 
			
		||||
                });
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Assign_Values_To_Argument_Vector()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var app = new CommandAppTester();
 | 
			
		||||
            app.Configure(config =>
 | 
			
		||||
            {
 | 
			
		||||
                config.PropagateExceptions();
 | 
			
		||||
                config.AddCommand<GenericCommand<ArgumentVectorSettings>>("multi");
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ExitCode.ShouldBe(0);
 | 
			
		||||
                result.Settings.ShouldBeOfType<OptionVectorSettings>().And(vec =>
 | 
			
		||||
                {
 | 
			
		||||
                    vec.Foo.ShouldBe(new string[] { "red", "blue" });
 | 
			
		||||
                    vec.Bar.ShouldBe(new int[] { 4 });
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
            // When
 | 
			
		||||
            var result = app.Run(new[]
 | 
			
		||||
            {
 | 
			
		||||
                "multi", "a", "b", "c",
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ExitCode.ShouldBe(0);
 | 
			
		||||
            result.Settings.ShouldBeOfType<ArgumentVectorSettings>().And(vec =>
 | 
			
		||||
            {
 | 
			
		||||
                vec.Foo.Length.ShouldBe(3);
 | 
			
		||||
                vec.Foo[0].ShouldBe("a");
 | 
			
		||||
                vec.Foo[1].ShouldBe("b");
 | 
			
		||||
                vec.Foo[2].ShouldBe("c");
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Assign_Values_To_Option_Vector()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var app = new CommandAppTester();
 | 
			
		||||
            app.Configure(config =>
 | 
			
		||||
            {
 | 
			
		||||
                config.PropagateExceptions();
 | 
			
		||||
                config.AddCommand<OptionVectorCommand>("cmd");
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            var result = app.Run(new[]
 | 
			
		||||
            {
 | 
			
		||||
                "cmd", "--foo", "red",
 | 
			
		||||
                "--bar", "4", "--foo", "blue",
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ExitCode.ShouldBe(0);
 | 
			
		||||
            result.Settings.ShouldBeOfType<OptionVectorSettings>().And(vec =>
 | 
			
		||||
            {
 | 
			
		||||
                vec.Foo.ShouldBe(new string[] { "red", "blue" });
 | 
			
		||||
                vec.Bar.ShouldBe(new int[] { 4 });
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,37 +1,31 @@
 | 
			
		||||
using Shouldly;
 | 
			
		||||
using Spectre.Console.Testing;
 | 
			
		||||
using Spectre.Console.Tests.Data;
 | 
			
		||||
using Xunit;
 | 
			
		||||
namespace Spectre.Console.Tests.Unit.Cli;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Unit.Cli
 | 
			
		||||
public sealed partial class CommandAppTests
 | 
			
		||||
{
 | 
			
		||||
    public sealed partial class CommandAppTests
 | 
			
		||||
    public sealed class Version
 | 
			
		||||
    {
 | 
			
		||||
        public sealed class Version
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Output_The_Version_To_The_Console()
 | 
			
		||||
        {
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Output_The_Version_To_The_Console()
 | 
			
		||||
            // Given
 | 
			
		||||
            var fixture = new CommandAppTester();
 | 
			
		||||
            fixture.Configure(config =>
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var fixture = new CommandAppTester();
 | 
			
		||||
                fixture.Configure(config =>
 | 
			
		||||
                config.AddBranch<AnimalSettings>("animal", animal =>
 | 
			
		||||
                {
 | 
			
		||||
                    config.AddBranch<AnimalSettings>("animal", animal =>
 | 
			
		||||
                    animal.AddBranch<MammalSettings>("mammal", mammal =>
 | 
			
		||||
                    {
 | 
			
		||||
                        animal.AddBranch<MammalSettings>("mammal", mammal =>
 | 
			
		||||
                        {
 | 
			
		||||
                            mammal.AddCommand<DogCommand>("dog");
 | 
			
		||||
                            mammal.AddCommand<HorseCommand>("horse");
 | 
			
		||||
                        });
 | 
			
		||||
                        mammal.AddCommand<DogCommand>("dog");
 | 
			
		||||
                        mammal.AddCommand<HorseCommand>("horse");
 | 
			
		||||
                    });
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = fixture.Run(Constants.VersionCommand);
 | 
			
		||||
            // When
 | 
			
		||||
            var result = fixture.Run(Constants.VersionCommand);
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.Output.ShouldStartWith("Spectre.Cli version ");
 | 
			
		||||
            }
 | 
			
		||||
            // Then
 | 
			
		||||
            result.Output.ShouldStartWith("Spectre.Cli version ");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,157 +1,148 @@
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Spectre.Console.Cli;
 | 
			
		||||
using Spectre.Console.Testing;
 | 
			
		||||
using Spectre.Console.Tests.Data;
 | 
			
		||||
using Spectre.Verify.Extensions;
 | 
			
		||||
using VerifyXunit;
 | 
			
		||||
using Xunit;
 | 
			
		||||
namespace Spectre.Console.Tests.Unit.Cli;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Unit.Cli
 | 
			
		||||
public sealed partial class CommandAppTests
 | 
			
		||||
{
 | 
			
		||||
    public sealed partial class CommandAppTests
 | 
			
		||||
    [UsesVerify]
 | 
			
		||||
    [ExpectationPath("Cli/Xml")]
 | 
			
		||||
    public sealed class Xml
 | 
			
		||||
    {
 | 
			
		||||
        [UsesVerify]
 | 
			
		||||
        [ExpectationPath("Cli/Xml")]
 | 
			
		||||
        public sealed class Xml
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Test_1")]
 | 
			
		||||
        public Task Should_Dump_Correct_Model_For_Case_1()
 | 
			
		||||
        {
 | 
			
		||||
            [Fact]
 | 
			
		||||
            [Expectation("Test_1")]
 | 
			
		||||
            public Task Should_Dump_Correct_Model_For_Case_1()
 | 
			
		||||
            // Given
 | 
			
		||||
            var fixture = new CommandAppTester();
 | 
			
		||||
            fixture.Configure(config =>
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var fixture = new CommandAppTester();
 | 
			
		||||
                fixture.Configure(config =>
 | 
			
		||||
                config.PropagateExceptions();
 | 
			
		||||
                config.AddBranch<AnimalSettings>("animal", animal =>
 | 
			
		||||
                {
 | 
			
		||||
                    config.PropagateExceptions();
 | 
			
		||||
                    config.AddBranch<AnimalSettings>("animal", animal =>
 | 
			
		||||
                    animal.AddBranch<MammalSettings>("mammal", mammal =>
 | 
			
		||||
                    {
 | 
			
		||||
                        animal.AddBranch<MammalSettings>("mammal", mammal =>
 | 
			
		||||
                        {
 | 
			
		||||
                            mammal.AddCommand<DogCommand>("dog");
 | 
			
		||||
                            mammal.AddCommand<HorseCommand>("horse");
 | 
			
		||||
                        });
 | 
			
		||||
                        mammal.AddCommand<DogCommand>("dog");
 | 
			
		||||
                        mammal.AddCommand<HorseCommand>("horse");
 | 
			
		||||
                    });
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = fixture.Run(Constants.XmlDocCommand);
 | 
			
		||||
            // When
 | 
			
		||||
            var result = fixture.Run(Constants.XmlDocCommand);
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                return Verifier.Verify(result.Output);
 | 
			
		||||
            }
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(result.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            [Expectation("Test_2")]
 | 
			
		||||
            public Task Should_Dump_Correct_Model_For_Case_2()
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Test_2")]
 | 
			
		||||
        public Task Should_Dump_Correct_Model_For_Case_2()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var fixture = new CommandAppTester();
 | 
			
		||||
            fixture.Configure(config =>
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var fixture = new CommandAppTester();
 | 
			
		||||
                fixture.Configure(config =>
 | 
			
		||||
                config.AddCommand<DogCommand>("dog");
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            var result = fixture.Run(Constants.XmlDocCommand);
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(result.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Test_3")]
 | 
			
		||||
        public Task Should_Dump_Correct_Model_For_Case_3()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var fixture = new CommandAppTester();
 | 
			
		||||
            fixture.Configure(config =>
 | 
			
		||||
            {
 | 
			
		||||
                config.AddBranch<AnimalSettings>("animal", animal =>
 | 
			
		||||
                {
 | 
			
		||||
                    config.AddCommand<DogCommand>("dog");
 | 
			
		||||
                    animal.AddCommand<DogCommand>("dog");
 | 
			
		||||
                    animal.AddCommand<HorseCommand>("horse");
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = fixture.Run(Constants.XmlDocCommand);
 | 
			
		||||
            // When
 | 
			
		||||
            var result = fixture.Run(Constants.XmlDocCommand);
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                return Verifier.Verify(result.Output);
 | 
			
		||||
            }
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(result.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            [Expectation("Test_3")]
 | 
			
		||||
            public Task Should_Dump_Correct_Model_For_Case_3()
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Test_4")]
 | 
			
		||||
        public Task Should_Dump_Correct_Model_For_Case_4()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var fixture = new CommandAppTester();
 | 
			
		||||
            fixture.Configure(config =>
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var fixture = new CommandAppTester();
 | 
			
		||||
                fixture.Configure(config =>
 | 
			
		||||
                config.AddBranch<AnimalSettings>("animal", animal =>
 | 
			
		||||
                {
 | 
			
		||||
                    config.AddBranch<AnimalSettings>("animal", animal =>
 | 
			
		||||
                    {
 | 
			
		||||
                        animal.AddCommand<DogCommand>("dog");
 | 
			
		||||
                        animal.AddCommand<HorseCommand>("horse");
 | 
			
		||||
                    });
 | 
			
		||||
                    animal.AddCommand<DogCommand>("dog");
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = fixture.Run(Constants.XmlDocCommand);
 | 
			
		||||
            // When
 | 
			
		||||
            var result = fixture.Run(Constants.XmlDocCommand);
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                return Verifier.Verify(result.Output);
 | 
			
		||||
            }
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(result.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            [Expectation("Test_4")]
 | 
			
		||||
            public Task Should_Dump_Correct_Model_For_Case_4()
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Test_5")]
 | 
			
		||||
        public Task Should_Dump_Correct_Model_For_Case_5()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var fixture = new CommandAppTester();
 | 
			
		||||
            fixture.Configure(config =>
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var fixture = new CommandAppTester();
 | 
			
		||||
                fixture.Configure(config =>
 | 
			
		||||
                {
 | 
			
		||||
                    config.AddBranch<AnimalSettings>("animal", animal =>
 | 
			
		||||
                    {
 | 
			
		||||
                        animal.AddCommand<DogCommand>("dog");
 | 
			
		||||
                    });
 | 
			
		||||
                });
 | 
			
		||||
                config.AddCommand<OptionVectorCommand>("cmd");
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = fixture.Run(Constants.XmlDocCommand);
 | 
			
		||||
            // When
 | 
			
		||||
            var result = fixture.Run(Constants.XmlDocCommand);
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                return Verifier.Verify(result.Output);
 | 
			
		||||
            }
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(result.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            [Expectation("Test_5")]
 | 
			
		||||
            public Task Should_Dump_Correct_Model_For_Case_5()
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Test_6")]
 | 
			
		||||
        public Task Should_Dump_Correct_Model_For_Model_With_Default_Command()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var fixture = new CommandAppTester();
 | 
			
		||||
            fixture.SetDefaultCommand<DogCommand>();
 | 
			
		||||
            fixture.Configure(config =>
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var fixture = new CommandAppTester();
 | 
			
		||||
                fixture.Configure(config =>
 | 
			
		||||
                {
 | 
			
		||||
                    config.AddCommand<OptionVectorCommand>("cmd");
 | 
			
		||||
                });
 | 
			
		||||
                config.AddCommand<HorseCommand>("horse");
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = fixture.Run(Constants.XmlDocCommand);
 | 
			
		||||
            // When
 | 
			
		||||
            var result = fixture.Run(Constants.XmlDocCommand);
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                return Verifier.Verify(result.Output);
 | 
			
		||||
            }
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(result.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            [Expectation("Test_6")]
 | 
			
		||||
            public Task Should_Dump_Correct_Model_For_Model_With_Default_Command()
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var fixture = new CommandAppTester();
 | 
			
		||||
                fixture.SetDefaultCommand<DogCommand>();
 | 
			
		||||
                fixture.Configure(config =>
 | 
			
		||||
                {
 | 
			
		||||
                    config.AddCommand<HorseCommand>("horse");
 | 
			
		||||
                });
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Hidden_Command_Options")]
 | 
			
		||||
        public Task Should_Not_Dump_Hidden_Options_On_A_Command()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var fixture = new CommandAppTester();
 | 
			
		||||
            fixture.SetDefaultCommand<HiddenOptionsCommand>();
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = fixture.Run(Constants.XmlDocCommand);
 | 
			
		||||
            // When
 | 
			
		||||
            var result = fixture.Run(Constants.XmlDocCommand);
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                return Verifier.Verify(result.Output);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            [Expectation("Hidden_Command_Options")]
 | 
			
		||||
            public Task Should_Not_Dump_Hidden_Options_On_A_Command()
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var fixture = new CommandAppTester();
 | 
			
		||||
                fixture.SetDefaultCommand<HiddenOptionsCommand>();
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = fixture.Run(Constants.XmlDocCommand);
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                return Verifier.Verify(result.Output);
 | 
			
		||||
            }
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(result.Output);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -1,16 +1,11 @@
 | 
			
		||||
using Spectre.Console.Cli;
 | 
			
		||||
using Spectre.Console.Testing;
 | 
			
		||||
using Xunit;
 | 
			
		||||
namespace Spectre.Console.Tests.Unit.Cli;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Unit.Cli
 | 
			
		||||
public sealed class DefaultTypeRegistrarTests
 | 
			
		||||
{
 | 
			
		||||
    public sealed class DefaultTypeRegistrarTests
 | 
			
		||||
    [Fact]
 | 
			
		||||
    public void Should_Pass_Base_Registrar_Tests()
 | 
			
		||||
    {
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Pass_Base_Registrar_Tests()
 | 
			
		||||
        {
 | 
			
		||||
            var harness = new TypeRegistrarBaseTests(() => new DefaultTypeRegistrar());
 | 
			
		||||
            harness.RunAllTests();
 | 
			
		||||
        }
 | 
			
		||||
        var harness = new TypeRegistrarBaseTests(() => new DefaultTypeRegistrar());
 | 
			
		||||
        harness.RunAllTests();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,23 +1,19 @@
 | 
			
		||||
using Shouldly;
 | 
			
		||||
using Xunit;
 | 
			
		||||
namespace Spectre.Console.Tests.Unit;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Unit
 | 
			
		||||
public sealed class ColorSystemTests
 | 
			
		||||
{
 | 
			
		||||
    public sealed class ColorSystemTests
 | 
			
		||||
    [Theory]
 | 
			
		||||
    [InlineData(ColorSystem.NoColors, ColorSystemSupport.NoColors)]
 | 
			
		||||
    [InlineData(ColorSystem.Legacy, ColorSystemSupport.Legacy)]
 | 
			
		||||
    [InlineData(ColorSystem.Standard, ColorSystemSupport.Standard)]
 | 
			
		||||
    [InlineData(ColorSystem.EightBit, ColorSystemSupport.EightBit)]
 | 
			
		||||
    [InlineData(ColorSystem.TrueColor, ColorSystemSupport.TrueColor)]
 | 
			
		||||
    public void Should_Be_Analog_To_ColorSystemSupport(ColorSystem colors, ColorSystemSupport support)
 | 
			
		||||
    {
 | 
			
		||||
        [Theory]
 | 
			
		||||
        [InlineData(ColorSystem.NoColors, ColorSystemSupport.NoColors)]
 | 
			
		||||
        [InlineData(ColorSystem.Legacy, ColorSystemSupport.Legacy)]
 | 
			
		||||
        [InlineData(ColorSystem.Standard, ColorSystemSupport.Standard)]
 | 
			
		||||
        [InlineData(ColorSystem.EightBit, ColorSystemSupport.EightBit)]
 | 
			
		||||
        [InlineData(ColorSystem.TrueColor, ColorSystemSupport.TrueColor)]
 | 
			
		||||
        public void Should_Be_Analog_To_ColorSystemSupport(ColorSystem colors, ColorSystemSupport support)
 | 
			
		||||
        {
 | 
			
		||||
            // Given, When
 | 
			
		||||
            var result = (int)colors;
 | 
			
		||||
        // Given, When
 | 
			
		||||
        var result = (int)colors;
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ShouldBe((int)support);
 | 
			
		||||
        }
 | 
			
		||||
        // Then
 | 
			
		||||
        result.ShouldBe((int)support);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,287 +1,280 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using Shouldly;
 | 
			
		||||
using Xunit;
 | 
			
		||||
namespace Spectre.Console.Tests.Unit;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Unit
 | 
			
		||||
public sealed class ColorTests
 | 
			
		||||
{
 | 
			
		||||
    public sealed class ColorTests
 | 
			
		||||
    public sealed class TheEqualsMethod
 | 
			
		||||
    {
 | 
			
		||||
        public sealed class TheEqualsMethod
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Consider_Color_And_Non_Color_Equal()
 | 
			
		||||
        {
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Consider_Color_And_Non_Color_Equal()
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var color1 = new Color(128, 0, 128);
 | 
			
		||||
            // Given
 | 
			
		||||
            var color1 = new Color(128, 0, 128);
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = color1.Equals("Foo");
 | 
			
		||||
            // When
 | 
			
		||||
            var result = color1.Equals("Foo");
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ShouldBeFalse();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Consider_Same_Colors_Equal_By_Component()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var color1 = new Color(128, 0, 128);
 | 
			
		||||
            var color2 = new Color(128, 0, 128);
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            var result = color1.Equals(color2);
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ShouldBeTrue();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Consider_Same_Known_Colors_Equal()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var color1 = Color.Cyan1;
 | 
			
		||||
            var color2 = Color.Cyan1;
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            var result = color1.Equals(color2);
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ShouldBeTrue();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Consider_Known_Color_And_Color_With_Same_Components_Equal()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var color1 = Color.Cyan1;
 | 
			
		||||
            var color2 = new Color(0, 255, 255);
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            var result = color1.Equals(color2);
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ShouldBeTrue();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Not_Consider_Different_Colors_Equal()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var color1 = new Color(128, 0, 128);
 | 
			
		||||
            var color2 = new Color(128, 128, 128);
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            var result = color1.Equals(color2);
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ShouldBeFalse();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Shourd_Not_Consider_Black_And_Default_Colors_Equal()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var color1 = Color.Default;
 | 
			
		||||
            var color2 = Color.Black;
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            var result = color1.Equals(color2);
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ShouldBeFalse();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public sealed class TheGetHashCodeMethod
 | 
			
		||||
    {
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Return_Same_HashCode_For_Same_Colors()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var color1 = new Color(128, 0, 128);
 | 
			
		||||
            var color2 = new Color(128, 0, 128);
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            var hash1 = color1.GetHashCode();
 | 
			
		||||
            var hash2 = color2.GetHashCode();
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            hash1.ShouldBe(hash2);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Return_Different_HashCode_For_Different_Colors()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var color1 = new Color(128, 0, 128);
 | 
			
		||||
            var color2 = new Color(128, 128, 128);
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            var hash1 = color1.GetHashCode();
 | 
			
		||||
            var hash2 = color2.GetHashCode();
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            hash1.ShouldNotBe(hash2);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public sealed class ImplicitConversions
 | 
			
		||||
    {
 | 
			
		||||
        public sealed class Int32ToColor
 | 
			
		||||
        {
 | 
			
		||||
            public static IEnumerable<object[]> Data =>
 | 
			
		||||
                Enumerable.Range(0, 255)
 | 
			
		||||
                    .Select(number => new object[] { number });
 | 
			
		||||
 | 
			
		||||
            [Theory]
 | 
			
		||||
            [MemberData(nameof(Data))]
 | 
			
		||||
            public void Should_Return_Expected_Color(int number)
 | 
			
		||||
            {
 | 
			
		||||
                // Given, When
 | 
			
		||||
                var result = (Color)number;
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ShouldBeFalse();
 | 
			
		||||
                result.ShouldBe(Color.FromInt32(number));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Consider_Same_Colors_Equal_By_Component()
 | 
			
		||||
            public void Should_Throw_If_Integer_Is_Lower_Than_Zero()
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var color1 = new Color(128, 0, 128);
 | 
			
		||||
                var color2 = new Color(128, 0, 128);
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = color1.Equals(color2);
 | 
			
		||||
                // Given, When
 | 
			
		||||
                var result = Record.Exception(() => (Color)(-1));
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ShouldBeTrue();
 | 
			
		||||
                result.ShouldBeOfType<InvalidOperationException>();
 | 
			
		||||
                result.Message.ShouldBe("Color number must be between 0 and 255");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Consider_Same_Known_Colors_Equal()
 | 
			
		||||
            public void Should_Throw_If_Integer_Is_Higher_Than_255()
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var color1 = Color.Cyan1;
 | 
			
		||||
                var color2 = Color.Cyan1;
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = color1.Equals(color2);
 | 
			
		||||
                // Given, When
 | 
			
		||||
                var result = Record.Exception(() => (Color)256);
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ShouldBeTrue();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Consider_Known_Color_And_Color_With_Same_Components_Equal()
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var color1 = Color.Cyan1;
 | 
			
		||||
                var color2 = new Color(0, 255, 255);
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = color1.Equals(color2);
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ShouldBeTrue();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Not_Consider_Different_Colors_Equal()
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var color1 = new Color(128, 0, 128);
 | 
			
		||||
                var color2 = new Color(128, 128, 128);
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = color1.Equals(color2);
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ShouldBeFalse();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Shourd_Not_Consider_Black_And_Default_Colors_Equal()
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var color1 = Color.Default;
 | 
			
		||||
                var color2 = Color.Black;
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = color1.Equals(color2);
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ShouldBeFalse();
 | 
			
		||||
                result.ShouldBeOfType<InvalidOperationException>();
 | 
			
		||||
                result.Message.ShouldBe("Color number must be between 0 and 255");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public sealed class TheGetHashCodeMethod
 | 
			
		||||
        public sealed class ConsoleColorToColor
 | 
			
		||||
        {
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Return_Same_HashCode_For_Same_Colors()
 | 
			
		||||
            [Theory]
 | 
			
		||||
            [InlineData(ConsoleColor.Black, 0)]
 | 
			
		||||
            [InlineData(ConsoleColor.DarkRed, 1)]
 | 
			
		||||
            [InlineData(ConsoleColor.DarkGreen, 2)]
 | 
			
		||||
            [InlineData(ConsoleColor.DarkYellow, 3)]
 | 
			
		||||
            [InlineData(ConsoleColor.DarkBlue, 4)]
 | 
			
		||||
            [InlineData(ConsoleColor.DarkMagenta, 5)]
 | 
			
		||||
            [InlineData(ConsoleColor.DarkCyan, 6)]
 | 
			
		||||
            [InlineData(ConsoleColor.Gray, 7)]
 | 
			
		||||
            [InlineData(ConsoleColor.DarkGray, 8)]
 | 
			
		||||
            [InlineData(ConsoleColor.Red, 9)]
 | 
			
		||||
            [InlineData(ConsoleColor.Green, 10)]
 | 
			
		||||
            [InlineData(ConsoleColor.Yellow, 11)]
 | 
			
		||||
            [InlineData(ConsoleColor.Blue, 12)]
 | 
			
		||||
            [InlineData(ConsoleColor.Magenta, 13)]
 | 
			
		||||
            [InlineData(ConsoleColor.Cyan, 14)]
 | 
			
		||||
            [InlineData(ConsoleColor.White, 15)]
 | 
			
		||||
            public void Should_Return_Expected_Color(ConsoleColor color, int expected)
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var color1 = new Color(128, 0, 128);
 | 
			
		||||
                var color2 = new Color(128, 0, 128);
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var hash1 = color1.GetHashCode();
 | 
			
		||||
                var hash2 = color2.GetHashCode();
 | 
			
		||||
                // Given, When
 | 
			
		||||
                var result = (Color)color;
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                hash1.ShouldBe(hash2);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Return_Different_HashCode_For_Different_Colors()
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var color1 = new Color(128, 0, 128);
 | 
			
		||||
                var color2 = new Color(128, 128, 128);
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var hash1 = color1.GetHashCode();
 | 
			
		||||
                var hash2 = color2.GetHashCode();
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                hash1.ShouldNotBe(hash2);
 | 
			
		||||
                result.ShouldBe(Color.FromInt32(expected));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public sealed class ImplicitConversions
 | 
			
		||||
        public sealed class ColorToConsoleColor
 | 
			
		||||
        {
 | 
			
		||||
            public sealed class Int32ToColor
 | 
			
		||||
            {
 | 
			
		||||
                public static IEnumerable<object[]> Data =>
 | 
			
		||||
                    Enumerable.Range(0, 255)
 | 
			
		||||
                        .Select(number => new object[] { number });
 | 
			
		||||
 | 
			
		||||
                [Theory]
 | 
			
		||||
                [MemberData(nameof(Data))]
 | 
			
		||||
                public void Should_Return_Expected_Color(int number)
 | 
			
		||||
                {
 | 
			
		||||
                    // Given, When
 | 
			
		||||
                    var result = (Color)number;
 | 
			
		||||
 | 
			
		||||
                    // Then
 | 
			
		||||
                    result.ShouldBe(Color.FromInt32(number));
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                [Fact]
 | 
			
		||||
                public void Should_Throw_If_Integer_Is_Lower_Than_Zero()
 | 
			
		||||
                {
 | 
			
		||||
                    // Given, When
 | 
			
		||||
                    var result = Record.Exception(() => (Color)(-1));
 | 
			
		||||
 | 
			
		||||
                    // Then
 | 
			
		||||
                    result.ShouldBeOfType<InvalidOperationException>();
 | 
			
		||||
                    result.Message.ShouldBe("Color number must be between 0 and 255");
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                [Fact]
 | 
			
		||||
                public void Should_Throw_If_Integer_Is_Higher_Than_255()
 | 
			
		||||
                {
 | 
			
		||||
                    // Given, When
 | 
			
		||||
                    var result = Record.Exception(() => (Color)256);
 | 
			
		||||
 | 
			
		||||
                    // Then
 | 
			
		||||
                    result.ShouldBeOfType<InvalidOperationException>();
 | 
			
		||||
                    result.Message.ShouldBe("Color number must be between 0 and 255");
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            public sealed class ConsoleColorToColor
 | 
			
		||||
            {
 | 
			
		||||
                [Theory]
 | 
			
		||||
                [InlineData(ConsoleColor.Black, 0)]
 | 
			
		||||
                [InlineData(ConsoleColor.DarkRed, 1)]
 | 
			
		||||
                [InlineData(ConsoleColor.DarkGreen, 2)]
 | 
			
		||||
                [InlineData(ConsoleColor.DarkYellow, 3)]
 | 
			
		||||
                [InlineData(ConsoleColor.DarkBlue, 4)]
 | 
			
		||||
                [InlineData(ConsoleColor.DarkMagenta, 5)]
 | 
			
		||||
                [InlineData(ConsoleColor.DarkCyan, 6)]
 | 
			
		||||
                [InlineData(ConsoleColor.Gray, 7)]
 | 
			
		||||
                [InlineData(ConsoleColor.DarkGray, 8)]
 | 
			
		||||
                [InlineData(ConsoleColor.Red, 9)]
 | 
			
		||||
                [InlineData(ConsoleColor.Green, 10)]
 | 
			
		||||
                [InlineData(ConsoleColor.Yellow, 11)]
 | 
			
		||||
                [InlineData(ConsoleColor.Blue, 12)]
 | 
			
		||||
                [InlineData(ConsoleColor.Magenta, 13)]
 | 
			
		||||
                [InlineData(ConsoleColor.Cyan, 14)]
 | 
			
		||||
                [InlineData(ConsoleColor.White, 15)]
 | 
			
		||||
                public void Should_Return_Expected_Color(ConsoleColor color, int expected)
 | 
			
		||||
                {
 | 
			
		||||
                    // Given, When
 | 
			
		||||
                    var result = (Color)color;
 | 
			
		||||
 | 
			
		||||
                    // Then
 | 
			
		||||
                    result.ShouldBe(Color.FromInt32(expected));
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            public sealed class ColorToConsoleColor
 | 
			
		||||
            {
 | 
			
		||||
                [Theory]
 | 
			
		||||
                [InlineData(0, ConsoleColor.Black)]
 | 
			
		||||
                [InlineData(1, ConsoleColor.DarkRed)]
 | 
			
		||||
                [InlineData(2, ConsoleColor.DarkGreen)]
 | 
			
		||||
                [InlineData(3, ConsoleColor.DarkYellow)]
 | 
			
		||||
                [InlineData(4, ConsoleColor.DarkBlue)]
 | 
			
		||||
                [InlineData(5, ConsoleColor.DarkMagenta)]
 | 
			
		||||
                [InlineData(6, ConsoleColor.DarkCyan)]
 | 
			
		||||
                [InlineData(7, ConsoleColor.Gray)]
 | 
			
		||||
                [InlineData(8, ConsoleColor.DarkGray)]
 | 
			
		||||
                [InlineData(9, ConsoleColor.Red)]
 | 
			
		||||
                [InlineData(10, ConsoleColor.Green)]
 | 
			
		||||
                [InlineData(11, ConsoleColor.Yellow)]
 | 
			
		||||
                [InlineData(12, ConsoleColor.Blue)]
 | 
			
		||||
                [InlineData(13, ConsoleColor.Magenta)]
 | 
			
		||||
                [InlineData(14, ConsoleColor.Cyan)]
 | 
			
		||||
                [InlineData(15, ConsoleColor.White)]
 | 
			
		||||
                public void Should_Return_Expected_ConsoleColor_For_Known_Color(int color, ConsoleColor expected)
 | 
			
		||||
                {
 | 
			
		||||
                    // Given, When
 | 
			
		||||
                    var result = (ConsoleColor)Color.FromInt32(color);
 | 
			
		||||
 | 
			
		||||
                    // Then
 | 
			
		||||
                    result.ShouldBe(expected);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public sealed class TheToMarkupMethod
 | 
			
		||||
        {
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Return_Expected_Markup_For_Default_Color()
 | 
			
		||||
            [Theory]
 | 
			
		||||
            [InlineData(0, ConsoleColor.Black)]
 | 
			
		||||
            [InlineData(1, ConsoleColor.DarkRed)]
 | 
			
		||||
            [InlineData(2, ConsoleColor.DarkGreen)]
 | 
			
		||||
            [InlineData(3, ConsoleColor.DarkYellow)]
 | 
			
		||||
            [InlineData(4, ConsoleColor.DarkBlue)]
 | 
			
		||||
            [InlineData(5, ConsoleColor.DarkMagenta)]
 | 
			
		||||
            [InlineData(6, ConsoleColor.DarkCyan)]
 | 
			
		||||
            [InlineData(7, ConsoleColor.Gray)]
 | 
			
		||||
            [InlineData(8, ConsoleColor.DarkGray)]
 | 
			
		||||
            [InlineData(9, ConsoleColor.Red)]
 | 
			
		||||
            [InlineData(10, ConsoleColor.Green)]
 | 
			
		||||
            [InlineData(11, ConsoleColor.Yellow)]
 | 
			
		||||
            [InlineData(12, ConsoleColor.Blue)]
 | 
			
		||||
            [InlineData(13, ConsoleColor.Magenta)]
 | 
			
		||||
            [InlineData(14, ConsoleColor.Cyan)]
 | 
			
		||||
            [InlineData(15, ConsoleColor.White)]
 | 
			
		||||
            public void Should_Return_Expected_ConsoleColor_For_Known_Color(int color, ConsoleColor expected)
 | 
			
		||||
            {
 | 
			
		||||
                // Given, When
 | 
			
		||||
                var result = Color.Default.ToMarkup();
 | 
			
		||||
                var result = (ConsoleColor)Color.FromInt32(color);
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ShouldBe("default");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Return_Expected_Markup_For_Known_Color()
 | 
			
		||||
            {
 | 
			
		||||
                // Given, When
 | 
			
		||||
                var result = Color.Red.ToMarkup();
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ShouldBe("red");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Return_Expected_Markup_For_Custom_Color()
 | 
			
		||||
            {
 | 
			
		||||
                // Given, When
 | 
			
		||||
                var result = new Color(255, 1, 12).ToMarkup();
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ShouldBe("#FF010C");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public sealed class TheToStringMethod
 | 
			
		||||
        {
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Return_Color_Name_For_Known_Colors()
 | 
			
		||||
            {
 | 
			
		||||
                // Given, When
 | 
			
		||||
                var name = Color.Fuchsia.ToString();
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                name.ShouldBe("fuchsia");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Return_Hex_String_For_Unknown_Colors()
 | 
			
		||||
            {
 | 
			
		||||
                // Given, When
 | 
			
		||||
                var name = new Color(128, 0, 128).ToString();
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                name.ShouldBe("#800080 (RGB=128,0,128)");
 | 
			
		||||
                result.ShouldBe(expected);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    public sealed class TheToMarkupMethod
 | 
			
		||||
    {
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Return_Expected_Markup_For_Default_Color()
 | 
			
		||||
        {
 | 
			
		||||
            // Given, When
 | 
			
		||||
            var result = Color.Default.ToMarkup();
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ShouldBe("default");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Return_Expected_Markup_For_Known_Color()
 | 
			
		||||
        {
 | 
			
		||||
            // Given, When
 | 
			
		||||
            var result = Color.Red.ToMarkup();
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ShouldBe("red");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Return_Expected_Markup_For_Custom_Color()
 | 
			
		||||
        {
 | 
			
		||||
            // Given, When
 | 
			
		||||
            var result = new Color(255, 1, 12).ToMarkup();
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ShouldBe("#FF010C");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public sealed class TheToStringMethod
 | 
			
		||||
    {
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Return_Color_Name_For_Known_Colors()
 | 
			
		||||
        {
 | 
			
		||||
            // Given, When
 | 
			
		||||
            var name = Color.Fuchsia.ToString();
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            name.ShouldBe("fuchsia");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Return_Hex_String_For_Unknown_Colors()
 | 
			
		||||
        {
 | 
			
		||||
            // Given, When
 | 
			
		||||
            var name = new Color(128, 0, 128).ToString();
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            name.ShouldBe("#800080 (RGB=128,0,128)");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,96 +1,91 @@
 | 
			
		||||
using Shouldly;
 | 
			
		||||
using Spectre.Console.Testing;
 | 
			
		||||
using Xunit;
 | 
			
		||||
namespace Spectre.Console.Tests.Unit;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Unit
 | 
			
		||||
public sealed class EmojiTests
 | 
			
		||||
{
 | 
			
		||||
    public sealed class EmojiTests
 | 
			
		||||
    [Fact]
 | 
			
		||||
    public void Should_Substitute_Emoji_Shortcodes_In_Markdown()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole();
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.Markup("Hello :globe_showing_europe_africa:!");
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        console.Output.ShouldBe("Hello 🌍!");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    public void Should_Contain_Predefined_Emojis()
 | 
			
		||||
    {
 | 
			
		||||
        // Given, When
 | 
			
		||||
        const string result = "Hello " + Emoji.Known.GlobeShowingEuropeAfrica + "!";
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        result.ShouldBe("Hello 🌍!");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public sealed class TheReplaceMethod
 | 
			
		||||
    {
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Substitute_Emoji_Shortcodes_In_Markdown()
 | 
			
		||||
        public void Should_Replace_Emojis_In_Text()
 | 
			
		||||
        {
 | 
			
		||||
            // Given, When
 | 
			
		||||
            var result = Emoji.Replace("Hello :globe_showing_europe_africa:!");
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ShouldBe("Hello 🌍!");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public sealed class Parsing
 | 
			
		||||
    {
 | 
			
		||||
        [Theory]
 | 
			
		||||
        [InlineData(":", ":")]
 | 
			
		||||
        [InlineData("::", "::")]
 | 
			
		||||
        [InlineData(":::", ":::")]
 | 
			
		||||
        [InlineData("::::", "::::")]
 | 
			
		||||
        [InlineData("::i:", "::i:")]
 | 
			
		||||
        [InlineData(":i:i:", ":i:i:")]
 | 
			
		||||
        [InlineData("::globe_showing_europe_africa::", ":🌍:")]
 | 
			
		||||
        [InlineData(":globe_showing_europe_africa::globe_showing_europe_africa:", "🌍🌍")]
 | 
			
		||||
        [InlineData("::globe_showing_europe_africa:::test:::globe_showing_europe_africa:::", ":🌍::test::🌍::")]
 | 
			
		||||
        public void Can_Handle_Different_Combinations(string markup, string expected)
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Markup("Hello :globe_showing_europe_africa:!");
 | 
			
		||||
            console.Markup(markup);
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            console.Output.ShouldBe("Hello 🌍!");
 | 
			
		||||
            console.Output.ShouldBe(expected);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Contain_Predefined_Emojis()
 | 
			
		||||
        public void Should_Leave_Single_Colons()
 | 
			
		||||
        {
 | 
			
		||||
            // Given, When
 | 
			
		||||
            const string result = "Hello " + Emoji.Known.GlobeShowingEuropeAfrica + "!";
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Markup("Hello :globe_showing_europe_africa:! Output: good");
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ShouldBe("Hello 🌍!");
 | 
			
		||||
            console.Output.ShouldBe("Hello 🌍! Output: good");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public sealed class TheReplaceMethod
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Unknown_emojis_should_remain_unchanged()
 | 
			
		||||
        {
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Replace_Emojis_In_Text()
 | 
			
		||||
            {
 | 
			
		||||
                // Given, When
 | 
			
		||||
                var result = Emoji.Replace("Hello :globe_showing_europe_africa:!");
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ShouldBe("Hello 🌍!");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
            // When
 | 
			
		||||
            console.Markup("Hello :globe_showing_flat_earth:!");
 | 
			
		||||
 | 
			
		||||
        public sealed class Parsing
 | 
			
		||||
        {
 | 
			
		||||
            [Theory]
 | 
			
		||||
            [InlineData(":", ":")]
 | 
			
		||||
            [InlineData("::", "::")]
 | 
			
		||||
            [InlineData(":::", ":::")]
 | 
			
		||||
            [InlineData("::::", "::::")]
 | 
			
		||||
            [InlineData("::i:", "::i:")]
 | 
			
		||||
            [InlineData(":i:i:", ":i:i:")]
 | 
			
		||||
            [InlineData("::globe_showing_europe_africa::", ":🌍:")]
 | 
			
		||||
            [InlineData(":globe_showing_europe_africa::globe_showing_europe_africa:", "🌍🌍")]
 | 
			
		||||
            [InlineData("::globe_showing_europe_africa:::test:::globe_showing_europe_africa:::", ":🌍::test::🌍::")]
 | 
			
		||||
            public void Can_Handle_Different_Combinations(string markup, string expected)
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var console = new TestConsole();
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                console.Markup(markup);
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                console.Output.ShouldBe(expected);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Leave_Single_Colons()
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var console = new TestConsole();
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                console.Markup("Hello :globe_showing_europe_africa:! Output: good");
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                console.Output.ShouldBe("Hello 🌍! Output: good");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Unknown_emojis_should_remain_unchanged()
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var console = new TestConsole();
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                console.Markup("Hello :globe_showing_flat_earth:!");
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                console.Output.ShouldBe("Hello :globe_showing_flat_earth:!");
 | 
			
		||||
            }
 | 
			
		||||
            // Then
 | 
			
		||||
            console.Output.ShouldBe("Hello :globe_showing_flat_earth:!");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,104 +1,95 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Spectre.Console.Testing;
 | 
			
		||||
using Spectre.Console.Tests.Data;
 | 
			
		||||
using Spectre.Verify.Extensions;
 | 
			
		||||
using VerifyXunit;
 | 
			
		||||
using Xunit;
 | 
			
		||||
namespace Spectre.Console.Tests.Unit;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Unit
 | 
			
		||||
[UsesVerify]
 | 
			
		||||
[ExpectationPath("Exception")]
 | 
			
		||||
public sealed class ExceptionTests
 | 
			
		||||
{
 | 
			
		||||
    [UsesVerify]
 | 
			
		||||
    [ExpectationPath("Exception")]
 | 
			
		||||
    public sealed class ExceptionTests
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("Default")]
 | 
			
		||||
    public Task Should_Write_Exception()
 | 
			
		||||
    {
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Default")]
 | 
			
		||||
        public Task Should_Write_Exception()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole().Width(1024);
 | 
			
		||||
            var dex = GetException(() => TestExceptions.MethodThatThrows(null));
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole().Width(1024);
 | 
			
		||||
        var dex = GetException(() => TestExceptions.MethodThatThrows(null));
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            var result = console.WriteNormalizedException(dex);
 | 
			
		||||
        // When
 | 
			
		||||
        var result = console.WriteNormalizedException(dex);
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(result);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("ShortenedTypes")]
 | 
			
		||||
        public Task Should_Write_Exception_With_Shortened_Types()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole().Width(1024);
 | 
			
		||||
            var dex = GetException(() => TestExceptions.MethodThatThrows(null));
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            var result = console.WriteNormalizedException(dex, ExceptionFormats.ShortenTypes);
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(result);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("ShortenedMethods")]
 | 
			
		||||
        public Task Should_Write_Exception_With_Shortened_Methods()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole().Width(1024);
 | 
			
		||||
            var dex = GetException(() => TestExceptions.MethodThatThrows(null));
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            var result = console.WriteNormalizedException(dex, ExceptionFormats.ShortenMethods);
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(result);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("InnerException")]
 | 
			
		||||
        public Task Should_Write_Exception_With_Inner_Exception()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole().Width(1024);
 | 
			
		||||
            var dex = GetException(() => TestExceptions.ThrowWithInnerException());
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            var result = console.WriteNormalizedException(dex);
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(result);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("CallSite")]
 | 
			
		||||
        public Task Should_Write_Exceptions_With_Generic_Type_Parameters_In_Callsite_As_Expected()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole().Width(1024);
 | 
			
		||||
            var dex = GetException(() => TestExceptions.ThrowWithGenericInnerException());
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            var result = console.WriteNormalizedException(dex);
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(result);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static Exception GetException(Action action)
 | 
			
		||||
        {
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                action?.Invoke();
 | 
			
		||||
            }
 | 
			
		||||
            catch (Exception e)
 | 
			
		||||
            {
 | 
			
		||||
                return e;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            throw new InvalidOperationException("Exception harness failed");
 | 
			
		||||
        }
 | 
			
		||||
        // Then
 | 
			
		||||
        return Verifier.Verify(result);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("ShortenedTypes")]
 | 
			
		||||
    public Task Should_Write_Exception_With_Shortened_Types()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole().Width(1024);
 | 
			
		||||
        var dex = GetException(() => TestExceptions.MethodThatThrows(null));
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        var result = console.WriteNormalizedException(dex, ExceptionFormats.ShortenTypes);
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        return Verifier.Verify(result);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("ShortenedMethods")]
 | 
			
		||||
    public Task Should_Write_Exception_With_Shortened_Methods()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole().Width(1024);
 | 
			
		||||
        var dex = GetException(() => TestExceptions.MethodThatThrows(null));
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        var result = console.WriteNormalizedException(dex, ExceptionFormats.ShortenMethods);
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        return Verifier.Verify(result);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("InnerException")]
 | 
			
		||||
    public Task Should_Write_Exception_With_Inner_Exception()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole().Width(1024);
 | 
			
		||||
        var dex = GetException(() => TestExceptions.ThrowWithInnerException());
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        var result = console.WriteNormalizedException(dex);
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        return Verifier.Verify(result);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("CallSite")]
 | 
			
		||||
    public Task Should_Write_Exceptions_With_Generic_Type_Parameters_In_Callsite_As_Expected()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole().Width(1024);
 | 
			
		||||
        var dex = GetException(() => TestExceptions.ThrowWithGenericInnerException());
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        var result = console.WriteNormalizedException(dex);
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        return Verifier.Verify(result);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static Exception GetException(Action action)
 | 
			
		||||
    {
 | 
			
		||||
        try
 | 
			
		||||
        {
 | 
			
		||||
            action?.Invoke();
 | 
			
		||||
        }
 | 
			
		||||
        catch (Exception e)
 | 
			
		||||
        {
 | 
			
		||||
            return e;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        throw new InvalidOperationException("Exception harness failed");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,30 +1,25 @@
 | 
			
		||||
using System.Globalization;
 | 
			
		||||
using Shouldly;
 | 
			
		||||
using Xunit;
 | 
			
		||||
namespace Spectre.Console.Tests.Unit;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Unit
 | 
			
		||||
public sealed class DownloadedColumnTests
 | 
			
		||||
{
 | 
			
		||||
    public sealed class DownloadedColumnTests
 | 
			
		||||
    [Theory]
 | 
			
		||||
    [InlineData(0, 1, "0/1 byte")]
 | 
			
		||||
    [InlineData(37, 101, "37/101 bytes")]
 | 
			
		||||
    [InlineData(101, 101, "101 bytes")]
 | 
			
		||||
    [InlineData(512, 1024, "0.5/1.0 KB")]
 | 
			
		||||
    [InlineData(1024, 1024, "1.0 KB")]
 | 
			
		||||
    [InlineData(1024 * 512, 5 * 1024 * 1024, "0.5/5.0 MB")]
 | 
			
		||||
    [InlineData(5 * 1024 * 1024, 5 * 1024 * 1024, "5.0 MB")]
 | 
			
		||||
    public void Should_Return_Correct_Value(double value, double total, string expected)
 | 
			
		||||
    {
 | 
			
		||||
        [Theory]
 | 
			
		||||
        [InlineData(0, 1, "0/1 byte")]
 | 
			
		||||
        [InlineData(37, 101, "37/101 bytes")]
 | 
			
		||||
        [InlineData(101, 101, "101 bytes")]
 | 
			
		||||
        [InlineData(512, 1024, "0.5/1.0 KB")]
 | 
			
		||||
        [InlineData(1024, 1024, "1.0 KB")]
 | 
			
		||||
        [InlineData(1024 * 512, 5 * 1024 * 1024, "0.5/5.0 MB")]
 | 
			
		||||
        [InlineData(5 * 1024 * 1024, 5 * 1024 * 1024, "5.0 MB")]
 | 
			
		||||
        public void Should_Return_Correct_Value(double value, double total, string expected)
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var fixture = new ProgressColumnFixture<DownloadedColumn>(value, total);
 | 
			
		||||
            fixture.Column.Culture = CultureInfo.InvariantCulture;
 | 
			
		||||
        // Given
 | 
			
		||||
        var fixture = new ProgressColumnFixture<DownloadedColumn>(value, total);
 | 
			
		||||
        fixture.Column.Culture = CultureInfo.InvariantCulture;
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            var result = fixture.Render();
 | 
			
		||||
        // When
 | 
			
		||||
        var result = fixture.Render();
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ShouldBe(expected);
 | 
			
		||||
        }
 | 
			
		||||
        // Then
 | 
			
		||||
        result.ShouldBe(expected);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,28 +1,23 @@
 | 
			
		||||
using System;
 | 
			
		||||
using Spectre.Console.Rendering;
 | 
			
		||||
using Spectre.Console.Testing;
 | 
			
		||||
namespace Spectre.Console.Tests.Unit;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Unit
 | 
			
		||||
public sealed class ProgressColumnFixture<T>
 | 
			
		||||
    where T : ProgressColumn, new()
 | 
			
		||||
{
 | 
			
		||||
    public sealed class ProgressColumnFixture<T>
 | 
			
		||||
        where T : ProgressColumn, new()
 | 
			
		||||
    public T Column { get; }
 | 
			
		||||
    public ProgressTask Task { get; set; }
 | 
			
		||||
 | 
			
		||||
    public ProgressColumnFixture(double completed, double total)
 | 
			
		||||
    {
 | 
			
		||||
        public T Column { get; }
 | 
			
		||||
        public ProgressTask Task { get; set; }
 | 
			
		||||
 | 
			
		||||
        public ProgressColumnFixture(double completed, double total)
 | 
			
		||||
        {
 | 
			
		||||
            Column = new T();
 | 
			
		||||
            Task = new ProgressTask(1, "Foo", total);
 | 
			
		||||
            Task.Increment(completed);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public string Render()
 | 
			
		||||
        {
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
            var context = new RenderContext(console.Profile.Capabilities);
 | 
			
		||||
            console.Write(Column.Render(context, Task, TimeSpan.Zero));
 | 
			
		||||
            return console.Output;
 | 
			
		||||
        }
 | 
			
		||||
        Column = new T();
 | 
			
		||||
        Task = new ProgressTask(1, "Foo", total);
 | 
			
		||||
        Task.Increment(completed);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    public string Render()
 | 
			
		||||
    {
 | 
			
		||||
        var console = new TestConsole();
 | 
			
		||||
        var context = new RenderContext(console.Profile.Capabilities);
 | 
			
		||||
        console.Write(Column.Render(context, Task, TimeSpan.Zero));
 | 
			
		||||
        return console.Output;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,275 +1,267 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Shouldly;
 | 
			
		||||
using Spectre.Console.Testing;
 | 
			
		||||
using Spectre.Verify.Extensions;
 | 
			
		||||
using VerifyXunit;
 | 
			
		||||
using Xunit;
 | 
			
		||||
namespace Spectre.Console.Tests.Unit;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Unit
 | 
			
		||||
[UsesVerify]
 | 
			
		||||
[ExpectationPath("Live/Progress")]
 | 
			
		||||
public sealed class ProgressTests
 | 
			
		||||
{
 | 
			
		||||
    [UsesVerify]
 | 
			
		||||
    [ExpectationPath("Live/Progress")]
 | 
			
		||||
    public sealed class ProgressTests
 | 
			
		||||
    [Fact]
 | 
			
		||||
    public void Should_Render_Task_Correctly()
 | 
			
		||||
    {
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Render_Task_Correctly()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole()
 | 
			
		||||
                .Width(10)
 | 
			
		||||
                .Interactive()
 | 
			
		||||
                .EmitAnsiSequences();
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole()
 | 
			
		||||
            .Width(10)
 | 
			
		||||
            .Interactive()
 | 
			
		||||
            .EmitAnsiSequences();
 | 
			
		||||
 | 
			
		||||
            var progress = new Progress(console)
 | 
			
		||||
                .Columns(new[] { new ProgressBarColumn() })
 | 
			
		||||
                .AutoRefresh(false)
 | 
			
		||||
                .AutoClear(true);
 | 
			
		||||
        var progress = new Progress(console)
 | 
			
		||||
            .Columns(new[] { new ProgressBarColumn() })
 | 
			
		||||
            .AutoRefresh(false)
 | 
			
		||||
            .AutoClear(true);
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            progress.Start(ctx => ctx.AddTask("foo"));
 | 
			
		||||
        // When
 | 
			
		||||
        progress.Start(ctx => ctx.AddTask("foo"));
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            console.Output
 | 
			
		||||
                .NormalizeLineEndings()
 | 
			
		||||
                .ShouldBe(
 | 
			
		||||
                    "[?25l" + // Hide cursor
 | 
			
		||||
                    "          \n" + // Top padding
 | 
			
		||||
                    "[38;5;8m━━━━━━━━━━[0m\n" + // Task
 | 
			
		||||
                    "          " + // Bottom padding
 | 
			
		||||
                    "[2K[1A[2K[1A[2K[?25h"); // Clear + show cursor
 | 
			
		||||
        }
 | 
			
		||||
        // Then
 | 
			
		||||
        console.Output
 | 
			
		||||
            .NormalizeLineEndings()
 | 
			
		||||
            .ShouldBe(
 | 
			
		||||
                "[?25l" + // Hide cursor
 | 
			
		||||
                "          \n" + // Top padding
 | 
			
		||||
                "[38;5;8m━━━━━━━━━━[0m\n" + // Task
 | 
			
		||||
                "          " + // Bottom padding
 | 
			
		||||
                "[2K[1A[2K[1A[2K[?25h"); // Clear + show cursor
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Not_Auto_Clear_If_Specified()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole()
 | 
			
		||||
                .Width(10)
 | 
			
		||||
                .Interactive()
 | 
			
		||||
                .EmitAnsiSequences();
 | 
			
		||||
    [Fact]
 | 
			
		||||
    public void Should_Not_Auto_Clear_If_Specified()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole()
 | 
			
		||||
            .Width(10)
 | 
			
		||||
            .Interactive()
 | 
			
		||||
            .EmitAnsiSequences();
 | 
			
		||||
 | 
			
		||||
            var progress = new Progress(console)
 | 
			
		||||
                .Columns(new[] { new ProgressBarColumn() })
 | 
			
		||||
                .AutoRefresh(false)
 | 
			
		||||
                .AutoClear(false);
 | 
			
		||||
        var progress = new Progress(console)
 | 
			
		||||
            .Columns(new[] { new ProgressBarColumn() })
 | 
			
		||||
            .AutoRefresh(false)
 | 
			
		||||
            .AutoClear(false);
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            progress.Start(ctx => ctx.AddTask("foo"));
 | 
			
		||||
        // When
 | 
			
		||||
        progress.Start(ctx => ctx.AddTask("foo"));
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            console.Output
 | 
			
		||||
                .NormalizeLineEndings()
 | 
			
		||||
                .ShouldBe(
 | 
			
		||||
                    "[?25l" + // Hide cursor
 | 
			
		||||
                    "          \n" + // Top padding
 | 
			
		||||
                    "[38;5;8m━━━━━━━━━━[0m\n" + // Task
 | 
			
		||||
                    "          \n" + // Bottom padding
 | 
			
		||||
                    "[?25h"); // show cursor
 | 
			
		||||
        }
 | 
			
		||||
        // Then
 | 
			
		||||
        console.Output
 | 
			
		||||
            .NormalizeLineEndings()
 | 
			
		||||
            .ShouldBe(
 | 
			
		||||
                "[?25l" + // Hide cursor
 | 
			
		||||
                "          \n" + // Top padding
 | 
			
		||||
                "[38;5;8m━━━━━━━━━━[0m\n" + // Task
 | 
			
		||||
                "          \n" + // Bottom padding
 | 
			
		||||
                "[?25h"); // show cursor
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Render_ReduceWidth")]
 | 
			
		||||
        public Task Should_Reduce_Width_If_Needed()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole()
 | 
			
		||||
                .Width(20)
 | 
			
		||||
                .Interactive();
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("Render_ReduceWidth")]
 | 
			
		||||
    public Task Should_Reduce_Width_If_Needed()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole()
 | 
			
		||||
            .Width(20)
 | 
			
		||||
            .Interactive();
 | 
			
		||||
 | 
			
		||||
            var progress = new Progress(console)
 | 
			
		||||
                .Columns(new ProgressColumn[]
 | 
			
		||||
                {
 | 
			
		||||
        var progress = new Progress(console)
 | 
			
		||||
            .Columns(new ProgressColumn[]
 | 
			
		||||
            {
 | 
			
		||||
                    new TaskDescriptionColumn(),
 | 
			
		||||
                    new ProgressBarColumn(),
 | 
			
		||||
                    new PercentageColumn(),
 | 
			
		||||
                    new RemainingTimeColumn(),
 | 
			
		||||
                    new SpinnerColumn(),
 | 
			
		||||
                })
 | 
			
		||||
                .AutoRefresh(false)
 | 
			
		||||
                .AutoClear(false);
 | 
			
		||||
            })
 | 
			
		||||
            .AutoRefresh(false)
 | 
			
		||||
            .AutoClear(false);
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            progress.Start(ctx =>
 | 
			
		||||
            {
 | 
			
		||||
                ctx.AddTask("foo");
 | 
			
		||||
                ctx.AddTask("bar");
 | 
			
		||||
                ctx.AddTask("baz");
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Setting_Max_Value_Should_Set_The_MaxValue_And_Cap_Value()
 | 
			
		||||
        // When
 | 
			
		||||
        progress.Start(ctx =>
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole()
 | 
			
		||||
                .Interactive();
 | 
			
		||||
            ctx.AddTask("foo");
 | 
			
		||||
            ctx.AddTask("bar");
 | 
			
		||||
            ctx.AddTask("baz");
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
            var task = default(ProgressTask);
 | 
			
		||||
            var progress = new Progress(console)
 | 
			
		||||
                .Columns(new[] { new ProgressBarColumn() })
 | 
			
		||||
                .AutoRefresh(false)
 | 
			
		||||
                .AutoClear(false);
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            progress.Start(ctx =>
 | 
			
		||||
            {
 | 
			
		||||
                task = ctx.AddTask("foo");
 | 
			
		||||
                task.Increment(100);
 | 
			
		||||
                task.MaxValue = 20;
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            task.MaxValue.ShouldBe(20);
 | 
			
		||||
            task.Value.ShouldBe(20);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Setting_Value_Should_Override_Incremented_Value()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole()
 | 
			
		||||
                .Interactive();
 | 
			
		||||
 | 
			
		||||
            var task = default(ProgressTask);
 | 
			
		||||
            var progress = new Progress(console)
 | 
			
		||||
                .Columns(new[] { new ProgressBarColumn() })
 | 
			
		||||
                .AutoRefresh(false)
 | 
			
		||||
                .AutoClear(false);
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            progress.Start(ctx =>
 | 
			
		||||
            {
 | 
			
		||||
                task = ctx.AddTask("foo");
 | 
			
		||||
                task.Increment(50);
 | 
			
		||||
                task.Value = 20;
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            task.MaxValue.ShouldBe(100);
 | 
			
		||||
            task.Value.ShouldBe(20);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Setting_Value_To_MaxValue_Should_Finish_Task()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole()
 | 
			
		||||
                .Interactive();
 | 
			
		||||
 | 
			
		||||
            var task = default(ProgressTask);
 | 
			
		||||
            var progress = new Progress(console)
 | 
			
		||||
                .Columns(new[] { new ProgressBarColumn() })
 | 
			
		||||
                .AutoRefresh(false)
 | 
			
		||||
                .AutoClear(false);
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            progress.Start(ctx =>
 | 
			
		||||
            {
 | 
			
		||||
                task = ctx.AddTask("foo");
 | 
			
		||||
                task.Value = task.MaxValue;
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            task.IsFinished.ShouldBe(true);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Increment_Manually_Set_Value()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole()
 | 
			
		||||
                .Interactive();
 | 
			
		||||
 | 
			
		||||
            var task = default(ProgressTask);
 | 
			
		||||
            var progress = new Progress(console)
 | 
			
		||||
                .Columns(new[] { new ProgressBarColumn() })
 | 
			
		||||
                .AutoRefresh(false)
 | 
			
		||||
                .AutoClear(false);
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            progress.Start(ctx =>
 | 
			
		||||
            {
 | 
			
		||||
                task = ctx.AddTask("foo");
 | 
			
		||||
                task.Value = 50;
 | 
			
		||||
                task.Increment(10);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            task.Value.ShouldBe(60);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Hide_Completed_Tasks()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole()
 | 
			
		||||
                .Width(10)
 | 
			
		||||
                .Interactive()
 | 
			
		||||
                .EmitAnsiSequences();
 | 
			
		||||
 | 
			
		||||
            var taskFinished = default(ProgressTask);
 | 
			
		||||
            var taskInProgress1 = default(ProgressTask);
 | 
			
		||||
            var taskInProgress2 = default(ProgressTask);
 | 
			
		||||
 | 
			
		||||
            var progress = new Progress(console)
 | 
			
		||||
                .Columns(new[] { new ProgressBarColumn() })
 | 
			
		||||
                .AutoRefresh(false)
 | 
			
		||||
                .AutoClear(false)
 | 
			
		||||
                .HideCompleted(true);
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            progress.Start(ctx =>
 | 
			
		||||
            {
 | 
			
		||||
                taskInProgress1 = ctx.AddTask("foo");
 | 
			
		||||
                taskFinished = ctx.AddTask("bar");
 | 
			
		||||
                taskInProgress2 = ctx.AddTask("baz");
 | 
			
		||||
                taskInProgress2.Increment(20);
 | 
			
		||||
                taskFinished.Value = taskFinished.MaxValue;
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            console.Output
 | 
			
		||||
                .NormalizeLineEndings()
 | 
			
		||||
                .ShouldBe(
 | 
			
		||||
                    "[?25l" + // Hide cursor
 | 
			
		||||
                    "          \n" + // top padding
 | 
			
		||||
                    "[38;5;8m━━━━━━━━━━[0m\n" + // taskInProgress1
 | 
			
		||||
                    "[38;5;11m━━[0m[38;5;8m━━━━━━━━[0m\n" + // taskInProgress2
 | 
			
		||||
                    "          \n" + // bottom padding
 | 
			
		||||
                    "[?25h"); // show cursor
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Report_Max_Remaining_Time_For_Extremely_Small_Progress()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole()
 | 
			
		||||
                .Interactive();
 | 
			
		||||
 | 
			
		||||
            var task = default(ProgressTask);
 | 
			
		||||
            var progress = new Progress(console)
 | 
			
		||||
                .Columns(new[] { new RemainingTimeColumn() })
 | 
			
		||||
                .AutoRefresh(false)
 | 
			
		||||
                .AutoClear(false);
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            progress.Start(ctx =>
 | 
			
		||||
            {
 | 
			
		||||
                task = ctx.AddTask("foo");
 | 
			
		||||
                task.Increment(double.Epsilon);
 | 
			
		||||
                // Make sure that at least one millisecond has elapsed between the increments else the RemainingTime is null
 | 
			
		||||
                // when the last timestamp is equal to the first timestamp of the samples.
 | 
			
		||||
                Thread.Sleep(1);
 | 
			
		||||
                task.Increment(double.Epsilon);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            task.RemainingTime.ShouldBe(TimeSpan.MaxValue);
 | 
			
		||||
        }
 | 
			
		||||
        // Then
 | 
			
		||||
        return Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    public void Setting_Max_Value_Should_Set_The_MaxValue_And_Cap_Value()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole()
 | 
			
		||||
            .Interactive();
 | 
			
		||||
 | 
			
		||||
        var task = default(ProgressTask);
 | 
			
		||||
        var progress = new Progress(console)
 | 
			
		||||
            .Columns(new[] { new ProgressBarColumn() })
 | 
			
		||||
            .AutoRefresh(false)
 | 
			
		||||
            .AutoClear(false);
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        progress.Start(ctx =>
 | 
			
		||||
        {
 | 
			
		||||
            task = ctx.AddTask("foo");
 | 
			
		||||
            task.Increment(100);
 | 
			
		||||
            task.MaxValue = 20;
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        task.MaxValue.ShouldBe(20);
 | 
			
		||||
        task.Value.ShouldBe(20);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    public void Setting_Value_Should_Override_Incremented_Value()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole()
 | 
			
		||||
            .Interactive();
 | 
			
		||||
 | 
			
		||||
        var task = default(ProgressTask);
 | 
			
		||||
        var progress = new Progress(console)
 | 
			
		||||
            .Columns(new[] { new ProgressBarColumn() })
 | 
			
		||||
            .AutoRefresh(false)
 | 
			
		||||
            .AutoClear(false);
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        progress.Start(ctx =>
 | 
			
		||||
        {
 | 
			
		||||
            task = ctx.AddTask("foo");
 | 
			
		||||
            task.Increment(50);
 | 
			
		||||
            task.Value = 20;
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        task.MaxValue.ShouldBe(100);
 | 
			
		||||
        task.Value.ShouldBe(20);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    public void Setting_Value_To_MaxValue_Should_Finish_Task()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole()
 | 
			
		||||
            .Interactive();
 | 
			
		||||
 | 
			
		||||
        var task = default(ProgressTask);
 | 
			
		||||
        var progress = new Progress(console)
 | 
			
		||||
            .Columns(new[] { new ProgressBarColumn() })
 | 
			
		||||
            .AutoRefresh(false)
 | 
			
		||||
            .AutoClear(false);
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        progress.Start(ctx =>
 | 
			
		||||
        {
 | 
			
		||||
            task = ctx.AddTask("foo");
 | 
			
		||||
            task.Value = task.MaxValue;
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        task.IsFinished.ShouldBe(true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    public void Should_Increment_Manually_Set_Value()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole()
 | 
			
		||||
            .Interactive();
 | 
			
		||||
 | 
			
		||||
        var task = default(ProgressTask);
 | 
			
		||||
        var progress = new Progress(console)
 | 
			
		||||
            .Columns(new[] { new ProgressBarColumn() })
 | 
			
		||||
            .AutoRefresh(false)
 | 
			
		||||
            .AutoClear(false);
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        progress.Start(ctx =>
 | 
			
		||||
        {
 | 
			
		||||
            task = ctx.AddTask("foo");
 | 
			
		||||
            task.Value = 50;
 | 
			
		||||
            task.Increment(10);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        task.Value.ShouldBe(60);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    public void Should_Hide_Completed_Tasks()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole()
 | 
			
		||||
            .Width(10)
 | 
			
		||||
            .Interactive()
 | 
			
		||||
            .EmitAnsiSequences();
 | 
			
		||||
 | 
			
		||||
        var taskFinished = default(ProgressTask);
 | 
			
		||||
        var taskInProgress1 = default(ProgressTask);
 | 
			
		||||
        var taskInProgress2 = default(ProgressTask);
 | 
			
		||||
 | 
			
		||||
        var progress = new Progress(console)
 | 
			
		||||
            .Columns(new[] { new ProgressBarColumn() })
 | 
			
		||||
            .AutoRefresh(false)
 | 
			
		||||
            .AutoClear(false)
 | 
			
		||||
            .HideCompleted(true);
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        progress.Start(ctx =>
 | 
			
		||||
        {
 | 
			
		||||
            taskInProgress1 = ctx.AddTask("foo");
 | 
			
		||||
            taskFinished = ctx.AddTask("bar");
 | 
			
		||||
            taskInProgress2 = ctx.AddTask("baz");
 | 
			
		||||
            taskInProgress2.Increment(20);
 | 
			
		||||
            taskFinished.Value = taskFinished.MaxValue;
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        console.Output
 | 
			
		||||
            .NormalizeLineEndings()
 | 
			
		||||
            .ShouldBe(
 | 
			
		||||
                "[?25l" + // Hide cursor
 | 
			
		||||
                "          \n" + // top padding
 | 
			
		||||
                "[38;5;8m━━━━━━━━━━[0m\n" + // taskInProgress1
 | 
			
		||||
                "[38;5;11m━━[0m[38;5;8m━━━━━━━━[0m\n" + // taskInProgress2
 | 
			
		||||
                "          \n" + // bottom padding
 | 
			
		||||
                "[?25h"); // show cursor
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    public void Should_Report_Max_Remaining_Time_For_Extremely_Small_Progress()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole()
 | 
			
		||||
            .Interactive();
 | 
			
		||||
 | 
			
		||||
        var task = default(ProgressTask);
 | 
			
		||||
        var progress = new Progress(console)
 | 
			
		||||
            .Columns(new[] { new RemainingTimeColumn() })
 | 
			
		||||
            .AutoRefresh(false)
 | 
			
		||||
            .AutoClear(false);
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        progress.Start(ctx =>
 | 
			
		||||
        {
 | 
			
		||||
            task = ctx.AddTask("foo");
 | 
			
		||||
            task.Increment(double.Epsilon);
 | 
			
		||||
 | 
			
		||||
            // Make sure that at least one millisecond has elapsed between the increments else the RemainingTime is null
 | 
			
		||||
            // when the last timestamp is equal to the first timestamp of the samples.
 | 
			
		||||
            Thread.Sleep(1);
 | 
			
		||||
 | 
			
		||||
            task.Increment(double.Epsilon);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        task.RemainingTime.ShouldBe(TimeSpan.MaxValue);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,61 +1,52 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Spectre.Console.Testing;
 | 
			
		||||
using Spectre.Verify.Extensions;
 | 
			
		||||
using VerifyXunit;
 | 
			
		||||
using Xunit;
 | 
			
		||||
namespace Spectre.Console.Tests.Unit;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Unit
 | 
			
		||||
[UsesVerify]
 | 
			
		||||
[ExpectationPath("Live/Status")]
 | 
			
		||||
public sealed class StatusTests
 | 
			
		||||
{
 | 
			
		||||
    [UsesVerify]
 | 
			
		||||
    [ExpectationPath("Live/Status")]
 | 
			
		||||
    public sealed class StatusTests
 | 
			
		||||
    public sealed class DummySpinner1 : Spinner
 | 
			
		||||
    {
 | 
			
		||||
        public sealed class DummySpinner1 : Spinner
 | 
			
		||||
        {
 | 
			
		||||
            public override TimeSpan Interval => TimeSpan.FromMilliseconds(100);
 | 
			
		||||
            public override bool IsUnicode => true;
 | 
			
		||||
            public override IReadOnlyList<string> Frames => new List<string> { "*", };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public sealed class DummySpinner2 : Spinner
 | 
			
		||||
        {
 | 
			
		||||
            public override TimeSpan Interval => TimeSpan.FromMilliseconds(100);
 | 
			
		||||
            public override bool IsUnicode => true;
 | 
			
		||||
            public override IReadOnlyList<string> Frames => new List<string> { "-", };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Render")]
 | 
			
		||||
        public Task Should_Render_Status_Correctly()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole()
 | 
			
		||||
                .Colors(ColorSystem.TrueColor)
 | 
			
		||||
                .Width(10)
 | 
			
		||||
                .Interactive()
 | 
			
		||||
                .EmitAnsiSequences();
 | 
			
		||||
 | 
			
		||||
            var status = new Status(console)
 | 
			
		||||
            {
 | 
			
		||||
                AutoRefresh = false,
 | 
			
		||||
                Spinner = new DummySpinner1(),
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            status.Start("foo", ctx =>
 | 
			
		||||
            {
 | 
			
		||||
                ctx.Refresh();
 | 
			
		||||
                ctx.Spinner(new DummySpinner2());
 | 
			
		||||
                ctx.Status("bar");
 | 
			
		||||
                ctx.Refresh();
 | 
			
		||||
                ctx.Spinner(new DummySpinner1());
 | 
			
		||||
                ctx.Status("baz");
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
        public override TimeSpan Interval => TimeSpan.FromMilliseconds(100);
 | 
			
		||||
        public override bool IsUnicode => true;
 | 
			
		||||
        public override IReadOnlyList<string> Frames => new List<string> { "*", };
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    public sealed class DummySpinner2 : Spinner
 | 
			
		||||
    {
 | 
			
		||||
        public override TimeSpan Interval => TimeSpan.FromMilliseconds(100);
 | 
			
		||||
        public override bool IsUnicode => true;
 | 
			
		||||
        public override IReadOnlyList<string> Frames => new List<string> { "-", };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("Render")]
 | 
			
		||||
    public Task Should_Render_Status_Correctly()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole()
 | 
			
		||||
            .Colors(ColorSystem.TrueColor)
 | 
			
		||||
            .Width(10)
 | 
			
		||||
            .Interactive()
 | 
			
		||||
            .EmitAnsiSequences();
 | 
			
		||||
 | 
			
		||||
        var status = new Status(console)
 | 
			
		||||
        {
 | 
			
		||||
            AutoRefresh = false,
 | 
			
		||||
            Spinner = new DummySpinner1(),
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        status.Start("foo", ctx =>
 | 
			
		||||
        {
 | 
			
		||||
            ctx.Refresh();
 | 
			
		||||
            ctx.Spinner(new DummySpinner2());
 | 
			
		||||
            ctx.Status("bar");
 | 
			
		||||
            ctx.Refresh();
 | 
			
		||||
            ctx.Spinner(new DummySpinner1());
 | 
			
		||||
            ctx.Status("baz");
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        return Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,156 +1,149 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Diagnostics.CodeAnalysis;
 | 
			
		||||
using Shouldly;
 | 
			
		||||
using Xunit;
 | 
			
		||||
namespace Spectre.Console.Tests.Unit;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Unit
 | 
			
		||||
public sealed class MultiSelectionPromptTests
 | 
			
		||||
{
 | 
			
		||||
    public sealed class MultiSelectionPromptTests
 | 
			
		||||
    private class CustomItem
 | 
			
		||||
    {
 | 
			
		||||
        private class CustomItem
 | 
			
		||||
        public int X { get; set; }
 | 
			
		||||
        public int Y { get; set; }
 | 
			
		||||
 | 
			
		||||
        public class Comparer : IEqualityComparer<CustomItem>
 | 
			
		||||
        {
 | 
			
		||||
            public int X { get; set; }
 | 
			
		||||
            public int Y { get; set; }
 | 
			
		||||
 | 
			
		||||
            public class Comparer : IEqualityComparer<CustomItem>
 | 
			
		||||
            public bool Equals(CustomItem x, CustomItem y)
 | 
			
		||||
            {
 | 
			
		||||
                public bool Equals(CustomItem x, CustomItem y)
 | 
			
		||||
                {
 | 
			
		||||
                    return x.X == y.X && x.Y == y.Y;
 | 
			
		||||
                }
 | 
			
		||||
                return x.X == y.X && x.Y == y.Y;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
                public int GetHashCode([DisallowNull] CustomItem obj)
 | 
			
		||||
                {
 | 
			
		||||
                    throw new NotImplementedException();
 | 
			
		||||
                }
 | 
			
		||||
            public int GetHashCode([DisallowNull] CustomItem obj)
 | 
			
		||||
            {
 | 
			
		||||
                throw new NotSupportedException();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Not_Mark_Item_As_Selected_By_Default()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var prompt = new MultiSelectionPrompt<int>();
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            var choice = prompt.AddChoice(32);
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            choice.IsSelected.ShouldBeFalse();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Mark_Item_As_Selected()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var prompt = new MultiSelectionPrompt<int>();
 | 
			
		||||
            var choice = prompt.AddChoice(32);
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            prompt.Select(32);
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            choice.IsSelected.ShouldBeTrue();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Mark_Custom_Item_As_Selected_If_The_Same_Reference_Is_Used()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var prompt = new MultiSelectionPrompt<CustomItem>();
 | 
			
		||||
            var item = new CustomItem { X = 18, Y = 32 };
 | 
			
		||||
            var choice = prompt.AddChoice(item);
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            prompt.Select(item);
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            choice.IsSelected.ShouldBeTrue();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Mark_Custom_Item_As_Selected_If_A_Comparer_Is_Provided()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var prompt = new MultiSelectionPrompt<CustomItem>(new CustomItem.Comparer());
 | 
			
		||||
            var choice = prompt.AddChoice(new CustomItem { X = 18, Y = 32 });
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            prompt.Select(new CustomItem { X = 18, Y = 32 });
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            choice.IsSelected.ShouldBeTrue();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Get_The_Direct_Parent()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var prompt = new MultiSelectionPrompt<string>();
 | 
			
		||||
            prompt.AddChoice("root").AddChild("level-1").AddChild("level-2").AddChild("item");
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            var actual = prompt.GetParent("item");
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            actual.ShouldBe("level-2");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Get_The_List_Of_All_Parents()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var prompt = new MultiSelectionPrompt<string>();
 | 
			
		||||
            prompt.AddChoice("root").AddChild("level-1").AddChild("level-2").AddChild("item");
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            var actual = prompt.GetParents("item");
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            actual.ShouldBe(new[] { "root", "level-1", "level-2" });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Get_An_Empty_List_Of_Parents_For_Root_Node()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var prompt = new MultiSelectionPrompt<string>();
 | 
			
		||||
            prompt.AddChoice("root");
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            var actual = prompt.GetParents("root");
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            actual.ShouldBeEmpty();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Get_Null_As_Direct_Parent_Of_Root_Node()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var prompt = new MultiSelectionPrompt<string>();
 | 
			
		||||
            prompt.AddChoice("root");
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            var actual = prompt.GetParent("root");
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            actual.ShouldBeNull();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Throw_When_Getting_Parents_Of_Non_Existing_Node()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var prompt = new MultiSelectionPrompt<string>();
 | 
			
		||||
            prompt.AddChoice("root").AddChild("level-1").AddChild("level-2").AddChild("item");
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            Action action = () => prompt.GetParents("non-existing");
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            action.ShouldThrow<ArgumentOutOfRangeException>();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    public void Should_Not_Mark_Item_As_Selected_By_Default()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var prompt = new MultiSelectionPrompt<int>();
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        var choice = prompt.AddChoice(32);
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        choice.IsSelected.ShouldBeFalse();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    public void Should_Mark_Item_As_Selected()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var prompt = new MultiSelectionPrompt<int>();
 | 
			
		||||
        var choice = prompt.AddChoice(32);
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        prompt.Select(32);
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        choice.IsSelected.ShouldBeTrue();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    public void Should_Mark_Custom_Item_As_Selected_If_The_Same_Reference_Is_Used()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var prompt = new MultiSelectionPrompt<CustomItem>();
 | 
			
		||||
        var item = new CustomItem { X = 18, Y = 32 };
 | 
			
		||||
        var choice = prompt.AddChoice(item);
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        prompt.Select(item);
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        choice.IsSelected.ShouldBeTrue();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    public void Should_Mark_Custom_Item_As_Selected_If_A_Comparer_Is_Provided()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var prompt = new MultiSelectionPrompt<CustomItem>(new CustomItem.Comparer());
 | 
			
		||||
        var choice = prompt.AddChoice(new CustomItem { X = 18, Y = 32 });
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        prompt.Select(new CustomItem { X = 18, Y = 32 });
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        choice.IsSelected.ShouldBeTrue();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    public void Should_Get_The_Direct_Parent()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var prompt = new MultiSelectionPrompt<string>();
 | 
			
		||||
        prompt.AddChoice("root").AddChild("level-1").AddChild("level-2").AddChild("item");
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        var actual = prompt.GetParent("item");
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        actual.ShouldBe("level-2");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    public void Should_Get_The_List_Of_All_Parents()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var prompt = new MultiSelectionPrompt<string>();
 | 
			
		||||
        prompt.AddChoice("root").AddChild("level-1").AddChild("level-2").AddChild("item");
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        var actual = prompt.GetParents("item");
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        actual.ShouldBe(new[] { "root", "level-1", "level-2" });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    public void Should_Get_An_Empty_List_Of_Parents_For_Root_Node()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var prompt = new MultiSelectionPrompt<string>();
 | 
			
		||||
        prompt.AddChoice("root");
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        var actual = prompt.GetParents("root");
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        actual.ShouldBeEmpty();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    public void Should_Get_Null_As_Direct_Parent_Of_Root_Node()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var prompt = new MultiSelectionPrompt<string>();
 | 
			
		||||
        prompt.AddChoice("root");
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        var actual = prompt.GetParent("root");
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        actual.ShouldBeNull();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    public void Should_Throw_When_Getting_Parents_Of_Non_Existing_Node()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var prompt = new MultiSelectionPrompt<string>();
 | 
			
		||||
        prompt.AddChoice("root").AddChild("level-1").AddChild("level-2").AddChild("item");
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        Action action = () => prompt.GetParents("non-existing");
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        action.ShouldThrow<ArgumentOutOfRangeException>();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,30 +1,24 @@
 | 
			
		||||
using System;
 | 
			
		||||
using Shouldly;
 | 
			
		||||
using Spectre.Console.Testing;
 | 
			
		||||
using Xunit;
 | 
			
		||||
namespace Spectre.Console.Tests.Unit;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Unit
 | 
			
		||||
public sealed class SelectionPromptTests
 | 
			
		||||
{
 | 
			
		||||
    public sealed class SelectionPromptTests
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [GitHubIssue(608)]
 | 
			
		||||
    public void Should_Not_Throw_When_Selecting_An_Item_With_Escaped_Markup()
 | 
			
		||||
    {
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [GitHubIssue(608)]
 | 
			
		||||
        public void Should_Not_Throw_When_Selecting_An_Item_With_Escaped_Markup()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
            console.Profile.Capabilities.Interactive = true;
 | 
			
		||||
            console.Input.PushKey(ConsoleKey.Enter);
 | 
			
		||||
            var input = "[red]This text will never be red[/]".EscapeMarkup();
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole();
 | 
			
		||||
        console.Profile.Capabilities.Interactive = true;
 | 
			
		||||
        console.Input.PushKey(ConsoleKey.Enter);
 | 
			
		||||
        var input = "[red]This text will never be red[/]".EscapeMarkup();
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            var prompt = new SelectionPrompt<string>()
 | 
			
		||||
                    .Title("Select one")
 | 
			
		||||
                    .AddChoices(input);
 | 
			
		||||
            prompt.Show(console);
 | 
			
		||||
        // When
 | 
			
		||||
        var prompt = new SelectionPrompt<string>()
 | 
			
		||||
                .Title("Select one")
 | 
			
		||||
                .AddChoices(input);
 | 
			
		||||
        prompt.Show(console);
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            console.Output.ShouldContain(@"[red]This text will never be red[/]");
 | 
			
		||||
        }
 | 
			
		||||
        // Then
 | 
			
		||||
        console.Output.ShouldContain(@"[red]This text will never be red[/]");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,253 +1,244 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Shouldly;
 | 
			
		||||
using Spectre.Console.Testing;
 | 
			
		||||
using Spectre.Verify.Extensions;
 | 
			
		||||
using VerifyXunit;
 | 
			
		||||
using Xunit;
 | 
			
		||||
namespace Spectre.Console.Tests.Unit;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Unit
 | 
			
		||||
[UsesVerify]
 | 
			
		||||
[ExpectationPath("Prompts/Text")]
 | 
			
		||||
public sealed class TextPromptTests
 | 
			
		||||
{
 | 
			
		||||
    [UsesVerify]
 | 
			
		||||
    [ExpectationPath("Prompts/Text")]
 | 
			
		||||
    public sealed class TextPromptTests
 | 
			
		||||
    [Fact]
 | 
			
		||||
    public void Should_Return_Entered_Text()
 | 
			
		||||
    {
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Return_Entered_Text()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
            console.Input.PushTextWithEnter("Hello World");
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole();
 | 
			
		||||
        console.Input.PushTextWithEnter("Hello World");
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            var result = console.Prompt(new TextPrompt<string>("Enter text:"));
 | 
			
		||||
        // When
 | 
			
		||||
        var result = console.Prompt(new TextPrompt<string>("Enter text:"));
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ShouldBe("Hello World");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("ConversionError")]
 | 
			
		||||
        public Task Should_Return_Validation_Error_If_Value_Cannot_Be_Converted()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
            console.Input.PushTextWithEnter("ninety-nine");
 | 
			
		||||
            console.Input.PushTextWithEnter("99");
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Prompt(new TextPrompt<int>("Age?"));
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(console.Lines);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("DefaultValue")]
 | 
			
		||||
        public Task Should_Chose_Default_Value_If_Nothing_Is_Entered()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
            console.Input.PushKey(ConsoleKey.Enter);
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Prompt(
 | 
			
		||||
                new TextPrompt<string>("Favorite fruit?")
 | 
			
		||||
                    .AddChoice("Banana")
 | 
			
		||||
                    .AddChoice("Orange")
 | 
			
		||||
                    .DefaultValue("Banana"));
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("InvalidChoice")]
 | 
			
		||||
        public Task Should_Return_Error_If_An_Invalid_Choice_Is_Made()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
            console.Input.PushTextWithEnter("Apple");
 | 
			
		||||
            console.Input.PushTextWithEnter("Banana");
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Prompt(
 | 
			
		||||
                new TextPrompt<string>("Favorite fruit?")
 | 
			
		||||
                    .AddChoice("Banana")
 | 
			
		||||
                    .AddChoice("Orange")
 | 
			
		||||
                    .DefaultValue("Banana"));
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("AcceptChoice")]
 | 
			
		||||
        public Task Should_Accept_Choice_In_List()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
            console.Input.PushTextWithEnter("Orange");
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Prompt(
 | 
			
		||||
                new TextPrompt<string>("Favorite fruit?")
 | 
			
		||||
                    .AddChoice("Banana")
 | 
			
		||||
                    .AddChoice("Orange")
 | 
			
		||||
                    .DefaultValue("Banana"));
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("AutoComplete_Empty")]
 | 
			
		||||
        public Task Should_Auto_Complete_To_First_Choice_If_Pressing_Tab_On_Empty_String()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
            console.Input.PushKey(ConsoleKey.Tab);
 | 
			
		||||
            console.Input.PushKey(ConsoleKey.Enter);
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Prompt(
 | 
			
		||||
                new TextPrompt<string>("Favorite fruit?")
 | 
			
		||||
                    .AddChoice("Banana")
 | 
			
		||||
                    .AddChoice("Orange")
 | 
			
		||||
                    .DefaultValue("Banana"));
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("AutoComplete_BestMatch")]
 | 
			
		||||
        public Task Should_Auto_Complete_To_Best_Match()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
            console.Input.PushText("Band");
 | 
			
		||||
            console.Input.PushKey(ConsoleKey.Tab);
 | 
			
		||||
            console.Input.PushKey(ConsoleKey.Enter);
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Prompt(
 | 
			
		||||
                new TextPrompt<string>("Favorite fruit?")
 | 
			
		||||
                    .AddChoice("Banana")
 | 
			
		||||
                    .AddChoice("Bandana")
 | 
			
		||||
                    .AddChoice("Orange"));
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("AutoComplete_NextChoice")]
 | 
			
		||||
        public Task Should_Auto_Complete_To_Next_Choice_When_Pressing_Tab_On_A_Match()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
            console.Input.PushText("Apple");
 | 
			
		||||
            console.Input.PushKey(ConsoleKey.Tab);
 | 
			
		||||
            console.Input.PushKey(ConsoleKey.Enter);
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Prompt(
 | 
			
		||||
                new TextPrompt<string>("Favorite fruit?")
 | 
			
		||||
                    .AddChoice("Apple")
 | 
			
		||||
                    .AddChoice("Banana")
 | 
			
		||||
                    .AddChoice("Orange"));
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("CustomValidation")]
 | 
			
		||||
        public Task Should_Return_Error_If_Custom_Validation_Fails()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
            console.Input.PushTextWithEnter("22");
 | 
			
		||||
            console.Input.PushTextWithEnter("102");
 | 
			
		||||
            console.Input.PushTextWithEnter("ABC");
 | 
			
		||||
            console.Input.PushTextWithEnter("99");
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Prompt(
 | 
			
		||||
                new TextPrompt<int>("Guess number:")
 | 
			
		||||
                    .ValidationErrorMessage("Invalid input")
 | 
			
		||||
                    .Validate(age =>
 | 
			
		||||
                    {
 | 
			
		||||
                        if (age < 99)
 | 
			
		||||
                        {
 | 
			
		||||
                            return ValidationResult.Error("Too low");
 | 
			
		||||
                        }
 | 
			
		||||
                        else if (age > 99)
 | 
			
		||||
                        {
 | 
			
		||||
                            return ValidationResult.Error("Too high");
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        return ValidationResult.Success();
 | 
			
		||||
                    }));
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("CustomConverter")]
 | 
			
		||||
        public Task Should_Use_Custom_Converter()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
            console.Input.PushTextWithEnter("Banana");
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            var result = console.Prompt(
 | 
			
		||||
                new TextPrompt<(int, string)>("Favorite fruit?")
 | 
			
		||||
                    .AddChoice((1, "Apple"))
 | 
			
		||||
                    .AddChoice((2, "Banana"))
 | 
			
		||||
                    .WithConverter(testData => testData.Item2));
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.Item1.ShouldBe(2);
 | 
			
		||||
            return Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("SecretDefaultValue")]
 | 
			
		||||
        public Task Should_Chose_Masked_Default_Value_If_Nothing_Is_Entered_And_Prompt_Is_Secret()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
            console.Input.PushKey(ConsoleKey.Enter);
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Prompt(
 | 
			
		||||
                new TextPrompt<string>("Favorite fruit?")
 | 
			
		||||
                    .Secret()
 | 
			
		||||
                    .DefaultValue("Banana"));
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("NoSuffix")]
 | 
			
		||||
        [GitHubIssue(413)]
 | 
			
		||||
        public Task Should_Not_Append_Questionmark_Or_Colon_If_No_Choices_Are_Set()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
            console.Input.PushTextWithEnter("Orange");
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Prompt(
 | 
			
		||||
                new TextPrompt<string>("Enter command$"));
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
        // Then
 | 
			
		||||
        result.ShouldBe("Hello World");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("ConversionError")]
 | 
			
		||||
    public Task Should_Return_Validation_Error_If_Value_Cannot_Be_Converted()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole();
 | 
			
		||||
        console.Input.PushTextWithEnter("ninety-nine");
 | 
			
		||||
        console.Input.PushTextWithEnter("99");
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.Prompt(new TextPrompt<int>("Age?"));
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        return Verifier.Verify(console.Lines);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("DefaultValue")]
 | 
			
		||||
    public Task Should_Chose_Default_Value_If_Nothing_Is_Entered()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole();
 | 
			
		||||
        console.Input.PushKey(ConsoleKey.Enter);
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.Prompt(
 | 
			
		||||
            new TextPrompt<string>("Favorite fruit?")
 | 
			
		||||
                .AddChoice("Banana")
 | 
			
		||||
                .AddChoice("Orange")
 | 
			
		||||
                .DefaultValue("Banana"));
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        return Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("InvalidChoice")]
 | 
			
		||||
    public Task Should_Return_Error_If_An_Invalid_Choice_Is_Made()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole();
 | 
			
		||||
        console.Input.PushTextWithEnter("Apple");
 | 
			
		||||
        console.Input.PushTextWithEnter("Banana");
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.Prompt(
 | 
			
		||||
            new TextPrompt<string>("Favorite fruit?")
 | 
			
		||||
                .AddChoice("Banana")
 | 
			
		||||
                .AddChoice("Orange")
 | 
			
		||||
                .DefaultValue("Banana"));
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        return Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("AcceptChoice")]
 | 
			
		||||
    public Task Should_Accept_Choice_In_List()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole();
 | 
			
		||||
        console.Input.PushTextWithEnter("Orange");
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.Prompt(
 | 
			
		||||
            new TextPrompt<string>("Favorite fruit?")
 | 
			
		||||
                .AddChoice("Banana")
 | 
			
		||||
                .AddChoice("Orange")
 | 
			
		||||
                .DefaultValue("Banana"));
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        return Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("AutoComplete_Empty")]
 | 
			
		||||
    public Task Should_Auto_Complete_To_First_Choice_If_Pressing_Tab_On_Empty_String()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole();
 | 
			
		||||
        console.Input.PushKey(ConsoleKey.Tab);
 | 
			
		||||
        console.Input.PushKey(ConsoleKey.Enter);
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.Prompt(
 | 
			
		||||
            new TextPrompt<string>("Favorite fruit?")
 | 
			
		||||
                .AddChoice("Banana")
 | 
			
		||||
                .AddChoice("Orange")
 | 
			
		||||
                .DefaultValue("Banana"));
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        return Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("AutoComplete_BestMatch")]
 | 
			
		||||
    public Task Should_Auto_Complete_To_Best_Match()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole();
 | 
			
		||||
        console.Input.PushText("Band");
 | 
			
		||||
        console.Input.PushKey(ConsoleKey.Tab);
 | 
			
		||||
        console.Input.PushKey(ConsoleKey.Enter);
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.Prompt(
 | 
			
		||||
            new TextPrompt<string>("Favorite fruit?")
 | 
			
		||||
                .AddChoice("Banana")
 | 
			
		||||
                .AddChoice("Bandana")
 | 
			
		||||
                .AddChoice("Orange"));
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        return Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("AutoComplete_NextChoice")]
 | 
			
		||||
    public Task Should_Auto_Complete_To_Next_Choice_When_Pressing_Tab_On_A_Match()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole();
 | 
			
		||||
        console.Input.PushText("Apple");
 | 
			
		||||
        console.Input.PushKey(ConsoleKey.Tab);
 | 
			
		||||
        console.Input.PushKey(ConsoleKey.Enter);
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.Prompt(
 | 
			
		||||
            new TextPrompt<string>("Favorite fruit?")
 | 
			
		||||
                .AddChoice("Apple")
 | 
			
		||||
                .AddChoice("Banana")
 | 
			
		||||
                .AddChoice("Orange"));
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        return Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("CustomValidation")]
 | 
			
		||||
    public Task Should_Return_Error_If_Custom_Validation_Fails()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole();
 | 
			
		||||
        console.Input.PushTextWithEnter("22");
 | 
			
		||||
        console.Input.PushTextWithEnter("102");
 | 
			
		||||
        console.Input.PushTextWithEnter("ABC");
 | 
			
		||||
        console.Input.PushTextWithEnter("99");
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.Prompt(
 | 
			
		||||
            new TextPrompt<int>("Guess number:")
 | 
			
		||||
                .ValidationErrorMessage("Invalid input")
 | 
			
		||||
                .Validate(age =>
 | 
			
		||||
                {
 | 
			
		||||
                    if (age < 99)
 | 
			
		||||
                    {
 | 
			
		||||
                        return ValidationResult.Error("Too low");
 | 
			
		||||
                    }
 | 
			
		||||
                    else if (age > 99)
 | 
			
		||||
                    {
 | 
			
		||||
                        return ValidationResult.Error("Too high");
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    return ValidationResult.Success();
 | 
			
		||||
                }));
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        return Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("CustomConverter")]
 | 
			
		||||
    public Task Should_Use_Custom_Converter()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole();
 | 
			
		||||
        console.Input.PushTextWithEnter("Banana");
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        var result = console.Prompt(
 | 
			
		||||
            new TextPrompt<(int, string)>("Favorite fruit?")
 | 
			
		||||
                .AddChoice((1, "Apple"))
 | 
			
		||||
                .AddChoice((2, "Banana"))
 | 
			
		||||
                .WithConverter(testData => testData.Item2));
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        result.Item1.ShouldBe(2);
 | 
			
		||||
        return Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("SecretDefaultValue")]
 | 
			
		||||
    public Task Should_Chose_Masked_Default_Value_If_Nothing_Is_Entered_And_Prompt_Is_Secret()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole();
 | 
			
		||||
        console.Input.PushKey(ConsoleKey.Enter);
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.Prompt(
 | 
			
		||||
            new TextPrompt<string>("Favorite fruit?")
 | 
			
		||||
                .Secret()
 | 
			
		||||
                .DefaultValue("Banana"));
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        return Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("NoSuffix")]
 | 
			
		||||
    [GitHubIssue(413)]
 | 
			
		||||
    public Task Should_Not_Append_Questionmark_Or_Colon_If_No_Choices_Are_Set()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole();
 | 
			
		||||
        console.Input.PushTextWithEnter("Orange");
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.Prompt(
 | 
			
		||||
            new TextPrompt<string>("Enter command$"));
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        return Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,54 +1,47 @@
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Spectre.Console.Testing;
 | 
			
		||||
using Spectre.Verify.Extensions;
 | 
			
		||||
using VerifyXunit;
 | 
			
		||||
using Xunit;
 | 
			
		||||
namespace Spectre.Console.Tests.Unit;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Unit
 | 
			
		||||
[UsesVerify]
 | 
			
		||||
[ExpectationPath("Widgets/Recorder")]
 | 
			
		||||
public sealed class RecorderTests
 | 
			
		||||
{
 | 
			
		||||
    [UsesVerify]
 | 
			
		||||
    [ExpectationPath("Widgets/Recorder")]
 | 
			
		||||
    public sealed class RecorderTests
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("Text")]
 | 
			
		||||
    public Task Should_Export_Text_As_Expected()
 | 
			
		||||
    {
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Text")]
 | 
			
		||||
        public Task Should_Export_Text_As_Expected()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
            var recorder = new Recorder(console);
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole();
 | 
			
		||||
        var recorder = new Recorder(console);
 | 
			
		||||
 | 
			
		||||
            recorder.Write(new Table()
 | 
			
		||||
                .AddColumns("Foo", "Bar", "Qux")
 | 
			
		||||
                .AddRow("Corgi", "Waldo", "Zap")
 | 
			
		||||
                .AddRow(new Panel("Hello World").RoundedBorder()));
 | 
			
		||||
        recorder.Write(new Table()
 | 
			
		||||
            .AddColumns("Foo", "Bar", "Qux")
 | 
			
		||||
            .AddRow("Corgi", "Waldo", "Zap")
 | 
			
		||||
            .AddRow(new Panel("Hello World").RoundedBorder()));
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            var result = recorder.ExportText();
 | 
			
		||||
        // When
 | 
			
		||||
        var result = recorder.ExportText();
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(result);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Html")]
 | 
			
		||||
        public Task Should_Export_Html_Text_As_Expected()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
            var recorder = new Recorder(console);
 | 
			
		||||
 | 
			
		||||
            recorder.Write(new Table()
 | 
			
		||||
                .AddColumns("[red on black]Foo[/]", "[green bold]Bar[/]", "[blue italic]Qux[/]")
 | 
			
		||||
                .AddRow("[invert underline]Corgi[/]", "[bold strikethrough]Waldo[/]", "[dim]Zap[/]")
 | 
			
		||||
                .AddRow(new Panel("[blue]Hello World[/]")
 | 
			
		||||
                    .BorderColor(Color.Red).RoundedBorder()));
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            var result = recorder.ExportHtml();
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(result);
 | 
			
		||||
        }
 | 
			
		||||
        // Then
 | 
			
		||||
        return Verifier.Verify(result);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("Html")]
 | 
			
		||||
    public Task Should_Export_Html_Text_As_Expected()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole();
 | 
			
		||||
        var recorder = new Recorder(console);
 | 
			
		||||
 | 
			
		||||
        recorder.Write(new Table()
 | 
			
		||||
            .AddColumns("[red on black]Foo[/]", "[green bold]Bar[/]", "[blue italic]Qux[/]")
 | 
			
		||||
            .AddRow("[invert underline]Corgi[/]", "[bold strikethrough]Waldo[/]", "[dim]Zap[/]")
 | 
			
		||||
            .AddRow(new Panel("[blue]Hello World[/]")
 | 
			
		||||
                .BorderColor(Color.Red).RoundedBorder()));
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        var result = recorder.ExportHtml();
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        return Verifier.Verify(result);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,210 +1,201 @@
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Shouldly;
 | 
			
		||||
using Spectre.Console.Rendering;
 | 
			
		||||
using Spectre.Console.Testing;
 | 
			
		||||
using Spectre.Verify.Extensions;
 | 
			
		||||
using VerifyXunit;
 | 
			
		||||
using Xunit;
 | 
			
		||||
namespace Spectre.Console.Tests.Unit;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Unit
 | 
			
		||||
[UsesVerify]
 | 
			
		||||
[ExpectationPath("Rendering/Borders/Box")]
 | 
			
		||||
public sealed class BoxBorderTests
 | 
			
		||||
{
 | 
			
		||||
    [UsesVerify]
 | 
			
		||||
    [ExpectationPath("Rendering/Borders/Box")]
 | 
			
		||||
    public sealed class BoxBorderTests
 | 
			
		||||
    public sealed class NoBorder
 | 
			
		||||
    {
 | 
			
		||||
        [UsesVerify]
 | 
			
		||||
        public sealed class NoBorder
 | 
			
		||||
        {
 | 
			
		||||
            public sealed class TheSafeGetBorderMethod
 | 
			
		||||
            {
 | 
			
		||||
                [Fact]
 | 
			
		||||
                public void Should_Return_Safe_Border()
 | 
			
		||||
                {
 | 
			
		||||
                    // Given, When
 | 
			
		||||
                    var border = BoxExtensions.GetSafeBorder(BoxBorder.None, safe: true);
 | 
			
		||||
 | 
			
		||||
                    // Then
 | 
			
		||||
                    border.ShouldBeSameAs(BoxBorder.None);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            [Expectation("NoBorder")]
 | 
			
		||||
            public Task Should_Render_As_Expected()
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var console = new TestConsole();
 | 
			
		||||
                var panel = Fixture.GetPanel().NoBorder();
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                console.Write(panel);
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                return Verifier.Verify(console.Output);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [UsesVerify]
 | 
			
		||||
        public sealed class AsciiBorder
 | 
			
		||||
        {
 | 
			
		||||
            public sealed class TheSafeGetBorderMethod
 | 
			
		||||
            {
 | 
			
		||||
                [Fact]
 | 
			
		||||
                public void Should_Return_Safe_Border()
 | 
			
		||||
                {
 | 
			
		||||
                    // Given, When
 | 
			
		||||
                    var border = BoxExtensions.GetSafeBorder(BoxBorder.Ascii, safe: true);
 | 
			
		||||
 | 
			
		||||
                    // Then
 | 
			
		||||
                    border.ShouldBeSameAs(BoxBorder.Ascii);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            [Expectation("AsciiBorder")]
 | 
			
		||||
            public Task Should_Render_As_Expected()
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var console = new TestConsole();
 | 
			
		||||
                var panel = Fixture.GetPanel().AsciiBorder();
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                console.Write(panel);
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                return Verifier.Verify(console.Output);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [UsesVerify]
 | 
			
		||||
        public sealed class DoubleBorder
 | 
			
		||||
        {
 | 
			
		||||
            public sealed class TheSafeGetBorderMethod
 | 
			
		||||
            {
 | 
			
		||||
                [Fact]
 | 
			
		||||
                public void Should_Return_Safe_Border()
 | 
			
		||||
                {
 | 
			
		||||
                    // Given, When
 | 
			
		||||
                    var border = BoxExtensions.GetSafeBorder(BoxBorder.Double, safe: true);
 | 
			
		||||
 | 
			
		||||
                    // Then
 | 
			
		||||
                    border.ShouldBeSameAs(BoxBorder.Double);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            [Expectation("DoubleBorder")]
 | 
			
		||||
            public Task Should_Render_As_Expected()
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var console = new TestConsole();
 | 
			
		||||
                var panel = Fixture.GetPanel().DoubleBorder();
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                console.Write(panel);
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                return Verifier.Verify(console.Output);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [UsesVerify]
 | 
			
		||||
        public sealed class HeavyBorder
 | 
			
		||||
        {
 | 
			
		||||
            public sealed class TheSafeGetBorderMethod
 | 
			
		||||
            {
 | 
			
		||||
                [Fact]
 | 
			
		||||
                public void Should_Return_Safe_Border()
 | 
			
		||||
                {
 | 
			
		||||
                    // Given, When
 | 
			
		||||
                    var border = BoxExtensions.GetSafeBorder(BoxBorder.Heavy, safe: true);
 | 
			
		||||
 | 
			
		||||
                    // Then
 | 
			
		||||
                    border.ShouldBeSameAs(BoxBorder.Square);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            [Expectation("HeavyBorder")]
 | 
			
		||||
            public Task Should_Render_As_Expected()
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var console = new TestConsole();
 | 
			
		||||
                var panel = Fixture.GetPanel().HeavyBorder();
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                console.Write(panel);
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                return Verifier.Verify(console.Output);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [UsesVerify]
 | 
			
		||||
        public sealed class RoundedBorder
 | 
			
		||||
        public sealed class TheSafeGetBorderMethod
 | 
			
		||||
        {
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Return_Safe_Border()
 | 
			
		||||
            {
 | 
			
		||||
                // Given, When
 | 
			
		||||
                var border = BoxExtensions.GetSafeBorder(BoxBorder.Rounded, safe: true);
 | 
			
		||||
                var border = BoxExtensions.GetSafeBorder(BoxBorder.None, safe: true);
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                border.ShouldBeSameAs(BoxBorder.Square);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            [Expectation("RoundedBorder")]
 | 
			
		||||
            public Task Should_Render_As_Expected()
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var console = new TestConsole();
 | 
			
		||||
                var panel = Fixture.GetPanel().RoundedBorder();
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                console.Write(panel);
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                return Verifier.Verify(console.Output);
 | 
			
		||||
                border.ShouldBeSameAs(BoxBorder.None);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [UsesVerify]
 | 
			
		||||
        public sealed class SquareBorder
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("NoBorder")]
 | 
			
		||||
        public Task Should_Render_As_Expected()
 | 
			
		||||
        {
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Return_Safe_Border()
 | 
			
		||||
            {
 | 
			
		||||
                // Given, When
 | 
			
		||||
                var border = BoxExtensions.GetSafeBorder(BoxBorder.Square, safe: true);
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
            var panel = Fixture.GetPanel().NoBorder();
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                border.ShouldBeSameAs(BoxBorder.Square);
 | 
			
		||||
            }
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(panel);
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            [Expectation("SquareBorder")]
 | 
			
		||||
            public Task Should_Render_As_Expected()
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var console = new TestConsole();
 | 
			
		||||
                var panel = Fixture.GetPanel().SquareBorder();
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                console.Write(panel);
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                return Verifier.Verify(console.Output);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static class Fixture
 | 
			
		||||
        {
 | 
			
		||||
            public static Panel GetPanel()
 | 
			
		||||
            {
 | 
			
		||||
                return new Panel("Hello World")
 | 
			
		||||
                    .Header("Greeting");
 | 
			
		||||
            }
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    [UsesVerify]
 | 
			
		||||
    public sealed class AsciiBorder
 | 
			
		||||
    {
 | 
			
		||||
        public sealed class TheSafeGetBorderMethod
 | 
			
		||||
        {
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Return_Safe_Border()
 | 
			
		||||
            {
 | 
			
		||||
                // Given, When
 | 
			
		||||
                var border = BoxExtensions.GetSafeBorder(BoxBorder.Ascii, safe: true);
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                border.ShouldBeSameAs(BoxBorder.Ascii);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("AsciiBorder")]
 | 
			
		||||
        public Task Should_Render_As_Expected()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
            var panel = Fixture.GetPanel().AsciiBorder();
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(panel);
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [UsesVerify]
 | 
			
		||||
    public sealed class DoubleBorder
 | 
			
		||||
    {
 | 
			
		||||
        public sealed class TheSafeGetBorderMethod
 | 
			
		||||
        {
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Return_Safe_Border()
 | 
			
		||||
            {
 | 
			
		||||
                // Given, When
 | 
			
		||||
                var border = BoxExtensions.GetSafeBorder(BoxBorder.Double, safe: true);
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                border.ShouldBeSameAs(BoxBorder.Double);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("DoubleBorder")]
 | 
			
		||||
        public Task Should_Render_As_Expected()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
            var panel = Fixture.GetPanel().DoubleBorder();
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(panel);
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [UsesVerify]
 | 
			
		||||
    public sealed class HeavyBorder
 | 
			
		||||
    {
 | 
			
		||||
        public sealed class TheSafeGetBorderMethod
 | 
			
		||||
        {
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Return_Safe_Border()
 | 
			
		||||
            {
 | 
			
		||||
                // Given, When
 | 
			
		||||
                var border = BoxExtensions.GetSafeBorder(BoxBorder.Heavy, safe: true);
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                border.ShouldBeSameAs(BoxBorder.Square);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("HeavyBorder")]
 | 
			
		||||
        public Task Should_Render_As_Expected()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
            var panel = Fixture.GetPanel().HeavyBorder();
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(panel);
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [UsesVerify]
 | 
			
		||||
    public sealed class RoundedBorder
 | 
			
		||||
    {
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Return_Safe_Border()
 | 
			
		||||
        {
 | 
			
		||||
            // Given, When
 | 
			
		||||
            var border = BoxExtensions.GetSafeBorder(BoxBorder.Rounded, safe: true);
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            border.ShouldBeSameAs(BoxBorder.Square);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("RoundedBorder")]
 | 
			
		||||
        public Task Should_Render_As_Expected()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
            var panel = Fixture.GetPanel().RoundedBorder();
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(panel);
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [UsesVerify]
 | 
			
		||||
    public sealed class SquareBorder
 | 
			
		||||
    {
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Return_Safe_Border()
 | 
			
		||||
        {
 | 
			
		||||
            // Given, When
 | 
			
		||||
            var border = BoxExtensions.GetSafeBorder(BoxBorder.Square, safe: true);
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            border.ShouldBeSameAs(BoxBorder.Square);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("SquareBorder")]
 | 
			
		||||
        public Task Should_Render_As_Expected()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
            var panel = Fixture.GetPanel().SquareBorder();
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(panel);
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static class Fixture
 | 
			
		||||
    {
 | 
			
		||||
        public static Panel GetPanel()
 | 
			
		||||
        {
 | 
			
		||||
            return new Panel("Hello World")
 | 
			
		||||
                .Header("Greeting");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -1,35 +1,27 @@
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using Shouldly;
 | 
			
		||||
using Spectre.Console.Rendering;
 | 
			
		||||
using Spectre.Console.Testing;
 | 
			
		||||
using Xunit;
 | 
			
		||||
namespace Spectre.Console.Tests.Unit;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Unit
 | 
			
		||||
public sealed class RenderHookTests
 | 
			
		||||
{
 | 
			
		||||
    public sealed class RenderHookTests
 | 
			
		||||
    private sealed class HelloRenderHook : IRenderHook
 | 
			
		||||
    {
 | 
			
		||||
        private sealed class HelloRenderHook : IRenderHook
 | 
			
		||||
        public IEnumerable<IRenderable> Process(RenderContext context, IEnumerable<IRenderable> renderables)
 | 
			
		||||
        {
 | 
			
		||||
            public IEnumerable<IRenderable> Process(RenderContext context, IEnumerable<IRenderable> renderables)
 | 
			
		||||
            {
 | 
			
		||||
                return new IRenderable[] { new Text("Hello\n") }.Concat(renderables);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Inject_Renderable_Before_Writing_To_Console()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
            console.Pipeline.Attach(new HelloRenderHook());
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(new Text("World"));
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            console.Lines[0].ShouldBe("Hello");
 | 
			
		||||
            console.Lines[1].ShouldBe("World");
 | 
			
		||||
            return new IRenderable[] { new Text("Hello\n") }.Concat(renderables);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    public void Should_Inject_Renderable_Before_Writing_To_Console()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole();
 | 
			
		||||
        console.Pipeline.Attach(new HelloRenderHook());
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.Write(new Text("World"));
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        console.Lines[0].ShouldBe("Hello");
 | 
			
		||||
        console.Lines[1].ShouldBe("World");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,95 +1,90 @@
 | 
			
		||||
using Shouldly;
 | 
			
		||||
using Spectre.Console.Rendering;
 | 
			
		||||
using VerifyXunit;
 | 
			
		||||
using Xunit;
 | 
			
		||||
namespace Spectre.Console.Tests.Unit;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Unit
 | 
			
		||||
public sealed class SegmentTests
 | 
			
		||||
{
 | 
			
		||||
    public sealed class SegmentTests
 | 
			
		||||
    [UsesVerify]
 | 
			
		||||
    public sealed class TheSplitMethod
 | 
			
		||||
    {
 | 
			
		||||
        [UsesVerify]
 | 
			
		||||
        public sealed class TheSplitMethod
 | 
			
		||||
        [Theory]
 | 
			
		||||
        [InlineData("Foo Bar", 0, "", "Foo Bar")]
 | 
			
		||||
        [InlineData("Foo Bar", 1, "F", "oo Bar")]
 | 
			
		||||
        [InlineData("Foo Bar", 2, "Fo", "o Bar")]
 | 
			
		||||
        [InlineData("Foo Bar", 3, "Foo", " Bar")]
 | 
			
		||||
        [InlineData("Foo Bar", 4, "Foo ", "Bar")]
 | 
			
		||||
        [InlineData("Foo Bar", 5, "Foo B", "ar")]
 | 
			
		||||
        [InlineData("Foo Bar", 6, "Foo Ba", "r")]
 | 
			
		||||
        [InlineData("Foo Bar", 7, "Foo Bar", null)]
 | 
			
		||||
        [InlineData("Foo 测试 Bar", 0, "", "Foo 测试 Bar")]
 | 
			
		||||
        [InlineData("Foo 测试 Bar", 1, "F", "oo 测试 Bar")]
 | 
			
		||||
        [InlineData("Foo 测试 Bar", 2, "Fo", "o 测试 Bar")]
 | 
			
		||||
        [InlineData("Foo 测试 Bar", 3, "Foo", " 测试 Bar")]
 | 
			
		||||
        [InlineData("Foo 测试 Bar", 4, "Foo ", "测试 Bar")]
 | 
			
		||||
        [InlineData("Foo 测试 Bar", 5, "Foo 测", "试 Bar")]
 | 
			
		||||
        [InlineData("Foo 测试 Bar", 6, "Foo 测", "试 Bar")]
 | 
			
		||||
        [InlineData("Foo 测试 Bar", 7, "Foo 测试", " Bar")]
 | 
			
		||||
        [InlineData("Foo 测试 Bar", 8, "Foo 测试", " Bar")]
 | 
			
		||||
        [InlineData("Foo 测试 Bar", 9, "Foo 测试 ", "Bar")]
 | 
			
		||||
        [InlineData("Foo 测试 Bar", 10, "Foo 测试 B", "ar")]
 | 
			
		||||
        [InlineData("Foo 测试 Bar", 11, "Foo 测试 Ba", "r")]
 | 
			
		||||
        [InlineData("Foo 测试 Bar", 12, "Foo 测试 Bar", null)]
 | 
			
		||||
        public void Should_Split_Segment_Correctly(string text, int offset, string expectedFirst, string expectedSecond)
 | 
			
		||||
        {
 | 
			
		||||
            [Theory]
 | 
			
		||||
            [InlineData("Foo Bar", 0, "", "Foo Bar")]
 | 
			
		||||
            [InlineData("Foo Bar", 1, "F", "oo Bar")]
 | 
			
		||||
            [InlineData("Foo Bar", 2, "Fo", "o Bar")]
 | 
			
		||||
            [InlineData("Foo Bar", 3, "Foo", " Bar")]
 | 
			
		||||
            [InlineData("Foo Bar", 4, "Foo ", "Bar")]
 | 
			
		||||
            [InlineData("Foo Bar", 5, "Foo B", "ar")]
 | 
			
		||||
            [InlineData("Foo Bar", 6, "Foo Ba", "r")]
 | 
			
		||||
            [InlineData("Foo Bar", 7, "Foo Bar", null)]
 | 
			
		||||
            [InlineData("Foo 测试 Bar", 0, "", "Foo 测试 Bar")]
 | 
			
		||||
            [InlineData("Foo 测试 Bar", 1, "F", "oo 测试 Bar")]
 | 
			
		||||
            [InlineData("Foo 测试 Bar", 2, "Fo", "o 测试 Bar")]
 | 
			
		||||
            [InlineData("Foo 测试 Bar", 3, "Foo", " 测试 Bar")]
 | 
			
		||||
            [InlineData("Foo 测试 Bar", 4, "Foo ", "测试 Bar")]
 | 
			
		||||
            [InlineData("Foo 测试 Bar", 5, "Foo 测", "试 Bar")]
 | 
			
		||||
            [InlineData("Foo 测试 Bar", 6, "Foo 测", "试 Bar")]
 | 
			
		||||
            [InlineData("Foo 测试 Bar", 7, "Foo 测试", " Bar")]
 | 
			
		||||
            [InlineData("Foo 测试 Bar", 8, "Foo 测试", " Bar")]
 | 
			
		||||
            [InlineData("Foo 测试 Bar", 9, "Foo 测试 ", "Bar")]
 | 
			
		||||
            [InlineData("Foo 测试 Bar", 10, "Foo 测试 B", "ar")]
 | 
			
		||||
            [InlineData("Foo 测试 Bar", 11, "Foo 测试 Ba", "r")]
 | 
			
		||||
            [InlineData("Foo 测试 Bar", 12, "Foo 测试 Bar", null)]
 | 
			
		||||
            public void Should_Split_Segment_Correctly(string text, int offset, string expectedFirst, string expectedSecond)
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var style = new Style(Color.Red, Color.Green, Decoration.Bold);
 | 
			
		||||
                var segment = new Segment(text, style);
 | 
			
		||||
            // Given
 | 
			
		||||
            var style = new Style(Color.Red, Color.Green, Decoration.Bold);
 | 
			
		||||
            var segment = new Segment(text, style);
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var (first, second) = segment.Split(offset);
 | 
			
		||||
            // When
 | 
			
		||||
            var (first, second) = segment.Split(offset);
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                first.Text.ShouldBe(expectedFirst);
 | 
			
		||||
                first.Style.ShouldBe(style);
 | 
			
		||||
                second?.Text?.ShouldBe(expectedSecond);
 | 
			
		||||
                second?.Style?.ShouldBe(style);
 | 
			
		||||
            }
 | 
			
		||||
            // Then
 | 
			
		||||
            first.Text.ShouldBe(expectedFirst);
 | 
			
		||||
            first.Style.ShouldBe(style);
 | 
			
		||||
            second?.Text?.ShouldBe(expectedSecond);
 | 
			
		||||
            second?.Style?.ShouldBe(style);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [UsesVerify]
 | 
			
		||||
    public sealed class TheSplitLinesMethod
 | 
			
		||||
    {
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Split_Segment()
 | 
			
		||||
        {
 | 
			
		||||
            // Given, When
 | 
			
		||||
            var lines = Segment.SplitLines(
 | 
			
		||||
                new[]
 | 
			
		||||
                {
 | 
			
		||||
                        new Segment("Foo"),
 | 
			
		||||
                        new Segment("Bar"),
 | 
			
		||||
                        new Segment("\n"),
 | 
			
		||||
                        new Segment("Baz"),
 | 
			
		||||
                        new Segment("Qux"),
 | 
			
		||||
                        new Segment("\n"),
 | 
			
		||||
                        new Segment("Corgi"),
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            lines.Count.ShouldBe(3);
 | 
			
		||||
 | 
			
		||||
            lines[0].Count.ShouldBe(2);
 | 
			
		||||
            lines[0][0].Text.ShouldBe("Foo");
 | 
			
		||||
            lines[0][1].Text.ShouldBe("Bar");
 | 
			
		||||
 | 
			
		||||
            lines[1].Count.ShouldBe(2);
 | 
			
		||||
            lines[1][0].Text.ShouldBe("Baz");
 | 
			
		||||
            lines[1][1].Text.ShouldBe("Qux");
 | 
			
		||||
 | 
			
		||||
            lines[2].Count.ShouldBe(1);
 | 
			
		||||
            lines[2][0].Text.ShouldBe("Corgi");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [UsesVerify]
 | 
			
		||||
        public sealed class TheSplitLinesMethod
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Split_Segment_With_Windows_LineBreak()
 | 
			
		||||
        {
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Split_Segment()
 | 
			
		||||
            {
 | 
			
		||||
                // Given, When
 | 
			
		||||
                var lines = Segment.SplitLines(
 | 
			
		||||
                    new[]
 | 
			
		||||
                    {
 | 
			
		||||
                        new Segment("Foo"),
 | 
			
		||||
                        new Segment("Bar"),
 | 
			
		||||
                        new Segment("\n"),
 | 
			
		||||
                        new Segment("Baz"),
 | 
			
		||||
                        new Segment("Qux"),
 | 
			
		||||
                        new Segment("\n"),
 | 
			
		||||
                        new Segment("Corgi"),
 | 
			
		||||
                    });
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                lines.Count.ShouldBe(3);
 | 
			
		||||
 | 
			
		||||
                lines[0].Count.ShouldBe(2);
 | 
			
		||||
                lines[0][0].Text.ShouldBe("Foo");
 | 
			
		||||
                lines[0][1].Text.ShouldBe("Bar");
 | 
			
		||||
 | 
			
		||||
                lines[1].Count.ShouldBe(2);
 | 
			
		||||
                lines[1][0].Text.ShouldBe("Baz");
 | 
			
		||||
                lines[1][1].Text.ShouldBe("Qux");
 | 
			
		||||
 | 
			
		||||
                lines[2].Count.ShouldBe(1);
 | 
			
		||||
                lines[2][0].Text.ShouldBe("Corgi");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Split_Segment_With_Windows_LineBreak()
 | 
			
		||||
            {
 | 
			
		||||
                // Given, When
 | 
			
		||||
                var lines = Segment.SplitLines(
 | 
			
		||||
                    new[]
 | 
			
		||||
                    {
 | 
			
		||||
            // Given, When
 | 
			
		||||
            var lines = Segment.SplitLines(
 | 
			
		||||
                new[]
 | 
			
		||||
                {
 | 
			
		||||
                        new Segment("Foo"),
 | 
			
		||||
                        new Segment("Bar"),
 | 
			
		||||
                        new Segment("\r\n"),
 | 
			
		||||
@@ -97,53 +92,52 @@ namespace Spectre.Console.Tests.Unit
 | 
			
		||||
                        new Segment("Qux"),
 | 
			
		||||
                        new Segment("\r\n"),
 | 
			
		||||
                        new Segment("Corgi"),
 | 
			
		||||
                    });
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                lines.Count.ShouldBe(3);
 | 
			
		||||
            // Then
 | 
			
		||||
            lines.Count.ShouldBe(3);
 | 
			
		||||
 | 
			
		||||
                lines[0].Count.ShouldBe(2);
 | 
			
		||||
                lines[0][0].Text.ShouldBe("Foo");
 | 
			
		||||
                lines[0][1].Text.ShouldBe("Bar");
 | 
			
		||||
            lines[0].Count.ShouldBe(2);
 | 
			
		||||
            lines[0][0].Text.ShouldBe("Foo");
 | 
			
		||||
            lines[0][1].Text.ShouldBe("Bar");
 | 
			
		||||
 | 
			
		||||
                lines[1].Count.ShouldBe(2);
 | 
			
		||||
                lines[1][0].Text.ShouldBe("Baz");
 | 
			
		||||
                lines[1][1].Text.ShouldBe("Qux");
 | 
			
		||||
            lines[1].Count.ShouldBe(2);
 | 
			
		||||
            lines[1][0].Text.ShouldBe("Baz");
 | 
			
		||||
            lines[1][1].Text.ShouldBe("Qux");
 | 
			
		||||
 | 
			
		||||
                lines[2].Count.ShouldBe(1);
 | 
			
		||||
                lines[2][0].Text.ShouldBe("Corgi");
 | 
			
		||||
            }
 | 
			
		||||
            lines[2].Count.ShouldBe(1);
 | 
			
		||||
            lines[2][0].Text.ShouldBe("Corgi");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Split_Segments_With_Linebreak_In_Text()
 | 
			
		||||
            {
 | 
			
		||||
                // Given, Given
 | 
			
		||||
                var lines = Segment.SplitLines(
 | 
			
		||||
                    new[]
 | 
			
		||||
                    {
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Split_Segments_With_Linebreak_In_Text()
 | 
			
		||||
        {
 | 
			
		||||
            // Given, Given
 | 
			
		||||
            var lines = Segment.SplitLines(
 | 
			
		||||
                new[]
 | 
			
		||||
                {
 | 
			
		||||
                        new Segment("Foo\n"),
 | 
			
		||||
                        new Segment("Bar\n"),
 | 
			
		||||
                        new Segment("Baz"),
 | 
			
		||||
                        new Segment("Qux\n"),
 | 
			
		||||
                        new Segment("Corgi"),
 | 
			
		||||
                    });
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                lines.Count.ShouldBe(4);
 | 
			
		||||
            // Then
 | 
			
		||||
            lines.Count.ShouldBe(4);
 | 
			
		||||
 | 
			
		||||
                lines[0].Count.ShouldBe(1);
 | 
			
		||||
                lines[0][0].Text.ShouldBe("Foo");
 | 
			
		||||
            lines[0].Count.ShouldBe(1);
 | 
			
		||||
            lines[0][0].Text.ShouldBe("Foo");
 | 
			
		||||
 | 
			
		||||
                lines[1].Count.ShouldBe(1);
 | 
			
		||||
                lines[1][0].Text.ShouldBe("Bar");
 | 
			
		||||
            lines[1].Count.ShouldBe(1);
 | 
			
		||||
            lines[1][0].Text.ShouldBe("Bar");
 | 
			
		||||
 | 
			
		||||
                lines[2].Count.ShouldBe(2);
 | 
			
		||||
                lines[2][0].Text.ShouldBe("Baz");
 | 
			
		||||
                lines[2][1].Text.ShouldBe("Qux");
 | 
			
		||||
            lines[2].Count.ShouldBe(2);
 | 
			
		||||
            lines[2][0].Text.ShouldBe("Baz");
 | 
			
		||||
            lines[2][1].Text.ShouldBe("Qux");
 | 
			
		||||
 | 
			
		||||
                lines[3].Count.ShouldBe(1);
 | 
			
		||||
                lines[3][0].Text.ShouldBe("Corgi");
 | 
			
		||||
            }
 | 
			
		||||
            lines[3].Count.ShouldBe(1);
 | 
			
		||||
            lines[3][0].Text.ShouldBe("Corgi");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,401 +1,396 @@
 | 
			
		||||
using System;
 | 
			
		||||
using Shouldly;
 | 
			
		||||
using Xunit;
 | 
			
		||||
namespace Spectre.Console.Tests.Unit;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Unit
 | 
			
		||||
public sealed class StyleTests
 | 
			
		||||
{
 | 
			
		||||
    public sealed class StyleTests
 | 
			
		||||
    [Fact]
 | 
			
		||||
    public void Should_Combine_Two_Styles_As_Expected()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var first = new Style(Color.White, Color.Yellow, Decoration.Bold | Decoration.Italic);
 | 
			
		||||
        var other = new Style(Color.Green, Color.Silver, Decoration.Underline, "https://example.com");
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        var result = first.Combine(other);
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        result.Foreground.ShouldBe(Color.Green);
 | 
			
		||||
        result.Background.ShouldBe(Color.Silver);
 | 
			
		||||
        result.Decoration.ShouldBe(Decoration.Bold | Decoration.Italic | Decoration.Underline);
 | 
			
		||||
        result.Link.ShouldBe("https://example.com");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    public void Should_Consider_Two_Identical_Styles_Equal()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var first = new Style(Color.White, Color.Yellow, Decoration.Bold | Decoration.Italic, "http://example.com");
 | 
			
		||||
        var second = new Style(Color.White, Color.Yellow, Decoration.Bold | Decoration.Italic, "http://example.com");
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        var result = first.Equals(second);
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        result.ShouldBeTrue();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    public void Should_Not_Consider_Two_Styles_With_Different_Foreground_Colors_Equal()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var first = new Style(Color.White, Color.Yellow, Decoration.Bold | Decoration.Italic, "http://example.com");
 | 
			
		||||
        var second = new Style(Color.Blue, Color.Yellow, Decoration.Bold | Decoration.Italic, "http://example.com");
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        var result = first.Equals(second);
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        result.ShouldBeFalse();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    public void Should_Not_Consider_Two_Styles_With_Different_Background_Colors_Equal()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var first = new Style(Color.White, Color.Yellow, Decoration.Bold | Decoration.Italic, "http://example.com");
 | 
			
		||||
        var second = new Style(Color.White, Color.Blue, Decoration.Bold | Decoration.Italic, "http://example.com");
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        var result = first.Equals(second);
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        result.ShouldBeFalse();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    public void Should_Not_Consider_Two_Styles_With_Different_Decorations_Equal()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var first = new Style(Color.White, Color.Yellow, Decoration.Bold | Decoration.Italic, "http://example.com");
 | 
			
		||||
        var second = new Style(Color.White, Color.Yellow, Decoration.Bold, "http://example.com");
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        var result = first.Equals(second);
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        result.ShouldBeFalse();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    public void Should_Not_Consider_Two_Styles_With_Different_Links_Equal()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var first = new Style(Color.White, Color.Yellow, Decoration.Bold | Decoration.Italic, "http://example.com");
 | 
			
		||||
        var second = new Style(Color.White, Color.Yellow, Decoration.Bold | Decoration.Italic, "http://foo.com");
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        var result = first.Equals(second);
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        result.ShouldBeFalse();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public sealed class TheParseMethod
 | 
			
		||||
    {
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Combine_Two_Styles_As_Expected()
 | 
			
		||||
        public void Default_Keyword_Should_Return_Default_Style()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var first = new Style(Color.White, Color.Yellow, Decoration.Bold | Decoration.Italic);
 | 
			
		||||
            var other = new Style(Color.Green, Color.Silver, Decoration.Underline, "https://example.com");
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            var result = first.Combine(other);
 | 
			
		||||
            // Given, When
 | 
			
		||||
            var result = Style.Parse("default");
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.Foreground.ShouldBe(Color.Green);
 | 
			
		||||
            result.Background.ShouldBe(Color.Silver);
 | 
			
		||||
            result.Decoration.ShouldBe(Decoration.Bold | Decoration.Italic | Decoration.Underline);
 | 
			
		||||
            result.ShouldNotBeNull();
 | 
			
		||||
            result.Foreground.ShouldBe(Color.Default);
 | 
			
		||||
            result.Background.ShouldBe(Color.Default);
 | 
			
		||||
            result.Decoration.ShouldBe(Decoration.None);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Theory]
 | 
			
		||||
        [InlineData("bold", Decoration.Bold)]
 | 
			
		||||
        [InlineData("b", Decoration.Bold)]
 | 
			
		||||
        [InlineData("dim", Decoration.Dim)]
 | 
			
		||||
        [InlineData("i", Decoration.Italic)]
 | 
			
		||||
        [InlineData("italic", Decoration.Italic)]
 | 
			
		||||
        [InlineData("underline", Decoration.Underline)]
 | 
			
		||||
        [InlineData("u", Decoration.Underline)]
 | 
			
		||||
        [InlineData("invert", Decoration.Invert)]
 | 
			
		||||
        [InlineData("conceal", Decoration.Conceal)]
 | 
			
		||||
        [InlineData("slowblink", Decoration.SlowBlink)]
 | 
			
		||||
        [InlineData("rapidblink", Decoration.RapidBlink)]
 | 
			
		||||
        [InlineData("strikethrough", Decoration.Strikethrough)]
 | 
			
		||||
        [InlineData("s", Decoration.Strikethrough)]
 | 
			
		||||
        public void Should_Parse_Decoration(string text, Decoration decoration)
 | 
			
		||||
        {
 | 
			
		||||
            // Given, When
 | 
			
		||||
            var result = Style.Parse(text);
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ShouldNotBeNull();
 | 
			
		||||
            result.Decoration.ShouldBe(decoration);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Parse_Link_Without_Address()
 | 
			
		||||
        {
 | 
			
		||||
            // Given, When
 | 
			
		||||
            var result = Style.Parse("link");
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ShouldNotBeNull();
 | 
			
		||||
            result.Link.ShouldBe("https://emptylink");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Parse_Link()
 | 
			
		||||
        {
 | 
			
		||||
            // Given, When
 | 
			
		||||
            var result = Style.Parse("link=https://example.com");
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ShouldNotBeNull();
 | 
			
		||||
            result.Link.ShouldBe("https://example.com");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Consider_Two_Identical_Styles_Equal()
 | 
			
		||||
        public void Should_Throw_If_Link_Is_Set_Twice()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var first = new Style(Color.White, Color.Yellow, Decoration.Bold | Decoration.Italic, "http://example.com");
 | 
			
		||||
            var second = new Style(Color.White, Color.Yellow, Decoration.Bold | Decoration.Italic, "http://example.com");
 | 
			
		||||
            // Given, When
 | 
			
		||||
            var result = Record.Exception(() => Style.Parse("link=https://example.com link=https://example.com"));
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            var result = first.Equals(second);
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ShouldBeOfType<InvalidOperationException>();
 | 
			
		||||
            result.Message.ShouldBe("A link has already been set.");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Parse_Background_If_Foreground_Is_Set_To_Default()
 | 
			
		||||
        {
 | 
			
		||||
            // Given, When
 | 
			
		||||
            var result = Style.Parse("default on green");
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ShouldNotBeNull();
 | 
			
		||||
            result.Decoration.ShouldBe(Decoration.None);
 | 
			
		||||
            result.Foreground.ShouldBe(Color.Default);
 | 
			
		||||
            result.Background.ShouldBe(Color.Green);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Throw_If_Foreground_Is_Set_Twice()
 | 
			
		||||
        {
 | 
			
		||||
            // Given, When
 | 
			
		||||
            var result = Record.Exception(() => Style.Parse("green yellow"));
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ShouldBeOfType<InvalidOperationException>();
 | 
			
		||||
            result.Message.ShouldBe("A foreground color has already been set.");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Throw_If_Background_Is_Set_Twice()
 | 
			
		||||
        {
 | 
			
		||||
            // Given, When
 | 
			
		||||
            var result = Record.Exception(() => Style.Parse("green on blue yellow"));
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ShouldBeOfType<InvalidOperationException>();
 | 
			
		||||
            result.Message.ShouldBe("A background color has already been set.");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Throw_If_Color_Name_Could_Not_Be_Found()
 | 
			
		||||
        {
 | 
			
		||||
            // Given, When
 | 
			
		||||
            var result = Record.Exception(() => Style.Parse("bold lol"));
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ShouldBeOfType<InvalidOperationException>();
 | 
			
		||||
            result.Message.ShouldBe("Could not find color or style 'lol'.");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Throw_If_Background_Color_Name_Could_Not_Be_Found()
 | 
			
		||||
        {
 | 
			
		||||
            // Given, When
 | 
			
		||||
            var result = Record.Exception(() => Style.Parse("blue on lol"));
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ShouldBeOfType<InvalidOperationException>();
 | 
			
		||||
            result.Message.ShouldBe("Could not find color 'lol'.");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Parse_Colors_And_Decoration_And_Link()
 | 
			
		||||
        {
 | 
			
		||||
            // Given, When
 | 
			
		||||
            var result = Style.Parse("link=https://example.com bold underline blue on green");
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ShouldNotBeNull();
 | 
			
		||||
            result.Decoration.ShouldBe(Decoration.Bold | Decoration.Underline);
 | 
			
		||||
            result.Foreground.ShouldBe(Color.Blue);
 | 
			
		||||
            result.Background.ShouldBe(Color.Green);
 | 
			
		||||
            result.Link.ShouldBe("https://example.com");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Theory]
 | 
			
		||||
        [InlineData("#FF0000 on #0000FF")]
 | 
			
		||||
        [InlineData("#F00 on #00F")]
 | 
			
		||||
        public void Should_Parse_Hex_Colors_Correctly(string style)
 | 
			
		||||
        {
 | 
			
		||||
            // Given, When
 | 
			
		||||
            var result = Style.Parse(style);
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.Foreground.ShouldBe(Color.Red);
 | 
			
		||||
            result.Background.ShouldBe(Color.Blue);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Theory]
 | 
			
		||||
        [InlineData("#", "Invalid hex color '#'.")]
 | 
			
		||||
        [InlineData("#FF00FF00FF", "Invalid hex color '#FF00FF00FF'.")]
 | 
			
		||||
        [InlineData("#FOO", "Invalid hex color '#FOO'. Could not find any recognizable digits.")]
 | 
			
		||||
        public void Should_Return_Error_If_Hex_Color_Is_Invalid(string style, string expected)
 | 
			
		||||
        {
 | 
			
		||||
            // Given, When
 | 
			
		||||
            var result = Record.Exception(() => Style.Parse(style));
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ShouldNotBeNull();
 | 
			
		||||
            result.Message.ShouldBe(expected);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Theory]
 | 
			
		||||
        [InlineData("rgb(255,0,0) on rgb(0,0,255)")]
 | 
			
		||||
        public void Should_Parse_Rgb_Colors_Correctly(string style)
 | 
			
		||||
        {
 | 
			
		||||
            // Given, When
 | 
			
		||||
            var result = Style.Parse(style);
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.Foreground.ShouldBe(Color.Red);
 | 
			
		||||
            result.Background.ShouldBe(Color.Blue);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Theory]
 | 
			
		||||
        [InlineData("12 on 24")]
 | 
			
		||||
        public void Should_Parse_Colors_Numbers_Correctly(string style)
 | 
			
		||||
        {
 | 
			
		||||
            // Given, When
 | 
			
		||||
            var result = Style.Parse(style);
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.Foreground.ShouldBe(Color.Blue);
 | 
			
		||||
            result.Background.ShouldBe(Color.DeepSkyBlue4_1);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Theory]
 | 
			
		||||
        [InlineData("-12", "Color number must be greater than or equal to 0 (was -12)")]
 | 
			
		||||
        [InlineData("256", "Color number must be less than or equal to 255 (was 256)")]
 | 
			
		||||
        public void Should_Return_Error_If_Color_Number_Is_Invalid(string style, string expected)
 | 
			
		||||
        {
 | 
			
		||||
            // Given, When
 | 
			
		||||
            var result = Record.Exception(() => Style.Parse(style));
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ShouldNotBeNull();
 | 
			
		||||
            result.Message.ShouldBe(expected);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Theory]
 | 
			
		||||
        [InlineData("rgb()", "Invalid RGB color 'rgb()'.")]
 | 
			
		||||
        [InlineData("rgb(", "Invalid RGB color 'rgb('.")]
 | 
			
		||||
        [InlineData("rgb(255)", "Invalid RGB color 'rgb(255)'.")]
 | 
			
		||||
        [InlineData("rgb(255,255)", "Invalid RGB color 'rgb(255,255)'.")]
 | 
			
		||||
        [InlineData("rgb(255,255,255", "Invalid RGB color 'rgb(255,255,255'.")]
 | 
			
		||||
        [InlineData("rgb(A,B,C)", "Invalid RGB color 'rgb(A,B,C)'. Input string was not in a correct format.")]
 | 
			
		||||
        public void Should_Return_Error_If_Rgb_Color_Is_Invalid(string style, string expected)
 | 
			
		||||
        {
 | 
			
		||||
            // Given, When
 | 
			
		||||
            var result = Record.Exception(() => Style.Parse(style));
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ShouldNotBeNull();
 | 
			
		||||
            result.Message.ShouldBe(expected);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public sealed class TheTryParseMethod
 | 
			
		||||
    {
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Return_True_If_Parsing_Succeeded()
 | 
			
		||||
        {
 | 
			
		||||
            // Given, When
 | 
			
		||||
            var result = Style.TryParse("bold", out var style);
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ShouldBeTrue();
 | 
			
		||||
            style.ShouldNotBeNull();
 | 
			
		||||
            style.Decoration.ShouldBe(Decoration.Bold);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Not_Consider_Two_Styles_With_Different_Foreground_Colors_Equal()
 | 
			
		||||
        public void Should_Return_False_If_Parsing_Failed()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var first = new Style(Color.White, Color.Yellow, Decoration.Bold | Decoration.Italic, "http://example.com");
 | 
			
		||||
            var second = new Style(Color.Blue, Color.Yellow, Decoration.Bold | Decoration.Italic, "http://example.com");
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            var result = first.Equals(second);
 | 
			
		||||
            // Given, When
 | 
			
		||||
            var result = Style.TryParse("lol", out _);
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ShouldBeFalse();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Not_Consider_Two_Styles_With_Different_Background_Colors_Equal()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var first = new Style(Color.White, Color.Yellow, Decoration.Bold | Decoration.Italic, "http://example.com");
 | 
			
		||||
            var second = new Style(Color.White, Color.Blue, Decoration.Bold | Decoration.Italic, "http://example.com");
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            var result = first.Equals(second);
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ShouldBeFalse();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Not_Consider_Two_Styles_With_Different_Decorations_Equal()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var first = new Style(Color.White, Color.Yellow, Decoration.Bold | Decoration.Italic, "http://example.com");
 | 
			
		||||
            var second = new Style(Color.White, Color.Yellow, Decoration.Bold, "http://example.com");
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            var result = first.Equals(second);
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ShouldBeFalse();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Not_Consider_Two_Styles_With_Different_Links_Equal()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var first = new Style(Color.White, Color.Yellow, Decoration.Bold | Decoration.Italic, "http://example.com");
 | 
			
		||||
            var second = new Style(Color.White, Color.Yellow, Decoration.Bold | Decoration.Italic, "http://foo.com");
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            var result = first.Equals(second);
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ShouldBeFalse();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public sealed class TheParseMethod
 | 
			
		||||
        {
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Default_Keyword_Should_Return_Default_Style()
 | 
			
		||||
            {
 | 
			
		||||
                // Given, When
 | 
			
		||||
                var result = Style.Parse("default");
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ShouldNotBeNull();
 | 
			
		||||
                result.Foreground.ShouldBe(Color.Default);
 | 
			
		||||
                result.Background.ShouldBe(Color.Default);
 | 
			
		||||
                result.Decoration.ShouldBe(Decoration.None);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Theory]
 | 
			
		||||
            [InlineData("bold", Decoration.Bold)]
 | 
			
		||||
            [InlineData("b", Decoration.Bold)]
 | 
			
		||||
            [InlineData("dim", Decoration.Dim)]
 | 
			
		||||
            [InlineData("i", Decoration.Italic)]
 | 
			
		||||
            [InlineData("italic", Decoration.Italic)]
 | 
			
		||||
            [InlineData("underline", Decoration.Underline)]
 | 
			
		||||
            [InlineData("u", Decoration.Underline)]
 | 
			
		||||
            [InlineData("invert", Decoration.Invert)]
 | 
			
		||||
            [InlineData("conceal", Decoration.Conceal)]
 | 
			
		||||
            [InlineData("slowblink", Decoration.SlowBlink)]
 | 
			
		||||
            [InlineData("rapidblink", Decoration.RapidBlink)]
 | 
			
		||||
            [InlineData("strikethrough", Decoration.Strikethrough)]
 | 
			
		||||
            [InlineData("s", Decoration.Strikethrough)]
 | 
			
		||||
            public void Should_Parse_Decoration(string text, Decoration decoration)
 | 
			
		||||
            {
 | 
			
		||||
                // Given, When
 | 
			
		||||
                var result = Style.Parse(text);
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ShouldNotBeNull();
 | 
			
		||||
                result.Decoration.ShouldBe(decoration);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Parse_Link_Without_Address()
 | 
			
		||||
            {
 | 
			
		||||
                // Given, When
 | 
			
		||||
                var result = Style.Parse("link");
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ShouldNotBeNull();
 | 
			
		||||
                result.Link.ShouldBe("https://emptylink");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Parse_Link()
 | 
			
		||||
            {
 | 
			
		||||
                // Given, When
 | 
			
		||||
                var result = Style.Parse("link=https://example.com");
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ShouldNotBeNull();
 | 
			
		||||
                result.Link.ShouldBe("https://example.com");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Throw_If_Link_Is_Set_Twice()
 | 
			
		||||
            {
 | 
			
		||||
                // Given, When
 | 
			
		||||
                var result = Record.Exception(() => Style.Parse("link=https://example.com link=https://example.com"));
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ShouldBeOfType<InvalidOperationException>();
 | 
			
		||||
                result.Message.ShouldBe("A link has already been set.");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Parse_Background_If_Foreground_Is_Set_To_Default()
 | 
			
		||||
            {
 | 
			
		||||
                // Given, When
 | 
			
		||||
                var result = Style.Parse("default on green");
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ShouldNotBeNull();
 | 
			
		||||
                result.Decoration.ShouldBe(Decoration.None);
 | 
			
		||||
                result.Foreground.ShouldBe(Color.Default);
 | 
			
		||||
                result.Background.ShouldBe(Color.Green);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Throw_If_Foreground_Is_Set_Twice()
 | 
			
		||||
            {
 | 
			
		||||
                // Given, When
 | 
			
		||||
                var result = Record.Exception(() => Style.Parse("green yellow"));
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ShouldBeOfType<InvalidOperationException>();
 | 
			
		||||
                result.Message.ShouldBe("A foreground color has already been set.");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Throw_If_Background_Is_Set_Twice()
 | 
			
		||||
            {
 | 
			
		||||
                // Given, When
 | 
			
		||||
                var result = Record.Exception(() => Style.Parse("green on blue yellow"));
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ShouldBeOfType<InvalidOperationException>();
 | 
			
		||||
                result.Message.ShouldBe("A background color has already been set.");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Throw_If_Color_Name_Could_Not_Be_Found()
 | 
			
		||||
            {
 | 
			
		||||
                // Given, When
 | 
			
		||||
                var result = Record.Exception(() => Style.Parse("bold lol"));
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ShouldBeOfType<InvalidOperationException>();
 | 
			
		||||
                result.Message.ShouldBe("Could not find color or style 'lol'.");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Throw_If_Background_Color_Name_Could_Not_Be_Found()
 | 
			
		||||
            {
 | 
			
		||||
                // Given, When
 | 
			
		||||
                var result = Record.Exception(() => Style.Parse("blue on lol"));
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ShouldBeOfType<InvalidOperationException>();
 | 
			
		||||
                result.Message.ShouldBe("Could not find color 'lol'.");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Parse_Colors_And_Decoration_And_Link()
 | 
			
		||||
            {
 | 
			
		||||
                // Given, When
 | 
			
		||||
                var result = Style.Parse("link=https://example.com bold underline blue on green");
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ShouldNotBeNull();
 | 
			
		||||
                result.Decoration.ShouldBe(Decoration.Bold | Decoration.Underline);
 | 
			
		||||
                result.Foreground.ShouldBe(Color.Blue);
 | 
			
		||||
                result.Background.ShouldBe(Color.Green);
 | 
			
		||||
                result.Link.ShouldBe("https://example.com");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Theory]
 | 
			
		||||
            [InlineData("#FF0000 on #0000FF")]
 | 
			
		||||
            [InlineData("#F00 on #00F")]
 | 
			
		||||
            public void Should_Parse_Hex_Colors_Correctly(string style)
 | 
			
		||||
            {
 | 
			
		||||
                // Given, When
 | 
			
		||||
                var result = Style.Parse(style);
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.Foreground.ShouldBe(Color.Red);
 | 
			
		||||
                result.Background.ShouldBe(Color.Blue);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Theory]
 | 
			
		||||
            [InlineData("#", "Invalid hex color '#'.")]
 | 
			
		||||
            [InlineData("#FF00FF00FF", "Invalid hex color '#FF00FF00FF'.")]
 | 
			
		||||
            [InlineData("#FOO", "Invalid hex color '#FOO'. Could not find any recognizable digits.")]
 | 
			
		||||
            public void Should_Return_Error_If_Hex_Color_Is_Invalid(string style, string expected)
 | 
			
		||||
            {
 | 
			
		||||
                // Given, When
 | 
			
		||||
                var result = Record.Exception(() => Style.Parse(style));
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ShouldNotBeNull();
 | 
			
		||||
                result.Message.ShouldBe(expected);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Theory]
 | 
			
		||||
            [InlineData("rgb(255,0,0) on rgb(0,0,255)")]
 | 
			
		||||
            public void Should_Parse_Rgb_Colors_Correctly(string style)
 | 
			
		||||
            {
 | 
			
		||||
                // Given, When
 | 
			
		||||
                var result = Style.Parse(style);
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.Foreground.ShouldBe(Color.Red);
 | 
			
		||||
                result.Background.ShouldBe(Color.Blue);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Theory]
 | 
			
		||||
            [InlineData("12 on 24")]
 | 
			
		||||
            public void Should_Parse_Colors_Numbers_Correctly(string style)
 | 
			
		||||
            {
 | 
			
		||||
                // Given, When
 | 
			
		||||
                var result = Style.Parse(style);
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.Foreground.ShouldBe(Color.Blue);
 | 
			
		||||
                result.Background.ShouldBe(Color.DeepSkyBlue4_1);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Theory]
 | 
			
		||||
            [InlineData("-12", "Color number must be greater than or equal to 0 (was -12)")]
 | 
			
		||||
            [InlineData("256", "Color number must be less than or equal to 255 (was 256)")]
 | 
			
		||||
            public void Should_Return_Error_If_Color_Number_Is_Invalid(string style, string expected)
 | 
			
		||||
            {
 | 
			
		||||
                // Given, When
 | 
			
		||||
                var result = Record.Exception(() => Style.Parse(style));
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ShouldNotBeNull();
 | 
			
		||||
                result.Message.ShouldBe(expected);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Theory]
 | 
			
		||||
            [InlineData("rgb()", "Invalid RGB color 'rgb()'.")]
 | 
			
		||||
            [InlineData("rgb(", "Invalid RGB color 'rgb('.")]
 | 
			
		||||
            [InlineData("rgb(255)", "Invalid RGB color 'rgb(255)'.")]
 | 
			
		||||
            [InlineData("rgb(255,255)", "Invalid RGB color 'rgb(255,255)'.")]
 | 
			
		||||
            [InlineData("rgb(255,255,255", "Invalid RGB color 'rgb(255,255,255'.")]
 | 
			
		||||
            [InlineData("rgb(A,B,C)", "Invalid RGB color 'rgb(A,B,C)'. Input string was not in a correct format.")]
 | 
			
		||||
            public void Should_Return_Error_If_Rgb_Color_Is_Invalid(string style, string expected)
 | 
			
		||||
            {
 | 
			
		||||
                // Given, When
 | 
			
		||||
                var result = Record.Exception(() => Style.Parse(style));
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ShouldNotBeNull();
 | 
			
		||||
                result.Message.ShouldBe(expected);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public sealed class TheTryParseMethod
 | 
			
		||||
        {
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Return_True_If_Parsing_Succeeded()
 | 
			
		||||
            {
 | 
			
		||||
                // Given, When
 | 
			
		||||
                var result = Style.TryParse("bold", out var style);
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ShouldBeTrue();
 | 
			
		||||
                style.ShouldNotBeNull();
 | 
			
		||||
                style.Decoration.ShouldBe(Decoration.Bold);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Return_False_If_Parsing_Failed()
 | 
			
		||||
            {
 | 
			
		||||
                // Given, When
 | 
			
		||||
                var result = Style.TryParse("lol", out _);
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ShouldBeFalse();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public sealed class TheToMarkupMethod
 | 
			
		||||
        {
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Return_Expected_Markup_For_Style_With_Foreground_Color()
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var style = new Style(Color.Red);
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = style.ToMarkup();
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ShouldBe("red");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Return_Expected_Markup_For_Style_With_Foreground_And_Background_Color()
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var style = new Style(Color.Red, Color.Green);
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = style.ToMarkup();
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ShouldBe("red on green");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Return_Expected_Markup_For_Style_With_Foreground_And_Background_Color_And_Decoration()
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var style = new Style(Color.Red, Color.Green, Decoration.Bold | Decoration.Underline);
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = style.ToMarkup();
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ShouldBe("bold underline red on green");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Return_Expected_Markup_For_Style_With_Only_Background_Color()
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var style = new Style(background: Color.Green);
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = style.ToMarkup();
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ShouldBe("default on green");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    public sealed class TheToMarkupMethod
 | 
			
		||||
    {
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Return_Expected_Markup_For_Style_With_Foreground_Color()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var style = new Style(Color.Red);
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            var result = style.ToMarkup();
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ShouldBe("red");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Return_Expected_Markup_For_Style_With_Foreground_And_Background_Color()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var style = new Style(Color.Red, Color.Green);
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            var result = style.ToMarkup();
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ShouldBe("red on green");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Return_Expected_Markup_For_Style_With_Foreground_And_Background_Color_And_Decoration()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var style = new Style(Color.Red, Color.Green, Decoration.Bold | Decoration.Underline);
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            var result = style.ToMarkup();
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ShouldBe("bold underline red on green");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Return_Expected_Markup_For_Style_With_Only_Background_Color()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var style = new Style(background: Color.Green);
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            var result = style.ToMarkup();
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ShouldBe("default on green");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,72 +1,64 @@
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Spectre.Console.Testing;
 | 
			
		||||
using Spectre.Verify.Extensions;
 | 
			
		||||
using VerifyXunit;
 | 
			
		||||
using Xunit;
 | 
			
		||||
namespace Spectre.Console.Tests.Unit;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Unit
 | 
			
		||||
[UsesVerify]
 | 
			
		||||
[ExpectationPath("Widgets/BarChart")]
 | 
			
		||||
public sealed class BarChartTests
 | 
			
		||||
{
 | 
			
		||||
    [UsesVerify]
 | 
			
		||||
    [ExpectationPath("Widgets/BarChart")]
 | 
			
		||||
    public sealed class BarChartTests
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("Render")]
 | 
			
		||||
    public async Task Should_Render_Correctly()
 | 
			
		||||
    {
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Render")]
 | 
			
		||||
        public async Task Should_Render_Correctly()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole();
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(new BarChart()
 | 
			
		||||
                .Width(60)
 | 
			
		||||
                .Label("Number of fruits")
 | 
			
		||||
                .AddItem("Apple", 12)
 | 
			
		||||
                .AddItem("Orange", 54)
 | 
			
		||||
                .AddItem("Banana", 33));
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            await Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Zero_Value")]
 | 
			
		||||
        public async Task Should_Render_Correctly_2()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(new BarChart()
 | 
			
		||||
                .Width(60)
 | 
			
		||||
                .Label("Number of fruits")
 | 
			
		||||
                .AddItem("Apple", 0)
 | 
			
		||||
                .AddItem("Orange", 54)
 | 
			
		||||
                .AddItem("Banana", 33));
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            await Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Fixed_Max_Value")]
 | 
			
		||||
        public async Task Should_Render_Correctly_3()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(new BarChart()
 | 
			
		||||
                .Width(60)
 | 
			
		||||
                .WithMaxValue(100)
 | 
			
		||||
                .Label("Number of fruits")
 | 
			
		||||
                .AddItem("Apple", 12)
 | 
			
		||||
                .AddItem("Orange", 54)
 | 
			
		||||
                .AddItem("Banana", 33));
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            await Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
        // When
 | 
			
		||||
        console.Write(new BarChart()
 | 
			
		||||
            .Width(60)
 | 
			
		||||
            .Label("Number of fruits")
 | 
			
		||||
            .AddItem("Apple", 12)
 | 
			
		||||
            .AddItem("Orange", 54)
 | 
			
		||||
            .AddItem("Banana", 33));
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        await Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("Zero_Value")]
 | 
			
		||||
    public async Task Should_Render_Correctly_2()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole();
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.Write(new BarChart()
 | 
			
		||||
            .Width(60)
 | 
			
		||||
            .Label("Number of fruits")
 | 
			
		||||
            .AddItem("Apple", 0)
 | 
			
		||||
            .AddItem("Orange", 54)
 | 
			
		||||
            .AddItem("Banana", 33));
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        await Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("Fixed_Max_Value")]
 | 
			
		||||
    public async Task Should_Render_Correctly_3()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole();
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.Write(new BarChart()
 | 
			
		||||
            .Width(60)
 | 
			
		||||
            .WithMaxValue(100)
 | 
			
		||||
            .Label("Number of fruits")
 | 
			
		||||
            .AddItem("Apple", 12)
 | 
			
		||||
            .AddItem("Orange", 54)
 | 
			
		||||
            .AddItem("Banana", 33));
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        await Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,150 +1,143 @@
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Spectre.Console.Testing;
 | 
			
		||||
using Spectre.Verify.Extensions;
 | 
			
		||||
using VerifyXunit;
 | 
			
		||||
using Xunit;
 | 
			
		||||
namespace Spectre.Console.Tests.Unit;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Unit
 | 
			
		||||
[UsesVerify]
 | 
			
		||||
[ExpectationPath("Widgets/BreakdownChart")]
 | 
			
		||||
public sealed class BreakdownChartTests
 | 
			
		||||
{
 | 
			
		||||
    [UsesVerify]
 | 
			
		||||
    [ExpectationPath("Widgets/BreakdownChart")]
 | 
			
		||||
    public sealed class BreakdownChartTests
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("Default")]
 | 
			
		||||
    public async Task Should_Render_Correctly()
 | 
			
		||||
    {
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Default")]
 | 
			
		||||
        public async Task Should_Render_Correctly()
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole();
 | 
			
		||||
        var chart = Fixture.GetChart();
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.Write(chart);
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        await Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("Width")]
 | 
			
		||||
    public async Task Should_Render_With_Specific_Width()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole();
 | 
			
		||||
        var chart = Fixture.GetChart().Width(60);
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.Write(chart);
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        await Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("TagFormat")]
 | 
			
		||||
    public async Task Should_Render_Correctly_With_Specific_Value_Formatter()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole();
 | 
			
		||||
        var chart = Fixture.GetChart()
 | 
			
		||||
            .Width(60)
 | 
			
		||||
            .Culture("sv-SE")
 | 
			
		||||
            .UseValueFormatter((v, c) => string.Format(c, "{0}%", v));
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.Write(chart);
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        await Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("HideTags")]
 | 
			
		||||
    public async Task Should_Render_Correctly_Without_Tags()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole();
 | 
			
		||||
        var chart = Fixture.GetChart().Width(60).HideTags();
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.Write(chart);
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        await Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("HideTagValues")]
 | 
			
		||||
    public async Task Should_Render_Correctly_Without_Tag_Values()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole();
 | 
			
		||||
        var chart = Fixture.GetChart().Width(60).HideTagValues();
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.Write(chart);
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        await Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("Culture")]
 | 
			
		||||
    public async Task Should_Render_Correctly_With_Specific_Culture()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole();
 | 
			
		||||
        var chart = Fixture.GetChart().Width(60).Culture("sv-SE");
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.Write(chart);
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        await Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("FullSize")]
 | 
			
		||||
    public async Task Should_Render_FullSize_Mode_Correctly()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole();
 | 
			
		||||
        var chart = Fixture.GetChart().Width(60).FullSize();
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.Write(chart);
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        await Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("Ansi")]
 | 
			
		||||
    public async Task Should_Render_Correct_Ansi()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole().EmitAnsiSequences();
 | 
			
		||||
        var chart = Fixture.GetChart().Width(60).FullSize();
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.Write(chart);
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        await Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static class Fixture
 | 
			
		||||
    {
 | 
			
		||||
        public static BreakdownChart GetChart()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
            var chart = Fixture.GetChart();
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(chart);
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            await Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Width")]
 | 
			
		||||
        public async Task Should_Render_With_Specific_Width()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
            var chart = Fixture.GetChart().Width(60);
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(chart);
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            await Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("TagFormat")]
 | 
			
		||||
        public async Task Should_Render_Correctly_With_Specific_Value_Formatter()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
            var chart = Fixture.GetChart()
 | 
			
		||||
                .Width(60)
 | 
			
		||||
                .Culture("sv-SE")
 | 
			
		||||
                .UseValueFormatter((v, c) => string.Format(c, "{0}%", v));
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(chart);
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            await Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("HideTags")]
 | 
			
		||||
        public async Task Should_Render_Correctly_Without_Tags()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
            var chart = Fixture.GetChart().Width(60).HideTags();
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(chart);
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            await Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("HideTagValues")]
 | 
			
		||||
        public async Task Should_Render_Correctly_Without_Tag_Values()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
            var chart = Fixture.GetChart().Width(60).HideTagValues();
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(chart);
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            await Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Culture")]
 | 
			
		||||
        public async Task Should_Render_Correctly_With_Specific_Culture()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
            var chart = Fixture.GetChart().Width(60).Culture("sv-SE");
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(chart);
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            await Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("FullSize")]
 | 
			
		||||
        public async Task Should_Render_FullSize_Mode_Correctly()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
            var chart = Fixture.GetChart().Width(60).FullSize();
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(chart);
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            await Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Ansi")]
 | 
			
		||||
        public async Task Should_Render_Correct_Ansi()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole().EmitAnsiSequences();
 | 
			
		||||
            var chart = Fixture.GetChart().Width(60).FullSize();
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(chart);
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            await Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static class Fixture
 | 
			
		||||
        {
 | 
			
		||||
            public static BreakdownChart GetChart()
 | 
			
		||||
            {
 | 
			
		||||
                return new BreakdownChart()
 | 
			
		||||
                    .AddItem("SCSS", 37, Color.Red)
 | 
			
		||||
                    .AddItem("HTML", 28.3, Color.Blue)
 | 
			
		||||
                    .AddItem("C#", 22.6, Color.Green)
 | 
			
		||||
                    .AddItem("JavaScript", 6, Color.Yellow)
 | 
			
		||||
                    .AddItem("Ruby", 6, Color.LightGreen)
 | 
			
		||||
                    .AddItem("Shell", 0.1, Color.Aqua);
 | 
			
		||||
            }
 | 
			
		||||
            return new BreakdownChart()
 | 
			
		||||
                .AddItem("SCSS", 37, Color.Red)
 | 
			
		||||
                .AddItem("HTML", 28.3, Color.Blue)
 | 
			
		||||
                .AddItem("C#", 22.6, Color.Green)
 | 
			
		||||
                .AddItem("JavaScript", 6, Color.Yellow)
 | 
			
		||||
                .AddItem("Ruby", 6, Color.LightGreen)
 | 
			
		||||
                .AddItem("Shell", 0.1, Color.Aqua);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,108 +1,100 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Spectre.Console.Testing;
 | 
			
		||||
using Spectre.Verify.Extensions;
 | 
			
		||||
using VerifyXunit;
 | 
			
		||||
using Xunit;
 | 
			
		||||
namespace Spectre.Console.Tests.Unit;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Unit
 | 
			
		||||
[UsesVerify]
 | 
			
		||||
[ExpectationPath("Widgets/Calendar")]
 | 
			
		||||
public sealed class CalendarTests
 | 
			
		||||
{
 | 
			
		||||
    [UsesVerify]
 | 
			
		||||
    [ExpectationPath("Widgets/Calendar")]
 | 
			
		||||
    public sealed class CalendarTests
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("Render")]
 | 
			
		||||
    public Task Should_Render_Calendar_Correctly()
 | 
			
		||||
    {
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Render")]
 | 
			
		||||
        public Task Should_Render_Calendar_Correctly()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
            var calendar = new Calendar(2020, 10)
 | 
			
		||||
                .AddCalendarEvent(new DateTime(2020, 9, 1))
 | 
			
		||||
                .AddCalendarEvent(new DateTime(2020, 10, 3))
 | 
			
		||||
                .AddCalendarEvent(new DateTime(2020, 10, 12));
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole();
 | 
			
		||||
        var calendar = new Calendar(2020, 10)
 | 
			
		||||
            .AddCalendarEvent(new DateTime(2020, 9, 1))
 | 
			
		||||
            .AddCalendarEvent(new DateTime(2020, 10, 3))
 | 
			
		||||
            .AddCalendarEvent(new DateTime(2020, 10, 12));
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(calendar);
 | 
			
		||||
        // When
 | 
			
		||||
        console.Write(calendar);
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Centered")]
 | 
			
		||||
        public Task Should_Center_Calendar_Correctly()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
            var calendar = new Calendar(2020, 10)
 | 
			
		||||
                .Centered()
 | 
			
		||||
                .AddCalendarEvent(new DateTime(2020, 9, 1))
 | 
			
		||||
                .AddCalendarEvent(new DateTime(2020, 10, 3))
 | 
			
		||||
                .AddCalendarEvent(new DateTime(2020, 10, 12));
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(calendar);
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("LeftAligned")]
 | 
			
		||||
        public Task Should_Left_Align_Calendar_Correctly()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
            var calendar = new Calendar(2020, 10)
 | 
			
		||||
                .LeftAligned()
 | 
			
		||||
                .AddCalendarEvent(new DateTime(2020, 9, 1))
 | 
			
		||||
                .AddCalendarEvent(new DateTime(2020, 10, 3))
 | 
			
		||||
                .AddCalendarEvent(new DateTime(2020, 10, 12));
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(calendar);
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("RightAligned")]
 | 
			
		||||
        public Task Should_Right_Align_Calendar_Correctly()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
            var calendar = new Calendar(2020, 10)
 | 
			
		||||
                .RightAligned()
 | 
			
		||||
                .AddCalendarEvent(new DateTime(2020, 9, 1))
 | 
			
		||||
                .AddCalendarEvent(new DateTime(2020, 10, 3))
 | 
			
		||||
                .AddCalendarEvent(new DateTime(2020, 10, 12));
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(calendar);
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Culture")]
 | 
			
		||||
        public Task Should_Render_Calendar_Correctly_For_Specific_Culture()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
            var calendar = new Calendar(2020, 10, 15)
 | 
			
		||||
                .Culture("de-DE")
 | 
			
		||||
                .AddCalendarEvent(new DateTime(2020, 9, 1))
 | 
			
		||||
                .AddCalendarEvent(new DateTime(2020, 10, 3))
 | 
			
		||||
                .AddCalendarEvent(new DateTime(2020, 10, 12));
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(calendar);
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
        // Then
 | 
			
		||||
        return Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("Centered")]
 | 
			
		||||
    public Task Should_Center_Calendar_Correctly()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole();
 | 
			
		||||
        var calendar = new Calendar(2020, 10)
 | 
			
		||||
            .Centered()
 | 
			
		||||
            .AddCalendarEvent(new DateTime(2020, 9, 1))
 | 
			
		||||
            .AddCalendarEvent(new DateTime(2020, 10, 3))
 | 
			
		||||
            .AddCalendarEvent(new DateTime(2020, 10, 12));
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.Write(calendar);
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        return Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("LeftAligned")]
 | 
			
		||||
    public Task Should_Left_Align_Calendar_Correctly()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole();
 | 
			
		||||
        var calendar = new Calendar(2020, 10)
 | 
			
		||||
            .LeftAligned()
 | 
			
		||||
            .AddCalendarEvent(new DateTime(2020, 9, 1))
 | 
			
		||||
            .AddCalendarEvent(new DateTime(2020, 10, 3))
 | 
			
		||||
            .AddCalendarEvent(new DateTime(2020, 10, 12));
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.Write(calendar);
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        return Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("RightAligned")]
 | 
			
		||||
    public Task Should_Right_Align_Calendar_Correctly()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole();
 | 
			
		||||
        var calendar = new Calendar(2020, 10)
 | 
			
		||||
            .RightAligned()
 | 
			
		||||
            .AddCalendarEvent(new DateTime(2020, 9, 1))
 | 
			
		||||
            .AddCalendarEvent(new DateTime(2020, 10, 3))
 | 
			
		||||
            .AddCalendarEvent(new DateTime(2020, 10, 12));
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.Write(calendar);
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        return Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("Culture")]
 | 
			
		||||
    public Task Should_Render_Calendar_Correctly_For_Specific_Culture()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole();
 | 
			
		||||
        var calendar = new Calendar(2020, 10, 15)
 | 
			
		||||
            .Culture("de-DE")
 | 
			
		||||
            .AddCalendarEvent(new DateTime(2020, 9, 1))
 | 
			
		||||
            .AddCalendarEvent(new DateTime(2020, 10, 3))
 | 
			
		||||
            .AddCalendarEvent(new DateTime(2020, 10, 12));
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.Write(calendar);
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        return Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,143 +1,134 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Shouldly;
 | 
			
		||||
using Spectre.Console.Testing;
 | 
			
		||||
using Spectre.Verify.Extensions;
 | 
			
		||||
using VerifyXunit;
 | 
			
		||||
using Xunit;
 | 
			
		||||
namespace Spectre.Console.Tests.Unit;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Unit
 | 
			
		||||
[UsesVerify]
 | 
			
		||||
[ExpectationPath("Widgets/Canvas")]
 | 
			
		||||
public class CanvasTests
 | 
			
		||||
{
 | 
			
		||||
    [UsesVerify]
 | 
			
		||||
    [ExpectationPath("Widgets/Canvas")]
 | 
			
		||||
    public class CanvasTests
 | 
			
		||||
    public sealed class TheConstructor
 | 
			
		||||
    {
 | 
			
		||||
        public sealed class TheConstructor
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Throw_If_Width_Is_Less_Than_Zero()
 | 
			
		||||
        {
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Throw_If_Width_Is_Less_Than_Zero()
 | 
			
		||||
            {
 | 
			
		||||
                // Given, When
 | 
			
		||||
                var result = Record.Exception(() => new Canvas(0, 1));
 | 
			
		||||
            // Given, When
 | 
			
		||||
            var result = Record.Exception(() => new Canvas(0, 1));
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ShouldBeOfType<ArgumentException>()
 | 
			
		||||
                    .And(ex => ex.ParamName.ShouldBe("width"));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Throw_If_Height_Is_Less_Than_Zero()
 | 
			
		||||
            {
 | 
			
		||||
                // Given, When
 | 
			
		||||
                var result = Record.Exception(() => new Canvas(1, 0));
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ShouldBeOfType<ArgumentException>()
 | 
			
		||||
                    .And(ex => ex.ParamName.ShouldBe("height"));
 | 
			
		||||
            }
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ShouldBeOfType<ArgumentException>()
 | 
			
		||||
                .And(ex => ex.ParamName.ShouldBe("width"));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Render")]
 | 
			
		||||
        public async Task Should_Render_Canvas_Correctly()
 | 
			
		||||
        public void Should_Throw_If_Height_Is_Less_Than_Zero()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole()
 | 
			
		||||
                .Colors(ColorSystem.Standard)
 | 
			
		||||
                .EmitAnsiSequences();
 | 
			
		||||
 | 
			
		||||
            var canvas = new Canvas(width: 5, height: 5);
 | 
			
		||||
            canvas.SetPixel(0, 0, Color.Red);
 | 
			
		||||
            canvas.SetPixel(4, 0, Color.Green);
 | 
			
		||||
            canvas.SetPixel(0, 4, Color.Blue);
 | 
			
		||||
            canvas.SetPixel(4, 4, Color.Yellow);
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(canvas);
 | 
			
		||||
            // Given, When
 | 
			
		||||
            var result = Record.Exception(() => new Canvas(1, 0));
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            await Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Render_Nested")]
 | 
			
		||||
        public async Task Simple_Measure()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole()
 | 
			
		||||
                .Colors(ColorSystem.Standard)
 | 
			
		||||
                .EmitAnsiSequences();
 | 
			
		||||
 | 
			
		||||
            var panel = new Panel(new Canvas(width: 2, height: 2)
 | 
			
		||||
                .SetPixel(0, 0, Color.Aqua)
 | 
			
		||||
                .SetPixel(1, 1, Color.Grey));
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(panel);
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            await Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Render_NarrowTerminal")]
 | 
			
		||||
        public async Task Should_Scale_Down_Canvas_Is_Bigger_Than_Terminal()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole()
 | 
			
		||||
                .Width(10)
 | 
			
		||||
                .Colors(ColorSystem.Standard)
 | 
			
		||||
                .EmitAnsiSequences();
 | 
			
		||||
 | 
			
		||||
            var canvas = new Canvas(width: 20, height: 10);
 | 
			
		||||
            canvas.SetPixel(0, 0, Color.Aqua);
 | 
			
		||||
            canvas.SetPixel(19, 9, Color.Grey);
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(canvas);
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            await Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Render_MaxWidth")]
 | 
			
		||||
        public async Task Should_Scale_Down_Canvas_If_MaxWidth_Is_Set()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole()
 | 
			
		||||
                .Colors(ColorSystem.Standard)
 | 
			
		||||
                .EmitAnsiSequences();
 | 
			
		||||
 | 
			
		||||
            var canvas = new Canvas(width: 20, height: 10) { MaxWidth = 10 };
 | 
			
		||||
            canvas.SetPixel(0, 0, Color.Aqua);
 | 
			
		||||
            canvas.SetPixel(19, 9, Color.Aqua);
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(canvas);
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            await Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Not_Render_Canvas_If_Canvas_Cannot_Be_Scaled_Down()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole()
 | 
			
		||||
                .Width(10)
 | 
			
		||||
                .Colors(ColorSystem.Standard)
 | 
			
		||||
                .EmitAnsiSequences();
 | 
			
		||||
 | 
			
		||||
            var canvas = new Canvas(width: 20, height: 2);
 | 
			
		||||
            canvas.SetPixel(0, 0, Color.Aqua);
 | 
			
		||||
            canvas.SetPixel(19, 1, Color.Grey);
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(canvas);
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            console.Output.ShouldBeEmpty();
 | 
			
		||||
            result.ShouldBeOfType<ArgumentException>()
 | 
			
		||||
                .And(ex => ex.ParamName.ShouldBe("height"));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("Render")]
 | 
			
		||||
    public async Task Should_Render_Canvas_Correctly()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole()
 | 
			
		||||
            .Colors(ColorSystem.Standard)
 | 
			
		||||
            .EmitAnsiSequences();
 | 
			
		||||
 | 
			
		||||
        var canvas = new Canvas(width: 5, height: 5);
 | 
			
		||||
        canvas.SetPixel(0, 0, Color.Red);
 | 
			
		||||
        canvas.SetPixel(4, 0, Color.Green);
 | 
			
		||||
        canvas.SetPixel(0, 4, Color.Blue);
 | 
			
		||||
        canvas.SetPixel(4, 4, Color.Yellow);
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.Write(canvas);
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        await Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("Render_Nested")]
 | 
			
		||||
    public async Task Simple_Measure()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole()
 | 
			
		||||
            .Colors(ColorSystem.Standard)
 | 
			
		||||
            .EmitAnsiSequences();
 | 
			
		||||
 | 
			
		||||
        var panel = new Panel(new Canvas(width: 2, height: 2)
 | 
			
		||||
            .SetPixel(0, 0, Color.Aqua)
 | 
			
		||||
            .SetPixel(1, 1, Color.Grey));
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.Write(panel);
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        await Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("Render_NarrowTerminal")]
 | 
			
		||||
    public async Task Should_Scale_Down_Canvas_Is_Bigger_Than_Terminal()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole()
 | 
			
		||||
            .Width(10)
 | 
			
		||||
            .Colors(ColorSystem.Standard)
 | 
			
		||||
            .EmitAnsiSequences();
 | 
			
		||||
 | 
			
		||||
        var canvas = new Canvas(width: 20, height: 10);
 | 
			
		||||
        canvas.SetPixel(0, 0, Color.Aqua);
 | 
			
		||||
        canvas.SetPixel(19, 9, Color.Grey);
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.Write(canvas);
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        await Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("Render_MaxWidth")]
 | 
			
		||||
    public async Task Should_Scale_Down_Canvas_If_MaxWidth_Is_Set()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole()
 | 
			
		||||
            .Colors(ColorSystem.Standard)
 | 
			
		||||
            .EmitAnsiSequences();
 | 
			
		||||
 | 
			
		||||
        var canvas = new Canvas(width: 20, height: 10) { MaxWidth = 10 };
 | 
			
		||||
        canvas.SetPixel(0, 0, Color.Aqua);
 | 
			
		||||
        canvas.SetPixel(19, 9, Color.Aqua);
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.Write(canvas);
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        await Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    public void Should_Not_Render_Canvas_If_Canvas_Cannot_Be_Scaled_Down()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole()
 | 
			
		||||
            .Width(10)
 | 
			
		||||
            .Colors(ColorSystem.Standard)
 | 
			
		||||
            .EmitAnsiSequences();
 | 
			
		||||
 | 
			
		||||
        var canvas = new Canvas(width: 20, height: 2);
 | 
			
		||||
        canvas.SetPixel(0, 0, Color.Aqua);
 | 
			
		||||
        canvas.SetPixel(19, 1, Color.Grey);
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.Write(canvas);
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        console.Output.ShouldBeEmpty();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,48 +1,40 @@
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Spectre.Console.Testing;
 | 
			
		||||
using Spectre.Verify.Extensions;
 | 
			
		||||
using VerifyXunit;
 | 
			
		||||
using Xunit;
 | 
			
		||||
namespace Spectre.Console.Tests.Unit;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Unit
 | 
			
		||||
[UsesVerify]
 | 
			
		||||
[ExpectationPath("Widgets/Columns")]
 | 
			
		||||
public sealed class ColumnsTests
 | 
			
		||||
{
 | 
			
		||||
    [UsesVerify]
 | 
			
		||||
    [ExpectationPath("Widgets/Columns")]
 | 
			
		||||
    public sealed class ColumnsTests
 | 
			
		||||
    private sealed class User
 | 
			
		||||
    {
 | 
			
		||||
        private sealed class User
 | 
			
		||||
        {
 | 
			
		||||
            public string Name { get; set; }
 | 
			
		||||
            public string Country { get; set; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Render")]
 | 
			
		||||
        public Task Should_Render_Columns_Correctly()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole().Width(61);
 | 
			
		||||
            var users = new[]
 | 
			
		||||
            {
 | 
			
		||||
                new User { Name = "Savannah Thompson", Country = "Australia" },
 | 
			
		||||
                new User { Name = "Sophie Ramos", Country = "United States" },
 | 
			
		||||
                new User { Name = "Katrin Goldberg", Country = "Germany" },
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            var cards = new List<Panel>();
 | 
			
		||||
            foreach (var user in users)
 | 
			
		||||
            {
 | 
			
		||||
                cards.Add(
 | 
			
		||||
                    new Panel($"[b]{user.Name}[/]\n[yellow]{user.Country}[/]")
 | 
			
		||||
                        .RoundedBorder().Expand());
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(new Columns(cards));
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
        public string Name { get; set; }
 | 
			
		||||
        public string Country { get; set; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("Render")]
 | 
			
		||||
    public Task Should_Render_Columns_Correctly()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole().Width(61);
 | 
			
		||||
        var users = new[]
 | 
			
		||||
        {
 | 
			
		||||
            new User { Name = "Savannah Thompson", Country = "Australia" },
 | 
			
		||||
            new User { Name = "Sophie Ramos", Country = "United States" },
 | 
			
		||||
            new User { Name = "Katrin Goldberg", Country = "Germany" },
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        var cards = new List<Panel>();
 | 
			
		||||
        foreach (var user in users)
 | 
			
		||||
        {
 | 
			
		||||
            cards.Add(
 | 
			
		||||
                new Panel($"[b]{user.Name}[/]\n[yellow]{user.Country}[/]")
 | 
			
		||||
                    .RoundedBorder().Expand());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.Write(new Columns(cards));
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        return Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,107 +1,100 @@
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Spectre.Console.Testing;
 | 
			
		||||
using Spectre.Verify.Extensions;
 | 
			
		||||
using VerifyXunit;
 | 
			
		||||
using Xunit;
 | 
			
		||||
namespace Spectre.Console.Tests.Unit;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Unit
 | 
			
		||||
[UsesVerify]
 | 
			
		||||
[ExpectationPath("Widgets/Figlet")]
 | 
			
		||||
public sealed class FigletTests
 | 
			
		||||
{
 | 
			
		||||
    [UsesVerify]
 | 
			
		||||
    [ExpectationPath("Widgets/Figlet")]
 | 
			
		||||
    public sealed class FigletTests
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("Load_Stream")]
 | 
			
		||||
    public async Task Should_Load_Font_From_Stream()
 | 
			
		||||
    {
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Load_Stream")]
 | 
			
		||||
        public async Task Should_Load_Font_From_Stream()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole().Width(180);
 | 
			
		||||
            var font = FigletFont.Load(EmbeddedResourceReader.LoadResourceStream("Spectre.Console.Tests/Data/starwars.flf"));
 | 
			
		||||
            var text = new FigletText(font, "Patrik was here");
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole().Width(180);
 | 
			
		||||
        var font = FigletFont.Load(EmbeddedResourceReader.LoadResourceStream("Spectre.Console.Tests/Data/starwars.flf"));
 | 
			
		||||
        var text = new FigletText(font, "Patrik was here");
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(text);
 | 
			
		||||
        // When
 | 
			
		||||
        console.Write(text);
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            await Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Render")]
 | 
			
		||||
        public async Task Should_Render_Text_Correctly()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole().Width(70);
 | 
			
		||||
            var text = new FigletText(FigletFont.Default, "Patrik was here");
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(text);
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            await Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Render_Wrapped")]
 | 
			
		||||
        public async Task Should_Render_Wrapped_Text_Correctly()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole().Width(70);
 | 
			
		||||
            var text = new FigletText(FigletFont.Default, "Spectre.Console");
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(text);
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            await Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Render_LeftAligned")]
 | 
			
		||||
        public async Task Should_Render_Left_Aligned_Text_Correctly()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole().Width(120);
 | 
			
		||||
            var text = new FigletText(FigletFont.Default, "Spectre.Console")
 | 
			
		||||
                .Alignment(Justify.Left);
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(text);
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            await Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Render_Centered")]
 | 
			
		||||
        public async Task Should_Render_Centered_Text_Correctly()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole().Width(120);
 | 
			
		||||
            var text = new FigletText(FigletFont.Default, "Spectre.Console")
 | 
			
		||||
                .Alignment(Justify.Center);
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(text);
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            await Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Render_RightAligned")]
 | 
			
		||||
        public async Task Should_Render_Right_Aligned_Text_Correctly()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole().Width(120);
 | 
			
		||||
            var text = new FigletText(FigletFont.Default, "Spectre.Console")
 | 
			
		||||
                .Alignment(Justify.Right);
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(text);
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            await Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
        // Then
 | 
			
		||||
        await Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("Render")]
 | 
			
		||||
    public async Task Should_Render_Text_Correctly()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole().Width(70);
 | 
			
		||||
        var text = new FigletText(FigletFont.Default, "Patrik was here");
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.Write(text);
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        await Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("Render_Wrapped")]
 | 
			
		||||
    public async Task Should_Render_Wrapped_Text_Correctly()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole().Width(70);
 | 
			
		||||
        var text = new FigletText(FigletFont.Default, "Spectre.Console");
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.Write(text);
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        await Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("Render_LeftAligned")]
 | 
			
		||||
    public async Task Should_Render_Left_Aligned_Text_Correctly()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole().Width(120);
 | 
			
		||||
        var text = new FigletText(FigletFont.Default, "Spectre.Console")
 | 
			
		||||
            .Alignment(Justify.Left);
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.Write(text);
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        await Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("Render_Centered")]
 | 
			
		||||
    public async Task Should_Render_Centered_Text_Correctly()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole().Width(120);
 | 
			
		||||
        var text = new FigletText(FigletFont.Default, "Spectre.Console")
 | 
			
		||||
            .Alignment(Justify.Center);
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.Write(text);
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        await Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("Render_RightAligned")]
 | 
			
		||||
    public async Task Should_Render_Right_Aligned_Text_Correctly()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole().Width(120);
 | 
			
		||||
        var text = new FigletText(FigletFont.Default, "Spectre.Console")
 | 
			
		||||
            .Alignment(Justify.Right);
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.Write(text);
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        await Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,200 +1,91 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Shouldly;
 | 
			
		||||
using Spectre.Console.Testing;
 | 
			
		||||
using Spectre.Verify.Extensions;
 | 
			
		||||
using VerifyXunit;
 | 
			
		||||
using Xunit;
 | 
			
		||||
namespace Spectre.Console.Tests.Unit;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Unit
 | 
			
		||||
[UsesVerify]
 | 
			
		||||
[ExpectationPath("Widgets/Grid")]
 | 
			
		||||
public sealed class GridTests
 | 
			
		||||
{
 | 
			
		||||
    [UsesVerify]
 | 
			
		||||
    [ExpectationPath("Widgets/Grid")]
 | 
			
		||||
    public sealed class GridTests
 | 
			
		||||
    public sealed class TheAddColumnMethod
 | 
			
		||||
    {
 | 
			
		||||
        public sealed class TheAddColumnMethod
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Throw_If_Rows_Are_Not_Empty()
 | 
			
		||||
        {
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Throw_If_Rows_Are_Not_Empty()
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var grid = new Grid();
 | 
			
		||||
                grid.AddColumn();
 | 
			
		||||
                grid.AddRow("Hello World!");
 | 
			
		||||
            // Given
 | 
			
		||||
            var grid = new Grid();
 | 
			
		||||
            grid.AddColumn();
 | 
			
		||||
            grid.AddRow("Hello World!");
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = Record.Exception(() => grid.AddColumn());
 | 
			
		||||
            // When
 | 
			
		||||
            var result = Record.Exception(() => grid.AddColumn());
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ShouldBeOfType<InvalidOperationException>()
 | 
			
		||||
                    .Message.ShouldBe("Cannot add new columns to grid with existing rows.");
 | 
			
		||||
            }
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ShouldBeOfType<InvalidOperationException>()
 | 
			
		||||
                .Message.ShouldBe("Cannot add new columns to grid with existing rows.");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public sealed class TheAddRowMethod
 | 
			
		||||
    {
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Throw_If_Rows_Are_Null()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var grid = new Grid();
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            var result = Record.Exception(() => grid.AddRow(null));
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ShouldBeOfType<ArgumentNullException>()
 | 
			
		||||
                .ParamName.ShouldBe("columns");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public sealed class TheAddRowMethod
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Add_Empty_Items_If_User_Provides_Less_Row_Items_Than_Columns()
 | 
			
		||||
        {
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Throw_If_Rows_Are_Null()
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var grid = new Grid();
 | 
			
		||||
            // Given
 | 
			
		||||
            var grid = new Grid();
 | 
			
		||||
            grid.AddColumn();
 | 
			
		||||
            grid.AddColumn();
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = Record.Exception(() => grid.AddRow(null));
 | 
			
		||||
            // When
 | 
			
		||||
            grid.AddRow("Foo");
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ShouldBeOfType<ArgumentNullException>()
 | 
			
		||||
                    .ParamName.ShouldBe("columns");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Add_Empty_Items_If_User_Provides_Less_Row_Items_Than_Columns()
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var grid = new Grid();
 | 
			
		||||
                grid.AddColumn();
 | 
			
		||||
                grid.AddColumn();
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                grid.AddRow("Foo");
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                grid.Rows.Count.ShouldBe(1);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            public void Should_Throw_If_Row_Columns_Are_Greater_Than_Number_Of_Columns()
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var grid = new Grid();
 | 
			
		||||
                grid.AddColumn();
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = Record.Exception(() => grid.AddRow("Foo", "Bar"));
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ShouldBeOfType<InvalidOperationException>();
 | 
			
		||||
                result.Message.ShouldBe("The number of row columns are greater than the number of grid columns.");
 | 
			
		||||
            }
 | 
			
		||||
            // Then
 | 
			
		||||
            grid.Rows.Count.ShouldBe(1);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [UsesVerify]
 | 
			
		||||
        [ExpectationPath("AddEmptyRow")]
 | 
			
		||||
        public sealed class TheAddEmptyRowMethod
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Throw_If_Row_Columns_Are_Greater_Than_Number_Of_Columns()
 | 
			
		||||
        {
 | 
			
		||||
            [Fact]
 | 
			
		||||
            [Expectation("Render")]
 | 
			
		||||
            public Task Should_Add_Empty_Row()
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var console = new TestConsole();
 | 
			
		||||
                var grid = new Grid();
 | 
			
		||||
                grid.AddColumns(2);
 | 
			
		||||
                grid.AddRow("Foo", "Bar");
 | 
			
		||||
                grid.AddEmptyRow();
 | 
			
		||||
                grid.AddRow("Qux", "Corgi");
 | 
			
		||||
                grid.AddEmptyRow();
 | 
			
		||||
            // Given
 | 
			
		||||
            var grid = new Grid();
 | 
			
		||||
            grid.AddColumn();
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                console.Write(grid);
 | 
			
		||||
            // When
 | 
			
		||||
            var result = Record.Exception(() => grid.AddRow("Foo", "Bar"));
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                return Verifier.Verify(console.Output);
 | 
			
		||||
            }
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ShouldBeOfType<InvalidOperationException>();
 | 
			
		||||
            result.Message.ShouldBe("The number of row columns are greater than the number of grid columns.");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [UsesVerify]
 | 
			
		||||
    [ExpectationPath("AddEmptyRow")]
 | 
			
		||||
    public sealed class TheAddEmptyRowMethod
 | 
			
		||||
    {
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Render")]
 | 
			
		||||
        public Task Should_Render_Grid_Correctly()
 | 
			
		||||
        public Task Should_Add_Empty_Row()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
            var grid = new Grid();
 | 
			
		||||
            grid.AddColumn();
 | 
			
		||||
            grid.AddColumn();
 | 
			
		||||
            grid.AddColumn();
 | 
			
		||||
            grid.AddRow("Qux", "Corgi", "Waldo");
 | 
			
		||||
            grid.AddRow("Grault", "Garply", "Fred");
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(grid);
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Render_2")]
 | 
			
		||||
        public Task Should_Render_Grid_Correctly_2()
 | 
			
		||||
        {
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
            var grid = new Grid();
 | 
			
		||||
            grid.AddColumn(new GridColumn { NoWrap = true });
 | 
			
		||||
            grid.AddColumn(new GridColumn { Padding = new Padding(2, 0, 0, 0) });
 | 
			
		||||
            grid.AddRow("[bold]Options[/]", string.Empty);
 | 
			
		||||
            grid.AddRow("  [blue]-h[/], [blue]--help[/]", "Show command line help.");
 | 
			
		||||
            grid.AddRow("  [blue]-c[/], [blue]--configuration[/]", "The configuration to run for.\nThe default for most projects is [green]Debug[/].");
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(grid);
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Render_Alignment")]
 | 
			
		||||
        public Task Should_Render_Grid_Column_Alignment_Correctly()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
            var grid = new Grid();
 | 
			
		||||
            grid.AddColumn(new GridColumn { Alignment = Justify.Right });
 | 
			
		||||
            grid.AddColumn(new GridColumn { Alignment = Justify.Center });
 | 
			
		||||
            grid.AddColumn(new GridColumn { Alignment = Justify.Left });
 | 
			
		||||
            grid.AddRow("Foo", "Bar", "Baz");
 | 
			
		||||
            grid.AddRow("Qux", "Corgi", "Waldo");
 | 
			
		||||
            grid.AddRow("Grault", "Garply", "Fred");
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(grid);
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Render_Padding")]
 | 
			
		||||
        public Task Should_Use_Default_Padding()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
            var grid = new Grid();
 | 
			
		||||
            grid.AddColumns(3);
 | 
			
		||||
            grid.AddRow("Foo", "Bar", "Baz");
 | 
			
		||||
            grid.AddRow("Qux", "Corgi", "Waldo");
 | 
			
		||||
            grid.AddRow("Grault", "Garply", "Fred");
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(grid);
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Render_ExplicitPadding")]
 | 
			
		||||
        public Task Should_Render_Explicit_Grid_Column_Padding_Correctly()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
            var grid = new Grid();
 | 
			
		||||
            grid.AddColumn(new GridColumn { Padding = new Padding(3, 0, 0, 0) });
 | 
			
		||||
            grid.AddColumn(new GridColumn { Padding = new Padding(0, 0, 0, 0) });
 | 
			
		||||
            grid.AddColumn(new GridColumn { Padding = new Padding(0, 0, 3, 0) });
 | 
			
		||||
            grid.AddRow("Foo", "Bar", "Baz");
 | 
			
		||||
            grid.AddRow("Qux", "Corgi", "Waldo");
 | 
			
		||||
            grid.AddRow("Grault", "Garply", "Fred");
 | 
			
		||||
            grid.AddColumns(2);
 | 
			
		||||
            grid.AddRow("Foo", "Bar");
 | 
			
		||||
            grid.AddEmptyRow();
 | 
			
		||||
            grid.AddRow("Qux", "Corgi");
 | 
			
		||||
            grid.AddEmptyRow();
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(grid);
 | 
			
		||||
@@ -203,4 +94,104 @@ namespace Spectre.Console.Tests.Unit
 | 
			
		||||
            return Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("Render")]
 | 
			
		||||
    public Task Should_Render_Grid_Correctly()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole();
 | 
			
		||||
        var grid = new Grid();
 | 
			
		||||
        grid.AddColumn();
 | 
			
		||||
        grid.AddColumn();
 | 
			
		||||
        grid.AddColumn();
 | 
			
		||||
        grid.AddRow("Qux", "Corgi", "Waldo");
 | 
			
		||||
        grid.AddRow("Grault", "Garply", "Fred");
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.Write(grid);
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        return Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("Render_2")]
 | 
			
		||||
    public Task Should_Render_Grid_Correctly_2()
 | 
			
		||||
    {
 | 
			
		||||
        var console = new TestConsole();
 | 
			
		||||
        var grid = new Grid();
 | 
			
		||||
        grid.AddColumn(new GridColumn { NoWrap = true });
 | 
			
		||||
        grid.AddColumn(new GridColumn { Padding = new Padding(2, 0, 0, 0) });
 | 
			
		||||
        grid.AddRow("[bold]Options[/]", string.Empty);
 | 
			
		||||
        grid.AddRow("  [blue]-h[/], [blue]--help[/]", "Show command line help.");
 | 
			
		||||
        grid.AddRow("  [blue]-c[/], [blue]--configuration[/]", "The configuration to run for.\nThe default for most projects is [green]Debug[/].");
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.Write(grid);
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        return Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("Render_Alignment")]
 | 
			
		||||
    public Task Should_Render_Grid_Column_Alignment_Correctly()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole();
 | 
			
		||||
        var grid = new Grid();
 | 
			
		||||
        grid.AddColumn(new GridColumn { Alignment = Justify.Right });
 | 
			
		||||
        grid.AddColumn(new GridColumn { Alignment = Justify.Center });
 | 
			
		||||
        grid.AddColumn(new GridColumn { Alignment = Justify.Left });
 | 
			
		||||
        grid.AddRow("Foo", "Bar", "Baz");
 | 
			
		||||
        grid.AddRow("Qux", "Corgi", "Waldo");
 | 
			
		||||
        grid.AddRow("Grault", "Garply", "Fred");
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.Write(grid);
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        return Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("Render_Padding")]
 | 
			
		||||
    public Task Should_Use_Default_Padding()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole();
 | 
			
		||||
        var grid = new Grid();
 | 
			
		||||
        grid.AddColumns(3);
 | 
			
		||||
        grid.AddRow("Foo", "Bar", "Baz");
 | 
			
		||||
        grid.AddRow("Qux", "Corgi", "Waldo");
 | 
			
		||||
        grid.AddRow("Grault", "Garply", "Fred");
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.Write(grid);
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        return Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("Render_ExplicitPadding")]
 | 
			
		||||
    public Task Should_Render_Explicit_Grid_Column_Padding_Correctly()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole();
 | 
			
		||||
        var grid = new Grid();
 | 
			
		||||
        grid.AddColumn(new GridColumn { Padding = new Padding(3, 0, 0, 0) });
 | 
			
		||||
        grid.AddColumn(new GridColumn { Padding = new Padding(0, 0, 0, 0) });
 | 
			
		||||
        grid.AddColumn(new GridColumn { Padding = new Padding(0, 0, 3, 0) });
 | 
			
		||||
        grid.AddRow("Foo", "Bar", "Baz");
 | 
			
		||||
        grid.AddRow("Qux", "Corgi", "Waldo");
 | 
			
		||||
        grid.AddRow("Grault", "Garply", "Fred");
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.Write(grid);
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        return Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,143 +1,137 @@
 | 
			
		||||
using System;
 | 
			
		||||
using Shouldly;
 | 
			
		||||
using Spectre.Console.Testing;
 | 
			
		||||
using Xunit;
 | 
			
		||||
namespace Spectre.Console.Tests.Unit;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Unit
 | 
			
		||||
public sealed class MarkupTests
 | 
			
		||||
{
 | 
			
		||||
    public sealed class MarkupTests
 | 
			
		||||
    public sealed class TheLengthProperty
 | 
			
		||||
    {
 | 
			
		||||
        public sealed class TheLengthProperty
 | 
			
		||||
        {
 | 
			
		||||
            [Theory]
 | 
			
		||||
            [InlineData("Hello", 5)]
 | 
			
		||||
            [InlineData("Hello\nWorld", 11)]
 | 
			
		||||
            [InlineData("[yellow]Hello[/]", 5)]
 | 
			
		||||
            public void Should_Return_The_Number_Of_Characters(string input, int expected)
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var markup = new Markup(input);
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = markup.Length;
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ShouldBe(expected);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public sealed class TheLinesProperty
 | 
			
		||||
        {
 | 
			
		||||
            [Theory]
 | 
			
		||||
            [InlineData("Hello", 1)]
 | 
			
		||||
            [InlineData("Hello\nWorld", 2)]
 | 
			
		||||
            [InlineData("[yellow]Hello[/]\nWorld", 2)]
 | 
			
		||||
            public void Should_Return_The_Number_Of_Lines(string input, int expected)
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var markup = new Markup(input);
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                var result = markup.Lines;
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ShouldBe(expected);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public sealed class TheEscapeMethod
 | 
			
		||||
        {
 | 
			
		||||
            [Theory]
 | 
			
		||||
            [InlineData("Hello World", "Hello World")]
 | 
			
		||||
            [InlineData("Hello World [", "Hello World [[")]
 | 
			
		||||
            [InlineData("Hello World ]", "Hello World ]]")]
 | 
			
		||||
            [InlineData("Hello [World]", "Hello [[World]]")]
 | 
			
		||||
            [InlineData("Hello [[World]]", "Hello [[[[World]]]]")]
 | 
			
		||||
            public void Should_Escape_Markup_As_Expected(string input, string expected)
 | 
			
		||||
            {
 | 
			
		||||
                // Given, When
 | 
			
		||||
                var result = Markup.Escape(input);
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ShouldBe(expected);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public sealed class TheRemoveMethod
 | 
			
		||||
        {
 | 
			
		||||
            [Theory]
 | 
			
		||||
            [InlineData("Hello World", "Hello World")]
 | 
			
		||||
            [InlineData("Hello [blue]World", "Hello World")]
 | 
			
		||||
            [InlineData("Hello [blue]World[/]", "Hello World")]
 | 
			
		||||
            public void Should_Remove_Markup_From_Text(string input, string expected)
 | 
			
		||||
            {
 | 
			
		||||
                // Given, When
 | 
			
		||||
                var result = Markup.Remove(input);
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                result.ShouldBe(expected);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Theory]
 | 
			
		||||
        [InlineData("Hello [[ World ]")]
 | 
			
		||||
        [InlineData("Hello [[ World ] !")]
 | 
			
		||||
        public void Should_Throw_If_Closing_Tag_Is_Not_Properly_Escaped(string input)
 | 
			
		||||
        [InlineData("Hello", 5)]
 | 
			
		||||
        [InlineData("Hello\nWorld", 11)]
 | 
			
		||||
        [InlineData("[yellow]Hello[/]", 5)]
 | 
			
		||||
        public void Should_Return_The_Number_Of_Characters(string input, int expected)
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            var result = Record.Exception(() => new Markup(input));
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ShouldNotBeNull();
 | 
			
		||||
            result.ShouldBeOfType<InvalidOperationException>();
 | 
			
		||||
            result.Message.ShouldBe("Encountered unescaped ']' token at position 16");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Escape_Markup_Blocks_As_Expected()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
            var markup = new Markup("Hello [[ World ]] !");
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(markup);
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            console.Output.ShouldBe("Hello [ World ] !");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Theory]
 | 
			
		||||
        [InlineData("Hello [link=http://example.com]example.com[/]", "Hello example.com")]
 | 
			
		||||
        [InlineData("Hello [link=http://example.com]http://example.com[/]", "Hello http://example.com")]
 | 
			
		||||
        public void Should_Render_Links_As_Expected(string input, string output)
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
            var markup = new Markup(input);
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(markup);
 | 
			
		||||
            var result = markup.Length;
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            console.Output.ShouldBe(output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Should_Not_Fail_With_Brackets_On_Calls_Without_Args()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.MarkupLine("{");
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            console.Output.NormalizeLineEndings()
 | 
			
		||||
                .ShouldBe("{\n");
 | 
			
		||||
            result.ShouldBe(expected);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    public sealed class TheLinesProperty
 | 
			
		||||
    {
 | 
			
		||||
        [Theory]
 | 
			
		||||
        [InlineData("Hello", 1)]
 | 
			
		||||
        [InlineData("Hello\nWorld", 2)]
 | 
			
		||||
        [InlineData("[yellow]Hello[/]\nWorld", 2)]
 | 
			
		||||
        public void Should_Return_The_Number_Of_Lines(string input, int expected)
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var markup = new Markup(input);
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            var result = markup.Lines;
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ShouldBe(expected);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public sealed class TheEscapeMethod
 | 
			
		||||
    {
 | 
			
		||||
        [Theory]
 | 
			
		||||
        [InlineData("Hello World", "Hello World")]
 | 
			
		||||
        [InlineData("Hello World [", "Hello World [[")]
 | 
			
		||||
        [InlineData("Hello World ]", "Hello World ]]")]
 | 
			
		||||
        [InlineData("Hello [World]", "Hello [[World]]")]
 | 
			
		||||
        [InlineData("Hello [[World]]", "Hello [[[[World]]]]")]
 | 
			
		||||
        public void Should_Escape_Markup_As_Expected(string input, string expected)
 | 
			
		||||
        {
 | 
			
		||||
            // Given, When
 | 
			
		||||
            var result = Markup.Escape(input);
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ShouldBe(expected);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public sealed class TheRemoveMethod
 | 
			
		||||
    {
 | 
			
		||||
        [Theory]
 | 
			
		||||
        [InlineData("Hello World", "Hello World")]
 | 
			
		||||
        [InlineData("Hello [blue]World", "Hello World")]
 | 
			
		||||
        [InlineData("Hello [blue]World[/]", "Hello World")]
 | 
			
		||||
        public void Should_Remove_Markup_From_Text(string input, string expected)
 | 
			
		||||
        {
 | 
			
		||||
            // Given, When
 | 
			
		||||
            var result = Markup.Remove(input);
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            result.ShouldBe(expected);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Theory]
 | 
			
		||||
    [InlineData("Hello [[ World ]")]
 | 
			
		||||
    [InlineData("Hello [[ World ] !")]
 | 
			
		||||
    public void Should_Throw_If_Closing_Tag_Is_Not_Properly_Escaped(string input)
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole();
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        var result = Record.Exception(() => new Markup(input));
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        result.ShouldNotBeNull();
 | 
			
		||||
        result.ShouldBeOfType<InvalidOperationException>();
 | 
			
		||||
        result.Message.ShouldBe("Encountered unescaped ']' token at position 16");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    public void Should_Escape_Markup_Blocks_As_Expected()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole();
 | 
			
		||||
        var markup = new Markup("Hello [[ World ]] !");
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.Write(markup);
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        console.Output.ShouldBe("Hello [ World ] !");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Theory]
 | 
			
		||||
    [InlineData("Hello [link=http://example.com]example.com[/]", "Hello example.com")]
 | 
			
		||||
    [InlineData("Hello [link=http://example.com]http://example.com[/]", "Hello http://example.com")]
 | 
			
		||||
    public void Should_Render_Links_As_Expected(string input, string output)
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole();
 | 
			
		||||
        var markup = new Markup(input);
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.Write(markup);
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        console.Output.ShouldBe(output);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    public void Should_Not_Fail_With_Brackets_On_Calls_Without_Args()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole();
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.MarkupLine("{");
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        console.Output.NormalizeLineEndings()
 | 
			
		||||
            .ShouldBe("{\n");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,75 +1,68 @@
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Spectre.Console.Testing;
 | 
			
		||||
using Spectre.Verify.Extensions;
 | 
			
		||||
using VerifyXunit;
 | 
			
		||||
using Xunit;
 | 
			
		||||
namespace Spectre.Console.Tests.Unit;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Unit
 | 
			
		||||
[UsesVerify]
 | 
			
		||||
[ExpectationPath("Widgets/Padder")]
 | 
			
		||||
public sealed class PadderTests
 | 
			
		||||
{
 | 
			
		||||
    [UsesVerify]
 | 
			
		||||
    [ExpectationPath("Widgets/Padder")]
 | 
			
		||||
    public sealed class PadderTests
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("Render")]
 | 
			
		||||
    public Task Should_Render_Padded_Object_Correctly()
 | 
			
		||||
    {
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Render")]
 | 
			
		||||
        public Task Should_Render_Padded_Object_Correctly()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole().Width(60);
 | 
			
		||||
            var table = new Table();
 | 
			
		||||
            table.AddColumn("Foo");
 | 
			
		||||
            table.AddColumn("Bar");
 | 
			
		||||
            table.AddRow("Baz", "Qux");
 | 
			
		||||
            table.AddRow("Corgi", "Waldo");
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole().Width(60);
 | 
			
		||||
        var table = new Table();
 | 
			
		||||
        table.AddColumn("Foo");
 | 
			
		||||
        table.AddColumn("Bar");
 | 
			
		||||
        table.AddRow("Baz", "Qux");
 | 
			
		||||
        table.AddRow("Corgi", "Waldo");
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(new Padder(table).Padding(1, 2, 3, 4));
 | 
			
		||||
        // When
 | 
			
		||||
        console.Write(new Padder(table).Padding(1, 2, 3, 4));
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Render_Expanded")]
 | 
			
		||||
        public Task Should_Render_Expanded_Padded_Object_Correctly()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole().Width(60);
 | 
			
		||||
            var table = new Table();
 | 
			
		||||
            table.AddColumn("Foo");
 | 
			
		||||
            table.AddColumn("Bar");
 | 
			
		||||
            table.AddRow("Baz", "Qux");
 | 
			
		||||
            table.AddRow("Corgi", "Waldo");
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(new Padder(table)
 | 
			
		||||
                .Padding(1, 2, 3, 4)
 | 
			
		||||
                .Expand());
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Render_Nested")]
 | 
			
		||||
        public Task Should_Render_Padded_Object_Correctly_When_Nested_Within_Other_Object()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole().Width(60);
 | 
			
		||||
            var table = new Table();
 | 
			
		||||
            table.AddColumn("Foo");
 | 
			
		||||
            table.AddColumn("Bar", c => c.PadLeft(0).PadRight(0));
 | 
			
		||||
            table.AddRow("Baz", "Qux");
 | 
			
		||||
            table.AddRow(new Text("Corgi"), new Padder(new Panel("Waldo"))
 | 
			
		||||
                .Padding(2, 1));
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(new Padder(table)
 | 
			
		||||
                .Padding(1, 2, 3, 4)
 | 
			
		||||
                .Expand());
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
        // Then
 | 
			
		||||
        return Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("Render_Expanded")]
 | 
			
		||||
    public Task Should_Render_Expanded_Padded_Object_Correctly()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole().Width(60);
 | 
			
		||||
        var table = new Table();
 | 
			
		||||
        table.AddColumn("Foo");
 | 
			
		||||
        table.AddColumn("Bar");
 | 
			
		||||
        table.AddRow("Baz", "Qux");
 | 
			
		||||
        table.AddRow("Corgi", "Waldo");
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.Write(new Padder(table)
 | 
			
		||||
            .Padding(1, 2, 3, 4)
 | 
			
		||||
            .Expand());
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        return Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("Render_Nested")]
 | 
			
		||||
    public Task Should_Render_Padded_Object_Correctly_When_Nested_Within_Other_Object()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole().Width(60);
 | 
			
		||||
        var table = new Table();
 | 
			
		||||
        table.AddColumn("Foo");
 | 
			
		||||
        table.AddColumn("Bar", c => c.PadLeft(0).PadRight(0));
 | 
			
		||||
        table.AddRow("Baz", "Qux");
 | 
			
		||||
        table.AddRow(new Text("Corgi"), new Padder(new Panel("Waldo"))
 | 
			
		||||
            .Padding(2, 1));
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.Write(new Padder(table)
 | 
			
		||||
            .Padding(1, 2, 3, 4)
 | 
			
		||||
            .Expand());
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        return Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,309 +1,300 @@
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Spectre.Console.Rendering;
 | 
			
		||||
using Spectre.Console.Testing;
 | 
			
		||||
using Spectre.Verify.Extensions;
 | 
			
		||||
using VerifyXunit;
 | 
			
		||||
using Xunit;
 | 
			
		||||
namespace Spectre.Console.Tests.Unit;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Unit
 | 
			
		||||
[UsesVerify]
 | 
			
		||||
[ExpectationPath("Widgets/Panel")]
 | 
			
		||||
public sealed class PanelTests
 | 
			
		||||
{
 | 
			
		||||
    [UsesVerify]
 | 
			
		||||
    [ExpectationPath("Widgets/Panel")]
 | 
			
		||||
    public sealed class PanelTests
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("Render")]
 | 
			
		||||
    public Task Should_Render_Panel()
 | 
			
		||||
    {
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Render")]
 | 
			
		||||
        public Task Should_Render_Panel()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole();
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(new Panel(new Text("Hello World")));
 | 
			
		||||
        // When
 | 
			
		||||
        console.Write(new Panel(new Text("Hello World")));
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Render_ZeroPadding")]
 | 
			
		||||
        public Task Should_Render_Panel_With_Padding_Set_To_Zero()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(new Panel(new Text("Hello World"))
 | 
			
		||||
            {
 | 
			
		||||
                Padding = new Padding(0, 0, 0, 0),
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Render_Padding")]
 | 
			
		||||
        public Task Should_Render_Panel_With_Padding()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(new Panel(new Text("Hello World"))
 | 
			
		||||
            {
 | 
			
		||||
                Padding = new Padding(3, 1, 5, 2),
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Render_Header")]
 | 
			
		||||
        public Task Should_Render_Panel_With_Header()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(new Panel("Hello World")
 | 
			
		||||
            {
 | 
			
		||||
                Header = new PanelHeader("Greeting"),
 | 
			
		||||
                Expand = true,
 | 
			
		||||
                Padding = new Padding(2, 0, 2, 0),
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Render_Header_LeftAligned")]
 | 
			
		||||
        public Task Should_Render_Panel_With_Left_Aligned_Header()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(new Panel("Hello World")
 | 
			
		||||
            {
 | 
			
		||||
                Header = new PanelHeader("Greeting").LeftAligned(),
 | 
			
		||||
                Expand = true,
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Render_Header_Centered")]
 | 
			
		||||
        public Task Should_Render_Panel_With_Centered_Header()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(new Panel("Hello World")
 | 
			
		||||
            {
 | 
			
		||||
                Header = new PanelHeader("Greeting").Centered(),
 | 
			
		||||
                Expand = true,
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Render_Header_RightAligned")]
 | 
			
		||||
        public Task Should_Render_Panel_With_Right_Aligned_Header()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(new Panel("Hello World")
 | 
			
		||||
            {
 | 
			
		||||
                Header = new PanelHeader("Greeting").RightAligned(),
 | 
			
		||||
                Expand = true,
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Render_Header_Collapse")]
 | 
			
		||||
        public Task Should_Collapse_Header_If_It_Will_Not_Fit()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole().Width(10);
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(new Panel("Hello World")
 | 
			
		||||
            {
 | 
			
		||||
                Header = new PanelHeader("Greeting"),
 | 
			
		||||
                Expand = true,
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Render_Unicode")]
 | 
			
		||||
        public Task Should_Render_Panel_With_Unicode_Correctly()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(new Panel(new Text(" \n💩\n ")));
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Render_Multiline")]
 | 
			
		||||
        public Task Should_Render_Panel_With_Multiple_Lines()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(new Panel(new Text("Hello World\nFoo Bar")));
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Render_LineEndings")]
 | 
			
		||||
        public Task Should_Preserve_Explicit_Line_Ending()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
            var text = new Panel(
 | 
			
		||||
                new Markup("I heard [underline on blue]you[/] like 📦\n\n\n\nSo I put a 📦 in a 📦"));
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(text);
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Render_Expand")]
 | 
			
		||||
        public Task Should_Expand_Panel_If_Enabled()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(new Panel(new Text("Hello World"))
 | 
			
		||||
            {
 | 
			
		||||
                Expand = true,
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Render_Child_RightAligned")]
 | 
			
		||||
        public Task Should_Justify_Child_To_Right_Correctly()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole().Width(25);
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(
 | 
			
		||||
                new Panel(new Text("Hello World").RightAligned())
 | 
			
		||||
                {
 | 
			
		||||
                    Expand = true,
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Render_Child_Centered")]
 | 
			
		||||
        public Task Should_Center_Child_Correctly()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole().Width(25);
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(
 | 
			
		||||
                new Panel(new Text("Hello World").Centered())
 | 
			
		||||
                {
 | 
			
		||||
                    Expand = true,
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Render_Child_Panel")]
 | 
			
		||||
        public Task Should_Render_Panel_Inside_Panel_Correctly()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(new Panel(new Panel(new Text("Hello World"))));
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Render_Wrap")]
 | 
			
		||||
        public Task Should_Wrap_Content_Correctly()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole().Width(84);
 | 
			
		||||
            var rows = new List<IRenderable>();
 | 
			
		||||
            var grid = new Grid();
 | 
			
		||||
            grid.AddColumn(new GridColumn().PadLeft(2).PadRight(0));
 | 
			
		||||
            grid.AddColumn(new GridColumn().PadLeft(1).PadRight(0));
 | 
			
		||||
            grid.AddRow("at", "[grey]System.Runtime.CompilerServices.TaskAwaiter.[/][yellow]HandleNonSuccessAndDebuggerNotification[/]([blue]Task[/] task)");
 | 
			
		||||
            rows.Add(grid);
 | 
			
		||||
 | 
			
		||||
            var panel = new Panel(grid)
 | 
			
		||||
                .Expand().RoundedBorder()
 | 
			
		||||
                .BorderStyle(new Style().Foreground(Color.Grey))
 | 
			
		||||
                .Header("[grey]Short paths[/]");
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(panel);
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Render_CJK")]
 | 
			
		||||
        public Task Should_Wrap_Table_With_CJK_Tables_In_Panel_Correctly()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
 | 
			
		||||
            var table = new Table();
 | 
			
		||||
            table.AddColumn("测试");
 | 
			
		||||
            table.AddRow("测试");
 | 
			
		||||
            var panel = new Panel(table);
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(panel);
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
        // Then
 | 
			
		||||
        return Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("Render_ZeroPadding")]
 | 
			
		||||
    public Task Should_Render_Panel_With_Padding_Set_To_Zero()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole();
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.Write(new Panel(new Text("Hello World"))
 | 
			
		||||
        {
 | 
			
		||||
            Padding = new Padding(0, 0, 0, 0),
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        return Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("Render_Padding")]
 | 
			
		||||
    public Task Should_Render_Panel_With_Padding()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole();
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.Write(new Panel(new Text("Hello World"))
 | 
			
		||||
        {
 | 
			
		||||
            Padding = new Padding(3, 1, 5, 2),
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        return Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("Render_Header")]
 | 
			
		||||
    public Task Should_Render_Panel_With_Header()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole();
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.Write(new Panel("Hello World")
 | 
			
		||||
        {
 | 
			
		||||
            Header = new PanelHeader("Greeting"),
 | 
			
		||||
            Expand = true,
 | 
			
		||||
            Padding = new Padding(2, 0, 2, 0),
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        return Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("Render_Header_LeftAligned")]
 | 
			
		||||
    public Task Should_Render_Panel_With_Left_Aligned_Header()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole();
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.Write(new Panel("Hello World")
 | 
			
		||||
        {
 | 
			
		||||
            Header = new PanelHeader("Greeting").LeftAligned(),
 | 
			
		||||
            Expand = true,
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        return Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("Render_Header_Centered")]
 | 
			
		||||
    public Task Should_Render_Panel_With_Centered_Header()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole();
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.Write(new Panel("Hello World")
 | 
			
		||||
        {
 | 
			
		||||
            Header = new PanelHeader("Greeting").Centered(),
 | 
			
		||||
            Expand = true,
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        return Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("Render_Header_RightAligned")]
 | 
			
		||||
    public Task Should_Render_Panel_With_Right_Aligned_Header()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole();
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.Write(new Panel("Hello World")
 | 
			
		||||
        {
 | 
			
		||||
            Header = new PanelHeader("Greeting").RightAligned(),
 | 
			
		||||
            Expand = true,
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        return Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("Render_Header_Collapse")]
 | 
			
		||||
    public Task Should_Collapse_Header_If_It_Will_Not_Fit()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole().Width(10);
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.Write(new Panel("Hello World")
 | 
			
		||||
        {
 | 
			
		||||
            Header = new PanelHeader("Greeting"),
 | 
			
		||||
            Expand = true,
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        return Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("Render_Unicode")]
 | 
			
		||||
    public Task Should_Render_Panel_With_Unicode_Correctly()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole();
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.Write(new Panel(new Text(" \n💩\n ")));
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        return Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("Render_Multiline")]
 | 
			
		||||
    public Task Should_Render_Panel_With_Multiple_Lines()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole();
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.Write(new Panel(new Text("Hello World\nFoo Bar")));
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        return Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("Render_LineEndings")]
 | 
			
		||||
    public Task Should_Preserve_Explicit_Line_Ending()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole();
 | 
			
		||||
        var text = new Panel(
 | 
			
		||||
            new Markup("I heard [underline on blue]you[/] like 📦\n\n\n\nSo I put a 📦 in a 📦"));
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.Write(text);
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        return Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("Render_Expand")]
 | 
			
		||||
    public Task Should_Expand_Panel_If_Enabled()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole();
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.Write(new Panel(new Text("Hello World"))
 | 
			
		||||
        {
 | 
			
		||||
            Expand = true,
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        return Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("Render_Child_RightAligned")]
 | 
			
		||||
    public Task Should_Justify_Child_To_Right_Correctly()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole().Width(25);
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.Write(
 | 
			
		||||
            new Panel(new Text("Hello World").RightAligned())
 | 
			
		||||
            {
 | 
			
		||||
                Expand = true,
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        return Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("Render_Child_Centered")]
 | 
			
		||||
    public Task Should_Center_Child_Correctly()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole().Width(25);
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.Write(
 | 
			
		||||
            new Panel(new Text("Hello World").Centered())
 | 
			
		||||
            {
 | 
			
		||||
                Expand = true,
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        return Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("Render_Child_Panel")]
 | 
			
		||||
    public Task Should_Render_Panel_Inside_Panel_Correctly()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole();
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.Write(new Panel(new Panel(new Text("Hello World"))));
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        return Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("Render_Wrap")]
 | 
			
		||||
    public Task Should_Wrap_Content_Correctly()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole().Width(84);
 | 
			
		||||
        var rows = new List<IRenderable>();
 | 
			
		||||
        var grid = new Grid();
 | 
			
		||||
        grid.AddColumn(new GridColumn().PadLeft(2).PadRight(0));
 | 
			
		||||
        grid.AddColumn(new GridColumn().PadLeft(1).PadRight(0));
 | 
			
		||||
        grid.AddRow("at", "[grey]System.Runtime.CompilerServices.TaskAwaiter.[/][yellow]HandleNonSuccessAndDebuggerNotification[/]([blue]Task[/] task)");
 | 
			
		||||
        rows.Add(grid);
 | 
			
		||||
 | 
			
		||||
        var panel = new Panel(grid)
 | 
			
		||||
            .Expand().RoundedBorder()
 | 
			
		||||
            .BorderStyle(new Style().Foreground(Color.Grey))
 | 
			
		||||
            .Header("[grey]Short paths[/]");
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.Write(panel);
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        return Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("Render_CJK")]
 | 
			
		||||
    public Task Should_Wrap_Table_With_CJK_Tables_In_Panel_Correctly()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole();
 | 
			
		||||
 | 
			
		||||
        var table = new Table();
 | 
			
		||||
        table.AddColumn("测试");
 | 
			
		||||
        table.AddRow("测试");
 | 
			
		||||
        var panel = new Panel(table);
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.Write(panel);
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        return Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,83 +1,75 @@
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Spectre.Console.Rendering;
 | 
			
		||||
using Spectre.Console.Testing;
 | 
			
		||||
using Spectre.Verify.Extensions;
 | 
			
		||||
using VerifyXunit;
 | 
			
		||||
using Xunit;
 | 
			
		||||
namespace Spectre.Console.Tests.Unit;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Unit
 | 
			
		||||
[UsesVerify]
 | 
			
		||||
[ExpectationPath("Widgets/Rows")]
 | 
			
		||||
public sealed class RowsTests
 | 
			
		||||
{
 | 
			
		||||
    [UsesVerify]
 | 
			
		||||
    [ExpectationPath("Widgets/Rows")]
 | 
			
		||||
    public sealed class RowsTests
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("Render")]
 | 
			
		||||
    public Task Should_Render_Rows()
 | 
			
		||||
    {
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Render")]
 | 
			
		||||
        public Task Should_Render_Rows()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole().Width(60);
 | 
			
		||||
            var rows = new Rows(
 | 
			
		||||
                new IRenderable[]
 | 
			
		||||
                {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole().Width(60);
 | 
			
		||||
        var rows = new Rows(
 | 
			
		||||
            new IRenderable[]
 | 
			
		||||
            {
 | 
			
		||||
                    new Markup("Hello"),
 | 
			
		||||
                    new Table()
 | 
			
		||||
                        .AddColumns("Foo", "Bar")
 | 
			
		||||
                        .AddRow("Baz", "Qux"),
 | 
			
		||||
                    new Markup("World"),
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(rows);
 | 
			
		||||
        // When
 | 
			
		||||
        console.Write(rows);
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Render_Nested")]
 | 
			
		||||
        public Task Should_Render_Rows_Correctly_Inside_Other_Widget()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole().Width(60);
 | 
			
		||||
            var table = new Table()
 | 
			
		||||
                .AddColumns("Foo", "Bar")
 | 
			
		||||
                .AddRow("HELLO WORLD")
 | 
			
		||||
                .AddRow(
 | 
			
		||||
                new Rows(new IRenderable[]
 | 
			
		||||
                {
 | 
			
		||||
                    new Markup("Hello"),
 | 
			
		||||
                    new Markup("World"),
 | 
			
		||||
                }), new Text("Qux"));
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(table);
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Render_Expanded_And_Nested")]
 | 
			
		||||
        public Task Should_Render_Rows_Correctly_Inside_Other_Widget_When_Expanded()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole().Width(60);
 | 
			
		||||
            var table = new Table()
 | 
			
		||||
                .AddColumns("Foo", "Bar")
 | 
			
		||||
                .AddRow("HELLO WORLD")
 | 
			
		||||
                .AddRow(
 | 
			
		||||
                new Rows(new IRenderable[]
 | 
			
		||||
                {
 | 
			
		||||
                    new Markup("Hello"),
 | 
			
		||||
                    new Markup("World"),
 | 
			
		||||
                }).Expand(), new Text("Qux"));
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(table);
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
        // Then
 | 
			
		||||
        return Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("Render_Nested")]
 | 
			
		||||
    public Task Should_Render_Rows_Correctly_Inside_Other_Widget()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole().Width(60);
 | 
			
		||||
        var table = new Table()
 | 
			
		||||
            .AddColumns("Foo", "Bar")
 | 
			
		||||
            .AddRow("HELLO WORLD")
 | 
			
		||||
            .AddRow(
 | 
			
		||||
            new Rows(new IRenderable[]
 | 
			
		||||
            {
 | 
			
		||||
                    new Markup("Hello"),
 | 
			
		||||
                    new Markup("World"),
 | 
			
		||||
            }), new Text("Qux"));
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.Write(table);
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        return Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("Render_Expanded_And_Nested")]
 | 
			
		||||
    public Task Should_Render_Rows_Correctly_Inside_Other_Widget_When_Expanded()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole().Width(60);
 | 
			
		||||
        var table = new Table()
 | 
			
		||||
            .AddColumns("Foo", "Bar")
 | 
			
		||||
            .AddRow("HELLO WORLD")
 | 
			
		||||
            .AddRow(
 | 
			
		||||
            new Rows(new IRenderable[]
 | 
			
		||||
            {
 | 
			
		||||
                    new Markup("Hello"),
 | 
			
		||||
                    new Markup("World"),
 | 
			
		||||
            }).Expand(), new Text("Qux"));
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.Write(table);
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        return Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,158 +1,150 @@
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Shouldly;
 | 
			
		||||
using Spectre.Console.Testing;
 | 
			
		||||
using Spectre.Verify.Extensions;
 | 
			
		||||
using VerifyXunit;
 | 
			
		||||
using Xunit;
 | 
			
		||||
namespace Spectre.Console.Tests.Unit;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Unit
 | 
			
		||||
[UsesVerify]
 | 
			
		||||
[ExpectationPath("Widgets/Rule")]
 | 
			
		||||
public sealed class RuleTests
 | 
			
		||||
{
 | 
			
		||||
    [UsesVerify]
 | 
			
		||||
    [ExpectationPath("Widgets/Rule")]
 | 
			
		||||
    public sealed class RuleTests
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("Render")]
 | 
			
		||||
    public Task Should_Render_Default_Rule_Without_Title()
 | 
			
		||||
    {
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Render")]
 | 
			
		||||
        public Task Should_Render_Default_Rule_Without_Title()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole().Width(40);
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole().Width(40);
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(new Rule());
 | 
			
		||||
        // When
 | 
			
		||||
        console.Write(new Rule());
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Render_Border_NoHeader")]
 | 
			
		||||
        public Task Should_Render_Default_Rule_With_Specified_Border()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole().Width(40);
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(new Rule().DoubleBorder());
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Render_Border_Header")]
 | 
			
		||||
        public Task Should_Render_With_Specified_Box()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole().Width(40);
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(new Rule("Hello World").DoubleBorder());
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Render_Header_DefaultAlignment")]
 | 
			
		||||
        public Task Should_Render_Default_Rule_With_Title_Centered_By_Default()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole().Width(40);
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(new Rule("Hello World"));
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Render_Header_LeftAligned")]
 | 
			
		||||
        public Task Should_Render_Default_Rule_With_Title_Left_Aligned()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole().Width(40);
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(new Rule("Hello World")
 | 
			
		||||
            {
 | 
			
		||||
                Alignment = Justify.Left,
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Render_Header_RightAligned")]
 | 
			
		||||
        public Task Should_Render_Default_Rule_With_Title_Right_Aligned()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole().Width(40);
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(new Rule("Hello World")
 | 
			
		||||
            {
 | 
			
		||||
                Alignment = Justify.Right,
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Render_Linebreaks")]
 | 
			
		||||
        public Task Should_Convert_Line_Breaks_In_Title_To_Spaces()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole().Width(40);
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(new Rule("Hello\nWorld\r\n!"));
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Render_Truncate")]
 | 
			
		||||
        public Task Should_Truncate_Title()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole().Width(40);
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(new Rule("          Hello World    "));
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Theory]
 | 
			
		||||
        [InlineData(1, "Hello World Hello World Hello World Hello World Hello World", "─")]
 | 
			
		||||
        [InlineData(2, "Hello World Hello World Hello World Hello World Hello World", "──")]
 | 
			
		||||
        [InlineData(3, "Hello World Hello World Hello World Hello World Hello World", "───")]
 | 
			
		||||
        [InlineData(4, "Hello World Hello World Hello World Hello World Hello World", "────")]
 | 
			
		||||
        [InlineData(5, "Hello World Hello World Hello World Hello World Hello World", "─────")]
 | 
			
		||||
        [InlineData(6, "Hello World Hello World Hello World Hello World Hello World", "──────")]
 | 
			
		||||
        [InlineData(7, "Hello World Hello World Hello World Hello World Hello World", "───────")]
 | 
			
		||||
        [InlineData(8, "Hello World Hello World Hello World Hello World Hello World", "── H… ──")]
 | 
			
		||||
        [InlineData(8, "A", "── A ───")]
 | 
			
		||||
        [InlineData(8, "AB", "── AB ──")]
 | 
			
		||||
        [InlineData(8, "ABC", "── A… ──")]
 | 
			
		||||
        [InlineData(40, "Hello World Hello World Hello World Hello World Hello World", "──── Hello World Hello World Hello… ────")]
 | 
			
		||||
        public void Should_Truncate_Too_Long_Title(int width, string input, string expected)
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole().Width(width);
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(new Rule(input));
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            console.Lines.Count.ShouldBe(1);
 | 
			
		||||
            console.Lines[0].ShouldBe(expected);
 | 
			
		||||
        }
 | 
			
		||||
        // Then
 | 
			
		||||
        return Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("Render_Border_NoHeader")]
 | 
			
		||||
    public Task Should_Render_Default_Rule_With_Specified_Border()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole().Width(40);
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.Write(new Rule().DoubleBorder());
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        return Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("Render_Border_Header")]
 | 
			
		||||
    public Task Should_Render_With_Specified_Box()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole().Width(40);
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.Write(new Rule("Hello World").DoubleBorder());
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        return Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("Render_Header_DefaultAlignment")]
 | 
			
		||||
    public Task Should_Render_Default_Rule_With_Title_Centered_By_Default()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole().Width(40);
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.Write(new Rule("Hello World"));
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        return Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("Render_Header_LeftAligned")]
 | 
			
		||||
    public Task Should_Render_Default_Rule_With_Title_Left_Aligned()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole().Width(40);
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.Write(new Rule("Hello World")
 | 
			
		||||
        {
 | 
			
		||||
            Alignment = Justify.Left,
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        return Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("Render_Header_RightAligned")]
 | 
			
		||||
    public Task Should_Render_Default_Rule_With_Title_Right_Aligned()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole().Width(40);
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.Write(new Rule("Hello World")
 | 
			
		||||
        {
 | 
			
		||||
            Alignment = Justify.Right,
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        return Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("Render_Linebreaks")]
 | 
			
		||||
    public Task Should_Convert_Line_Breaks_In_Title_To_Spaces()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole().Width(40);
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.Write(new Rule("Hello\nWorld\r\n!"));
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        return Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    [Expectation("Render_Truncate")]
 | 
			
		||||
    public Task Should_Truncate_Title()
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole().Width(40);
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.Write(new Rule("          Hello World    "));
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        return Verifier.Verify(console.Output);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Theory]
 | 
			
		||||
    [InlineData(1, "Hello World Hello World Hello World Hello World Hello World", "─")]
 | 
			
		||||
    [InlineData(2, "Hello World Hello World Hello World Hello World Hello World", "──")]
 | 
			
		||||
    [InlineData(3, "Hello World Hello World Hello World Hello World Hello World", "───")]
 | 
			
		||||
    [InlineData(4, "Hello World Hello World Hello World Hello World Hello World", "────")]
 | 
			
		||||
    [InlineData(5, "Hello World Hello World Hello World Hello World Hello World", "─────")]
 | 
			
		||||
    [InlineData(6, "Hello World Hello World Hello World Hello World Hello World", "──────")]
 | 
			
		||||
    [InlineData(7, "Hello World Hello World Hello World Hello World Hello World", "───────")]
 | 
			
		||||
    [InlineData(8, "Hello World Hello World Hello World Hello World Hello World", "── H… ──")]
 | 
			
		||||
    [InlineData(8, "A", "── A ───")]
 | 
			
		||||
    [InlineData(8, "AB", "── AB ──")]
 | 
			
		||||
    [InlineData(8, "ABC", "── A… ──")]
 | 
			
		||||
    [InlineData(40, "Hello World Hello World Hello World Hello World Hello World", "──── Hello World Hello World Hello… ────")]
 | 
			
		||||
    public void Should_Truncate_Too_Long_Title(int width, string input, string expected)
 | 
			
		||||
    {
 | 
			
		||||
        // Given
 | 
			
		||||
        var console = new TestConsole().Width(width);
 | 
			
		||||
 | 
			
		||||
        // When
 | 
			
		||||
        console.Write(new Rule(input));
 | 
			
		||||
 | 
			
		||||
        // Then
 | 
			
		||||
        console.Lines.Count.ShouldBe(1);
 | 
			
		||||
        console.Lines[0].ShouldBe(expected);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,131 +1,119 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Spectre.Console.Testing;
 | 
			
		||||
using Spectre.Verify.Extensions;
 | 
			
		||||
using VerifyXunit;
 | 
			
		||||
using Xunit;
 | 
			
		||||
namespace Spectre.Console.Tests.Unit;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Unit
 | 
			
		||||
[UsesVerify]
 | 
			
		||||
[ExpectationPath("Widgets/Table/Rows/Extensions")]
 | 
			
		||||
public sealed class TableRowCollectionExtensionsTests
 | 
			
		||||
{
 | 
			
		||||
    [UsesVerify]
 | 
			
		||||
    [ExpectationPath("Widgets/Table/Rows/Extensions")]
 | 
			
		||||
    public sealed class TableRowCollectionExtensionsTests
 | 
			
		||||
    public sealed class TheAddRowMethod
 | 
			
		||||
    {
 | 
			
		||||
        [UsesVerify]
 | 
			
		||||
        public sealed class TheAddRowMethod
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Add", "Renderables")]
 | 
			
		||||
        public Task Should_Add_Renderables()
 | 
			
		||||
        {
 | 
			
		||||
            [Fact]
 | 
			
		||||
            [Expectation("Add", "Renderables")]
 | 
			
		||||
            public Task Should_Add_Renderables()
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var console = new TestConsole();
 | 
			
		||||
                var table = new Table();
 | 
			
		||||
                table.AddColumn("Column #1");
 | 
			
		||||
                table.AddColumn("Column #2");
 | 
			
		||||
                table.AddRow(new[] { new Text("1"), new Text("1-2") });
 | 
			
		||||
                table.AddRow(new[] { new Text("2"), new Text("2-2") });
 | 
			
		||||
                table.AddRow(new[] { new Text("3"), new Text("3-2") });
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
            var table = new Table();
 | 
			
		||||
            table.AddColumn("Column #1");
 | 
			
		||||
            table.AddColumn("Column #2");
 | 
			
		||||
            table.AddRow(new[] { new Text("1"), new Text("1-2") });
 | 
			
		||||
            table.AddRow(new[] { new Text("2"), new Text("2-2") });
 | 
			
		||||
            table.AddRow(new[] { new Text("3"), new Text("3-2") });
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                console.Write(table);
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(table);
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                return Verifier.Verify(console.Output);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            [Expectation("Add", "Strings")]
 | 
			
		||||
            public Task Should_Add_Strings()
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var console = new TestConsole();
 | 
			
		||||
                var table = new Table();
 | 
			
		||||
                table.AddColumn("Column #1");
 | 
			
		||||
                table.AddColumn("Column #2");
 | 
			
		||||
                table.AddRow("1", "1-2");
 | 
			
		||||
                table.AddRow("2", "2-2");
 | 
			
		||||
                table.AddRow("3", "3-2");
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                console.Write(table);
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                return Verifier.Verify(console.Output);
 | 
			
		||||
            }
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [UsesVerify]
 | 
			
		||||
        public sealed class TheInsertRowMethod
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Add", "Strings")]
 | 
			
		||||
        public Task Should_Add_Strings()
 | 
			
		||||
        {
 | 
			
		||||
            [Fact]
 | 
			
		||||
            [Expectation("Insert", "Renderables")]
 | 
			
		||||
            public Task Should_Insert_Renderables()
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var console = new TestConsole();
 | 
			
		||||
                var table = new Table();
 | 
			
		||||
                table.AddColumn("Column #1");
 | 
			
		||||
                table.AddColumn("Column #2");
 | 
			
		||||
                table.AddRow(new[] { new Text("1"), new Text("1-2") });
 | 
			
		||||
                table.AddRow(new[] { new Text("2"), new Text("2-2") });
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
            var table = new Table();
 | 
			
		||||
            table.AddColumn("Column #1");
 | 
			
		||||
            table.AddColumn("Column #2");
 | 
			
		||||
            table.AddRow("1", "1-2");
 | 
			
		||||
            table.AddRow("2", "2-2");
 | 
			
		||||
            table.AddRow("3", "3-2");
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                table.InsertRow(1, new[] { new Text("3"), new Text("3-2") });
 | 
			
		||||
            // When
 | 
			
		||||
            console.Write(table);
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                console.Write(table);
 | 
			
		||||
                return Verifier.Verify(console.Output);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [Fact]
 | 
			
		||||
            [Expectation("Insert", "Strings")]
 | 
			
		||||
            public Task Should_Insert_Strings()
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var console = new TestConsole();
 | 
			
		||||
                var table = new Table();
 | 
			
		||||
                table.AddColumn("Column #1");
 | 
			
		||||
                table.AddColumn("Column #2");
 | 
			
		||||
                table.AddRow("1", "1-2");
 | 
			
		||||
                table.AddRow("2", "2-2");
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                table.InsertRow(1, "3", "3-2");
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                console.Write(table);
 | 
			
		||||
                return Verifier.Verify(console.Output);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [UsesVerify]
 | 
			
		||||
        public sealed class TheRemoveRowMethod
 | 
			
		||||
        {
 | 
			
		||||
            [Fact]
 | 
			
		||||
            [Expectation("Remove")]
 | 
			
		||||
            public Task Should_Remove_Row()
 | 
			
		||||
            {
 | 
			
		||||
                // Given
 | 
			
		||||
                var console = new TestConsole();
 | 
			
		||||
                var table = new Table();
 | 
			
		||||
                table.AddColumn("Column #1");
 | 
			
		||||
                table.AddColumn("Column #2");
 | 
			
		||||
                table.AddRow(new[] { new Text("1"), new Text("1-2") });
 | 
			
		||||
                table.AddRow(new[] { new Text("2"), new Text("2-2") });
 | 
			
		||||
                table.AddRow(new[] { new Text("3"), new Text("3-2") });
 | 
			
		||||
 | 
			
		||||
                // When
 | 
			
		||||
                table.RemoveRow(1);
 | 
			
		||||
 | 
			
		||||
                // Then
 | 
			
		||||
                console.Write(table);
 | 
			
		||||
                return Verifier.Verify(console.Output);
 | 
			
		||||
            }
 | 
			
		||||
            // Then
 | 
			
		||||
            return Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    [UsesVerify]
 | 
			
		||||
    public sealed class TheInsertRowMethod
 | 
			
		||||
    {
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Insert", "Renderables")]
 | 
			
		||||
        public Task Should_Insert_Renderables()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
            var table = new Table();
 | 
			
		||||
            table.AddColumn("Column #1");
 | 
			
		||||
            table.AddColumn("Column #2");
 | 
			
		||||
            table.AddRow(new[] { new Text("1"), new Text("1-2") });
 | 
			
		||||
            table.AddRow(new[] { new Text("2"), new Text("2-2") });
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            table.InsertRow(1, new[] { new Text("3"), new Text("3-2") });
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            console.Write(table);
 | 
			
		||||
            return Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Insert", "Strings")]
 | 
			
		||||
        public Task Should_Insert_Strings()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
            var table = new Table();
 | 
			
		||||
            table.AddColumn("Column #1");
 | 
			
		||||
            table.AddColumn("Column #2");
 | 
			
		||||
            table.AddRow("1", "1-2");
 | 
			
		||||
            table.AddRow("2", "2-2");
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            table.InsertRow(1, "3", "3-2");
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            console.Write(table);
 | 
			
		||||
            return Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [UsesVerify]
 | 
			
		||||
    public sealed class TheRemoveRowMethod
 | 
			
		||||
    {
 | 
			
		||||
        [Fact]
 | 
			
		||||
        [Expectation("Remove")]
 | 
			
		||||
        public Task Should_Remove_Row()
 | 
			
		||||
        {
 | 
			
		||||
            // Given
 | 
			
		||||
            var console = new TestConsole();
 | 
			
		||||
            var table = new Table();
 | 
			
		||||
            table.AddColumn("Column #1");
 | 
			
		||||
            table.AddColumn("Column #2");
 | 
			
		||||
            table.AddRow(new[] { new Text("1"), new Text("1-2") });
 | 
			
		||||
            table.AddRow(new[] { new Text("2"), new Text("2-2") });
 | 
			
		||||
            table.AddRow(new[] { new Text("3"), new Text("3-2") });
 | 
			
		||||
 | 
			
		||||
            // When
 | 
			
		||||
            table.RemoveRow(1);
 | 
			
		||||
 | 
			
		||||
            // Then
 | 
			
		||||
            console.Write(table);
 | 
			
		||||
            return Verifier.Verify(console.Output);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user