mirror of
https://github.com/nsnail/spectre.console.git
synced 2025-06-19 21:38:16 +08:00
Add global usings (#668)
* Use global usings * Fix namespace declarations for test projects
This commit is contained in:
@ -1,35 +1,107 @@
|
||||
root = false
|
||||
[*.cs]
|
||||
|
||||
[*.cs]
|
||||
# Default severity for analyzer diagnostics with category 'StyleCop.CSharp.DocumentationRules'
|
||||
dotnet_analyzer_diagnostic.category-StyleCop.CSharp.DocumentationRules.severity = none
|
||||
|
||||
# CA1707: Identifiers should not contain underscores
|
||||
dotnet_diagnostic.CA1707.severity = none
|
||||
# IDE0055: Fix formatting
|
||||
dotnet_diagnostic.IDE0055.severity = warning
|
||||
|
||||
# SA1600: Elements should be documented
|
||||
dotnet_diagnostic.SA1600.severity = none
|
||||
# SA1101: Prefix local calls with this
|
||||
dotnet_diagnostic.SA1101.severity = none
|
||||
|
||||
# SA1601: Partial elements should be documented
|
||||
dotnet_diagnostic.SA1601.severity = none
|
||||
# SA1633: File should have header
|
||||
dotnet_diagnostic.SA1633.severity = none
|
||||
|
||||
# SA1200: Using directives should be placed correctly
|
||||
dotnet_diagnostic.SA1200.severity = none
|
||||
# SA1201: Elements should appear in the correct order
|
||||
dotnet_diagnostic.SA1201.severity = none
|
||||
|
||||
# SA1202: Public members should come before private members
|
||||
dotnet_diagnostic.SA1202.severity = none
|
||||
|
||||
# SA1309: Field names should not begin with underscore
|
||||
dotnet_diagnostic.SA1309.severity = none
|
||||
|
||||
# SA1404: Code analysis suppressions should have justification
|
||||
dotnet_diagnostic.SA1404.severity = none
|
||||
|
||||
# SA1516: Elements should be separated by a blank line
|
||||
dotnet_diagnostic.SA1516.severity = none
|
||||
|
||||
# CA1303: Do not pass literals as localized parameters
|
||||
dotnet_diagnostic.CA1303.severity = none
|
||||
|
||||
# CSA1204: Static members should appear before non-static members
|
||||
dotnet_diagnostic.SA1204.severity = none
|
||||
|
||||
# IDE0052: Remove unread private members
|
||||
dotnet_diagnostic.IDE0052.severity = warning
|
||||
|
||||
# IDE0063: Use simple 'using' statement
|
||||
csharp_prefer_simple_using_statement = false:suggestion
|
||||
|
||||
# IDE0018: Variable declaration can be inlined
|
||||
dotnet_diagnostic.IDE0018.severity = warning
|
||||
|
||||
# SA1625: Element documenation should not be copied and pasted
|
||||
dotnet_diagnostic.SA1625.severity = none
|
||||
|
||||
# IDE0005: Using directive is unnecessary
|
||||
dotnet_diagnostic.IDE0005.severity = warning
|
||||
|
||||
# SA1117: Parameters should be on same line or separate lines
|
||||
dotnet_diagnostic.SA1117.severity = none
|
||||
|
||||
# SA1404: Code analysis suppression should have justification
|
||||
dotnet_diagnostic.SA1404.severity = none
|
||||
|
||||
# SA1101: Prefix local calls with this
|
||||
dotnet_diagnostic.SA1101.severity = none
|
||||
|
||||
# SA1633: File should have header
|
||||
dotnet_diagnostic.SA1633.severity = none
|
||||
|
||||
# SA1649: File name should match first type name
|
||||
dotnet_diagnostic.SA1649.severity = none
|
||||
|
||||
# SA1402: File may only contain a single type
|
||||
dotnet_diagnostic.SA1402.severity = none
|
||||
|
||||
# CA1814: Prefer jagged arrays over multidimensional
|
||||
dotnet_diagnostic.CA1814.severity = none
|
||||
|
||||
# RCS1194: Implement exception constructors.
|
||||
dotnet_diagnostic.RCS1194.severity = none
|
||||
|
||||
# CA1032: Implement standard exception constructors
|
||||
dotnet_diagnostic.CA1032.severity = none
|
||||
|
||||
# CA1826: Do not use Enumerable methods on indexable collections. Instead use the collection directly
|
||||
dotnet_diagnostic.CA1826.severity = none
|
||||
|
||||
# RCS1079: Throwing of new NotImplementedException.
|
||||
dotnet_diagnostic.RCS1079.severity = warning
|
||||
|
||||
# RCS1057: Add empty line between declarations.
|
||||
dotnet_diagnostic.RCS1057.severity = none
|
||||
|
||||
# RCS1057: Validate arguments correctly
|
||||
dotnet_diagnostic.RCS1227.severity = none
|
||||
|
||||
# IDE0004: Remove Unnecessary Cast
|
||||
dotnet_diagnostic.IDE0004.severity = warning
|
||||
|
||||
# CA1810: Initialize reference type static fields inline
|
||||
dotnet_diagnostic.CA1810.severity = none
|
||||
|
||||
# IDE0044: Add readonly modifier
|
||||
dotnet_diagnostic.IDE0044.severity = warning
|
||||
|
||||
# RCS1047: Non-asynchronous method name should not end with 'Async'.
|
||||
dotnet_diagnostic.RCS1047.severity = none
|
||||
|
||||
# RCS1090: Call 'ConfigureAwait(false)'.
|
||||
dotnet_diagnostic.RCS1090.severity = warning
|
||||
|
||||
# CS1591: Missing XML comment for publicly visible type or member
|
||||
dotnet_diagnostic.CS1591.severity = none
|
||||
|
||||
# SA1210: Using directives should be ordered alphabetically by namespace
|
||||
dotnet_diagnostic.SA1210.severity = none
|
||||
|
||||
# CA1034: Nested types should not be visible
|
||||
dotnet_diagnostic.CA1034.severity = none
|
||||
|
||||
# CA2000: Dispose objects before losing scope
|
||||
dotnet_diagnostic.CA2000.severity = none
|
||||
|
||||
# SA1118: Parameter should not span multiple lines
|
||||
dotnet_diagnostic.SA1118.severity = none
|
||||
|
||||
# CA1031: Do not catch general exception types
|
||||
dotnet_diagnostic.CA1031.severity = none
|
||||
dotnet_diagnostic.CS1591.severity = none
|
16
test/Directory.Build.props
Normal file
16
test/Directory.Build.props
Normal file
@ -0,0 +1,16 @@
|
||||
<Project>
|
||||
<PropertyGroup Label="Settings">
|
||||
<LangVersion>10</LangVersion>
|
||||
<IsPackable>false</IsPackable>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.312">
|
||||
<PrivateAssets>All</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Roslynator.Analyzers" Version="3.3.0">
|
||||
<PrivateAssets>All</PrivateAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
</Project>
|
12
test/Spectre.Console.Analyzer.Tests/CodeAnalyzerHelper.cs
Normal file
12
test/Spectre.Console.Analyzer.Tests/CodeAnalyzerHelper.cs
Normal file
@ -0,0 +1,12 @@
|
||||
namespace Spectre.Console.Analyzer.Tests;
|
||||
|
||||
internal static class CodeAnalyzerHelper
|
||||
{
|
||||
internal static ReferenceAssemblies CurrentSpectre { get; }
|
||||
|
||||
static CodeAnalyzerHelper()
|
||||
{
|
||||
CurrentSpectre = ReferenceAssemblies.Net.Net50.AddAssemblies(
|
||||
ImmutableArray.Create(typeof(AnsiConsole).Assembly.Location.Replace(".dll", string.Empty)));
|
||||
}
|
||||
}
|
@ -1,55 +1,44 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.CodeAnalysis.CodeFixes;
|
||||
using Microsoft.VisualStudio.Composition;
|
||||
using Spectre.Console.Analyzer.FixProviders;
|
||||
namespace Spectre.Console.Analyzer.Tests;
|
||||
|
||||
namespace Spectre.Console.Analyzer.Tests
|
||||
internal static class CodeFixProviderDiscovery
|
||||
{
|
||||
internal static class CodeFixProviderDiscovery
|
||||
private static readonly Lazy<IExportProviderFactory> _exportProviderFactory;
|
||||
|
||||
static CodeFixProviderDiscovery()
|
||||
{
|
||||
private static readonly Lazy<IExportProviderFactory> _exportProviderFactory;
|
||||
|
||||
static CodeFixProviderDiscovery()
|
||||
{
|
||||
_exportProviderFactory = new Lazy<IExportProviderFactory>(
|
||||
() =>
|
||||
{
|
||||
var discovery = new AttributedPartDiscovery(Resolver.DefaultInstance, isNonPublicSupported: true);
|
||||
var parts = Task.Run(() => discovery.CreatePartsAsync(typeof(SystemConsoleToAnsiConsoleFix).Assembly)).GetAwaiter().GetResult();
|
||||
var catalog = ComposableCatalog.Create(Resolver.DefaultInstance).AddParts(parts);
|
||||
|
||||
var configuration = CompositionConfiguration.Create(catalog);
|
||||
var runtimeComposition = RuntimeComposition.CreateRuntimeComposition(configuration);
|
||||
return runtimeComposition.CreateExportProviderFactory();
|
||||
},
|
||||
LazyThreadSafetyMode.ExecutionAndPublication);
|
||||
}
|
||||
|
||||
public static IEnumerable<CodeFixProvider> GetCodeFixProviders(string language)
|
||||
{
|
||||
var exportProvider = _exportProviderFactory.Value.CreateExportProvider();
|
||||
var exports = exportProvider.GetExports<CodeFixProvider, LanguageMetadata>();
|
||||
return exports.Where(export => export.Metadata.Languages.Contains(language)).Select(export => export.Value);
|
||||
}
|
||||
|
||||
private class LanguageMetadata
|
||||
{
|
||||
public LanguageMetadata(IDictionary<string, object> data)
|
||||
_exportProviderFactory = new Lazy<IExportProviderFactory>(
|
||||
() =>
|
||||
{
|
||||
if (!data.TryGetValue(nameof(ExportCodeFixProviderAttribute.Languages), out var languages))
|
||||
{
|
||||
languages = Array.Empty<string>();
|
||||
}
|
||||
var discovery = new AttributedPartDiscovery(Resolver.DefaultInstance, isNonPublicSupported: true);
|
||||
var parts = Task.Run(() => discovery.CreatePartsAsync(typeof(SystemConsoleToAnsiConsoleFix).Assembly)).GetAwaiter().GetResult();
|
||||
var catalog = ComposableCatalog.Create(Resolver.DefaultInstance).AddParts(parts);
|
||||
|
||||
Languages = ((string[])languages).ToImmutableArray();
|
||||
var configuration = CompositionConfiguration.Create(catalog);
|
||||
var runtimeComposition = RuntimeComposition.CreateRuntimeComposition(configuration);
|
||||
return runtimeComposition.CreateExportProviderFactory();
|
||||
},
|
||||
LazyThreadSafetyMode.ExecutionAndPublication);
|
||||
}
|
||||
|
||||
public static IEnumerable<CodeFixProvider> GetCodeFixProviders(string language)
|
||||
{
|
||||
var exportProvider = _exportProviderFactory.Value.CreateExportProvider();
|
||||
var exports = exportProvider.GetExports<CodeFixProvider, LanguageMetadata>();
|
||||
return exports.Where(export => export.Metadata.Languages.Contains(language)).Select(export => export.Value);
|
||||
}
|
||||
|
||||
private class LanguageMetadata
|
||||
{
|
||||
public LanguageMetadata(IDictionary<string, object> data)
|
||||
{
|
||||
if (!data.TryGetValue(nameof(ExportCodeFixProviderAttribute.Languages), out var languages))
|
||||
{
|
||||
languages = Array.Empty<string>();
|
||||
}
|
||||
|
||||
public ImmutableArray<string> Languages { get; }
|
||||
Languages = ((string[])languages).ToImmutableArray();
|
||||
}
|
||||
|
||||
public ImmutableArray<string> Languages { get; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
15
test/Spectre.Console.Analyzer.Tests/Properties/Usings.cs
Normal file
15
test/Spectre.Console.Analyzer.Tests/Properties/Usings.cs
Normal file
@ -0,0 +1,15 @@
|
||||
global using System;
|
||||
global using System.Collections.Generic;
|
||||
global using System.Collections.Immutable;
|
||||
global using System.Linq;
|
||||
global using System.Threading;
|
||||
global using System.Threading.Tasks;
|
||||
global using Microsoft.CodeAnalysis;
|
||||
global using Microsoft.CodeAnalysis.CodeFixes;
|
||||
global using Microsoft.CodeAnalysis.CSharp.Testing;
|
||||
global using Microsoft.CodeAnalysis.Diagnostics;
|
||||
global using Microsoft.CodeAnalysis.Testing;
|
||||
global using Microsoft.CodeAnalysis.Testing.Verifiers;
|
||||
global using Microsoft.VisualStudio.Composition;
|
||||
global using Spectre.Console.Analyzer.FixProviders;
|
||||
global using Xunit;
|
@ -5,6 +5,10 @@
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<AdditionalFiles Include="..\..\src\stylecop.json" Link="Properties/stylecop.json" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Analyzer.Testing.XUnit" Version="1.1.0" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.CodeFix.Testing.XUnit" Version="1.1.0" />
|
||||
|
@ -1,86 +1,63 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.CodeAnalysis.CodeFixes;
|
||||
using Microsoft.CodeAnalysis.CSharp.Testing;
|
||||
using Microsoft.CodeAnalysis.Diagnostics;
|
||||
using Microsoft.CodeAnalysis.Testing;
|
||||
using Microsoft.CodeAnalysis.Testing.Verifiers;
|
||||
namespace Spectre.Console.Analyzer.Tests;
|
||||
|
||||
namespace Spectre.Console.Analyzer.Tests
|
||||
public static class SpectreAnalyzerVerifier<TAnalyzer>
|
||||
where TAnalyzer : DiagnosticAnalyzer, new()
|
||||
{
|
||||
public static class SpectreAnalyzerVerifier<TAnalyzer>
|
||||
where TAnalyzer : DiagnosticAnalyzer, new()
|
||||
public static Task VerifyCodeFixAsync(string source, DiagnosticResult expected, string fixedSource)
|
||||
=> VerifyCodeFixAsync(source, new[] { expected }, fixedSource);
|
||||
|
||||
private static Task VerifyCodeFixAsync(string source, IEnumerable<DiagnosticResult> expected, string fixedSource)
|
||||
{
|
||||
public static Task VerifyCodeFixAsync(string source, DiagnosticResult expected, string fixedSource)
|
||||
=> VerifyCodeFixAsync(source, new[] { expected }, fixedSource);
|
||||
|
||||
private static Task VerifyCodeFixAsync(string source, IEnumerable<DiagnosticResult> expected, string fixedSource)
|
||||
// Roslyn fixers always use \r\n for newlines, regardless of OS environment settings, so we normalize
|
||||
// the source as it typically comes from multi-line strings with varying newlines.
|
||||
if (Environment.NewLine != "\r\n")
|
||||
{
|
||||
// Roslyn fixers always use \r\n for newlines, regardless of OS environment settings, so we normalize
|
||||
// the source as it typically comes from multi-line strings with varying newlines.
|
||||
if (Environment.NewLine != "\r\n")
|
||||
{
|
||||
source = source.Replace(Environment.NewLine, "\r\n");
|
||||
fixedSource = fixedSource.Replace(Environment.NewLine, "\r\n");
|
||||
}
|
||||
|
||||
var test = new Test
|
||||
{
|
||||
TestCode = source,
|
||||
FixedCode = fixedSource,
|
||||
};
|
||||
|
||||
test.ExpectedDiagnostics.AddRange(expected);
|
||||
return test.RunAsync();
|
||||
source = source.Replace(Environment.NewLine, "\r\n");
|
||||
fixedSource = fixedSource.Replace(Environment.NewLine, "\r\n");
|
||||
}
|
||||
|
||||
public static Task VerifyAnalyzerAsync(string source, params DiagnosticResult[] expected)
|
||||
var test = new Test
|
||||
{
|
||||
var test = new Test
|
||||
{
|
||||
TestCode = source,
|
||||
CompilerDiagnostics = CompilerDiagnostics.All,
|
||||
};
|
||||
TestCode = source,
|
||||
FixedCode = fixedSource,
|
||||
};
|
||||
|
||||
test.ExpectedDiagnostics.AddRange(expected);
|
||||
return test.RunAsync();
|
||||
test.ExpectedDiagnostics.AddRange(expected);
|
||||
return test.RunAsync();
|
||||
}
|
||||
|
||||
public static Task VerifyAnalyzerAsync(string source, params DiagnosticResult[] expected)
|
||||
{
|
||||
var test = new Test
|
||||
{
|
||||
TestCode = source,
|
||||
CompilerDiagnostics = CompilerDiagnostics.All,
|
||||
};
|
||||
|
||||
test.ExpectedDiagnostics.AddRange(expected);
|
||||
return test.RunAsync();
|
||||
}
|
||||
|
||||
// Code fix tests support both analyzer and code fix testing. This test class is derived from the code fix test
|
||||
// to avoid the need to maintain duplicate copies of the customization work.
|
||||
private class Test : CSharpCodeFixTest<TAnalyzer, EmptyCodeFixProvider, XUnitVerifier>
|
||||
{
|
||||
public Test()
|
||||
{
|
||||
ReferenceAssemblies = CodeAnalyzerHelper.CurrentSpectre;
|
||||
TestBehaviors |= TestBehaviors.SkipGeneratedCodeCheck;
|
||||
}
|
||||
|
||||
// Code fix tests support both analyzer and code fix testing. This test class is derived from the code fix test
|
||||
// to avoid the need to maintain duplicate copies of the customization work.
|
||||
private class Test : CSharpCodeFixTest<TAnalyzer, EmptyCodeFixProvider, XUnitVerifier>
|
||||
protected override IEnumerable<CodeFixProvider> GetCodeFixProviders()
|
||||
{
|
||||
public Test()
|
||||
var analyzer = new TAnalyzer();
|
||||
foreach (var provider in CodeFixProviderDiscovery.GetCodeFixProviders(Language))
|
||||
{
|
||||
ReferenceAssemblies = CodeAnalyzerHelper.CurrentSpectre;
|
||||
TestBehaviors |= TestBehaviors.SkipGeneratedCodeCheck;
|
||||
}
|
||||
|
||||
protected override IEnumerable<CodeFixProvider> GetCodeFixProviders()
|
||||
{
|
||||
var analyzer = new TAnalyzer();
|
||||
foreach (var provider in CodeFixProviderDiscovery.GetCodeFixProviders(Language))
|
||||
if (analyzer.SupportedDiagnostics.Any(diagnostic => provider.FixableDiagnosticIds.Contains(diagnostic.Id)))
|
||||
{
|
||||
if (analyzer.SupportedDiagnostics.Any(diagnostic => provider.FixableDiagnosticIds.Contains(diagnostic.Id)))
|
||||
{
|
||||
yield return provider;
|
||||
}
|
||||
yield return provider;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static class CodeAnalyzerHelper
|
||||
{
|
||||
internal static ReferenceAssemblies CurrentSpectre { get; }
|
||||
|
||||
static CodeAnalyzerHelper()
|
||||
{
|
||||
CurrentSpectre = ReferenceAssemblies.Net.Net50.AddAssemblies(
|
||||
ImmutableArray.Create(typeof(AnsiConsole).Assembly.Location.Replace(".dll", string.Empty)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,19 +1,15 @@
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.Testing;
|
||||
using Xunit;
|
||||
namespace Spectre.Console.Analyzer.Tests.Unit.Analyzers;
|
||||
|
||||
namespace Spectre.Console.Analyzer.Tests.Unit.Analyzers
|
||||
public class NoCurrentLiveRenderablesTests
|
||||
{
|
||||
public class NoCurrentLiveRenderablesTests
|
||||
{
|
||||
private static readonly DiagnosticResult _expectedDiagnostics = new(
|
||||
Descriptors.S1020_AvoidConcurrentCallsToMultipleLiveRenderables.Id,
|
||||
DiagnosticSeverity.Warning);
|
||||
private static readonly DiagnosticResult _expectedDiagnostics = new(
|
||||
Descriptors.S1020_AvoidConcurrentCallsToMultipleLiveRenderables.Id,
|
||||
DiagnosticSeverity.Warning);
|
||||
|
||||
[Fact]
|
||||
public async void Status_call_within_live_call_warns()
|
||||
{
|
||||
const string Source = @"
|
||||
[Fact]
|
||||
public async void Status_call_within_live_call_warns()
|
||||
{
|
||||
const string Source = @"
|
||||
using Spectre.Console;
|
||||
|
||||
class TestClass
|
||||
@ -27,15 +23,15 @@ class TestClass
|
||||
}
|
||||
}";
|
||||
|
||||
await SpectreAnalyzerVerifier<NoConcurrentLiveRenderablesAnalyzer>
|
||||
.VerifyAnalyzerAsync(Source, _expectedDiagnostics.WithLocation(10, 13))
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
await SpectreAnalyzerVerifier<NoConcurrentLiveRenderablesAnalyzer>
|
||||
.VerifyAnalyzerAsync(Source, _expectedDiagnostics.WithLocation(10, 13))
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async void Status_call_within_live_call_warns_with_instance()
|
||||
{
|
||||
const string Source = @"
|
||||
[Fact]
|
||||
public async void Status_call_within_live_call_warns_with_instance()
|
||||
{
|
||||
const string Source = @"
|
||||
using Spectre.Console;
|
||||
|
||||
class Child
|
||||
@ -51,15 +47,15 @@ class Child
|
||||
}
|
||||
}";
|
||||
|
||||
await SpectreAnalyzerVerifier<NoConcurrentLiveRenderablesAnalyzer>
|
||||
.VerifyAnalyzerAsync(Source, _expectedDiagnostics.WithLocation(12, 13))
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
await SpectreAnalyzerVerifier<NoConcurrentLiveRenderablesAnalyzer>
|
||||
.VerifyAnalyzerAsync(Source, _expectedDiagnostics.WithLocation(12, 13))
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async void Calling_start_on_non_live_renderable_has_no_warning()
|
||||
{
|
||||
const string Source = @"
|
||||
[Fact]
|
||||
public async void Calling_start_on_non_live_renderable_has_no_warning()
|
||||
{
|
||||
const string Source = @"
|
||||
using Spectre.Console;
|
||||
|
||||
class Program
|
||||
@ -72,9 +68,8 @@ class Program
|
||||
static void Start() => AnsiConsole.WriteLine(""Starting..."");
|
||||
}";
|
||||
|
||||
await SpectreAnalyzerVerifier<NoConcurrentLiveRenderablesAnalyzer>
|
||||
.VerifyAnalyzerAsync(Source)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
await SpectreAnalyzerVerifier<NoConcurrentLiveRenderablesAnalyzer>
|
||||
.VerifyAnalyzerAsync(Source)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,20 +1,15 @@
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.Testing;
|
||||
using Xunit;
|
||||
namespace Spectre.Console.Analyzer.Tests.Unit.Analyzers;
|
||||
|
||||
namespace Spectre.Console.Analyzer.Tests.Unit.Analyzers
|
||||
public class NoPromptsDuringLiveRenderablesTests
|
||||
{
|
||||
public class NoPromptsDuringLiveRenderablesTests
|
||||
{
|
||||
private static readonly DiagnosticResult _expectedDiagnostics = new(
|
||||
Descriptors.S1021_AvoidPromptCallsDuringLiveRenderables.Id,
|
||||
DiagnosticSeverity.Warning);
|
||||
private static readonly DiagnosticResult _expectedDiagnostics = new(
|
||||
Descriptors.S1021_AvoidPromptCallsDuringLiveRenderables.Id,
|
||||
DiagnosticSeverity.Warning);
|
||||
|
||||
[Fact]
|
||||
public async Task Prompt_out_of_progress_does_not_warn()
|
||||
{
|
||||
const string Source = @"
|
||||
[Fact]
|
||||
public async Task Prompt_out_of_progress_does_not_warn()
|
||||
{
|
||||
const string Source = @"
|
||||
using Spectre.Console;
|
||||
|
||||
class TestClass
|
||||
@ -25,15 +20,15 @@ class TestClass
|
||||
}
|
||||
}";
|
||||
|
||||
await SpectreAnalyzerVerifier<NoPromptsDuringLiveRenderablesAnalyzer>
|
||||
.VerifyAnalyzerAsync(Source)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
await SpectreAnalyzerVerifier<NoPromptsDuringLiveRenderablesAnalyzer>
|
||||
.VerifyAnalyzerAsync(Source)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Instance_variables_warn()
|
||||
{
|
||||
const string Source = @"
|
||||
[Fact]
|
||||
public async Task Instance_variables_warn()
|
||||
{
|
||||
const string Source = @"
|
||||
using Spectre.Console;
|
||||
|
||||
class TestClass
|
||||
@ -49,15 +44,15 @@ class TestClass
|
||||
}
|
||||
}";
|
||||
|
||||
await SpectreAnalyzerVerifier<NoPromptsDuringLiveRenderablesAnalyzer>
|
||||
.VerifyAnalyzerAsync(Source, _expectedDiagnostics.WithLocation(12, 26))
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
await SpectreAnalyzerVerifier<NoPromptsDuringLiveRenderablesAnalyzer>
|
||||
.VerifyAnalyzerAsync(Source, _expectedDiagnostics.WithLocation(12, 26))
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Prompt_in_progress_warns()
|
||||
{
|
||||
const string Source = @"
|
||||
[Fact]
|
||||
public async Task Prompt_in_progress_warns()
|
||||
{
|
||||
const string Source = @"
|
||||
using Spectre.Console;
|
||||
|
||||
class TestClass
|
||||
@ -71,15 +66,15 @@ class TestClass
|
||||
}
|
||||
}";
|
||||
|
||||
await SpectreAnalyzerVerifier<NoPromptsDuringLiveRenderablesAnalyzer>
|
||||
.VerifyAnalyzerAsync(Source, _expectedDiagnostics.WithLocation(10, 13))
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
await SpectreAnalyzerVerifier<NoPromptsDuringLiveRenderablesAnalyzer>
|
||||
.VerifyAnalyzerAsync(Source, _expectedDiagnostics.WithLocation(10, 13))
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Can_call_other_methods_from_within_renderables()
|
||||
{
|
||||
const string Source = @"
|
||||
[Fact]
|
||||
public async Task Can_call_other_methods_from_within_renderables()
|
||||
{
|
||||
const string Source = @"
|
||||
using Spectre.Console;
|
||||
|
||||
class Program
|
||||
@ -96,9 +91,8 @@ class Program
|
||||
static string Confirm() => string.Empty;
|
||||
}";
|
||||
|
||||
await SpectreAnalyzerVerifier<NoPromptsDuringLiveRenderablesAnalyzer>
|
||||
.VerifyAnalyzerAsync(Source)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
await SpectreAnalyzerVerifier<NoPromptsDuringLiveRenderablesAnalyzer>
|
||||
.VerifyAnalyzerAsync(Source)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,19 +1,15 @@
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.Testing;
|
||||
using Xunit;
|
||||
namespace Spectre.Console.Analyzer.Tests.Unit.Analyzers;
|
||||
|
||||
namespace Spectre.Console.Analyzer.Tests.Unit.Analyzers
|
||||
public class FavorInstanceAnsiConsoleOverStaticAnalyzerTests
|
||||
{
|
||||
public class FavorInstanceAnsiConsoleOverStaticAnalyzerTests
|
||||
{
|
||||
private static readonly DiagnosticResult _expectedDiagnostics = new(
|
||||
Descriptors.S1010_FavorInstanceAnsiConsoleOverStatic.Id,
|
||||
DiagnosticSeverity.Info);
|
||||
private static readonly DiagnosticResult _expectedDiagnostics = new(
|
||||
Descriptors.S1010_FavorInstanceAnsiConsoleOverStatic.Id,
|
||||
DiagnosticSeverity.Info);
|
||||
|
||||
[Fact]
|
||||
public async void Should_only_warn_within_methods()
|
||||
{
|
||||
const string Source = @"
|
||||
[Fact]
|
||||
public async void Should_only_warn_within_methods()
|
||||
{
|
||||
const string Source = @"
|
||||
using Spectre.Console;
|
||||
|
||||
internal sealed class Foo
|
||||
@ -27,15 +23,15 @@ internal sealed class Foo
|
||||
}
|
||||
";
|
||||
|
||||
await SpectreAnalyzerVerifier<FavorInstanceAnsiConsoleOverStaticAnalyzer>
|
||||
.VerifyAnalyzerAsync(Source)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
await SpectreAnalyzerVerifier<FavorInstanceAnsiConsoleOverStaticAnalyzer>
|
||||
.VerifyAnalyzerAsync(Source)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async void Instance_console_has_no_warnings()
|
||||
{
|
||||
const string Source = @"
|
||||
[Fact]
|
||||
public async void Instance_console_has_no_warnings()
|
||||
{
|
||||
const string Source = @"
|
||||
using Spectre.Console;
|
||||
|
||||
class TestClass
|
||||
@ -48,15 +44,15 @@ class TestClass
|
||||
}
|
||||
}";
|
||||
|
||||
await SpectreAnalyzerVerifier<FavorInstanceAnsiConsoleOverStaticAnalyzer>
|
||||
.VerifyAnalyzerAsync(Source)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
await SpectreAnalyzerVerifier<FavorInstanceAnsiConsoleOverStaticAnalyzer>
|
||||
.VerifyAnalyzerAsync(Source)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async void Static_console_with_no_instance_variables_has_no_warnings()
|
||||
{
|
||||
const string Source = @"
|
||||
[Fact]
|
||||
public async void Static_console_with_no_instance_variables_has_no_warnings()
|
||||
{
|
||||
const string Source = @"
|
||||
using Spectre.Console;
|
||||
|
||||
class TestClass
|
||||
@ -67,15 +63,15 @@ class TestClass
|
||||
}
|
||||
}";
|
||||
|
||||
await SpectreAnalyzerVerifier<FavorInstanceAnsiConsoleOverStaticAnalyzer>
|
||||
.VerifyAnalyzerAsync(Source)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
await SpectreAnalyzerVerifier<FavorInstanceAnsiConsoleOverStaticAnalyzer>
|
||||
.VerifyAnalyzerAsync(Source)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async void Console_Write_Has_Warning()
|
||||
{
|
||||
const string Source = @"
|
||||
[Fact]
|
||||
public async void Console_Write_Has_Warning()
|
||||
{
|
||||
const string Source = @"
|
||||
using Spectre.Console;
|
||||
|
||||
class TestClass
|
||||
@ -89,9 +85,8 @@ class TestClass
|
||||
}
|
||||
}";
|
||||
|
||||
await SpectreAnalyzerVerifier<FavorInstanceAnsiConsoleOverStaticAnalyzer>
|
||||
.VerifyAnalyzerAsync(Source, _expectedDiagnostics.WithLocation(11, 9))
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
await SpectreAnalyzerVerifier<FavorInstanceAnsiConsoleOverStaticAnalyzer>
|
||||
.VerifyAnalyzerAsync(Source, _expectedDiagnostics.WithLocation(11, 9))
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,19 +1,15 @@
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.Testing;
|
||||
using Xunit;
|
||||
namespace Spectre.Console.Analyzer.Tests.Unit.Analyzers;
|
||||
|
||||
namespace Spectre.Console.Analyzer.Tests.Unit.Analyzers
|
||||
public class UseSpectreInsteadOfSystemConsoleAnalyzerTests
|
||||
{
|
||||
public class UseSpectreInsteadOfSystemConsoleAnalyzerTests
|
||||
{
|
||||
private static readonly DiagnosticResult _expectedDiagnostics = new(
|
||||
Descriptors.S1000_UseAnsiConsoleOverSystemConsole.Id,
|
||||
DiagnosticSeverity.Warning);
|
||||
private static readonly DiagnosticResult _expectedDiagnostics = new(
|
||||
Descriptors.S1000_UseAnsiConsoleOverSystemConsole.Id,
|
||||
DiagnosticSeverity.Warning);
|
||||
|
||||
[Fact]
|
||||
public async void Non_configured_SystemConsole_methods_report_no_warnings()
|
||||
{
|
||||
const string Source = @"
|
||||
[Fact]
|
||||
public async void Non_configured_SystemConsole_methods_report_no_warnings()
|
||||
{
|
||||
const string Source = @"
|
||||
using System;
|
||||
|
||||
class TestClass {
|
||||
@ -23,15 +19,15 @@ class TestClass {
|
||||
}
|
||||
}";
|
||||
|
||||
await SpectreAnalyzerVerifier<UseSpectreInsteadOfSystemConsoleAnalyzer>
|
||||
.VerifyAnalyzerAsync(Source)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
await SpectreAnalyzerVerifier<UseSpectreInsteadOfSystemConsoleAnalyzer>
|
||||
.VerifyAnalyzerAsync(Source)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async void Console_Write_Has_Warning()
|
||||
{
|
||||
const string Source = @"
|
||||
[Fact]
|
||||
public async void Console_Write_Has_Warning()
|
||||
{
|
||||
const string Source = @"
|
||||
using System;
|
||||
|
||||
class TestClass {
|
||||
@ -41,15 +37,15 @@ class TestClass {
|
||||
}
|
||||
}";
|
||||
|
||||
await SpectreAnalyzerVerifier<UseSpectreInsteadOfSystemConsoleAnalyzer>
|
||||
.VerifyAnalyzerAsync(Source, _expectedDiagnostics.WithLocation(7, 9))
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
await SpectreAnalyzerVerifier<UseSpectreInsteadOfSystemConsoleAnalyzer>
|
||||
.VerifyAnalyzerAsync(Source, _expectedDiagnostics.WithLocation(7, 9))
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async void Console_WriteLine_Has_Warning()
|
||||
{
|
||||
const string Source = @"
|
||||
[Fact]
|
||||
public async void Console_WriteLine_Has_Warning()
|
||||
{
|
||||
const string Source = @"
|
||||
using System;
|
||||
|
||||
class TestClass
|
||||
@ -59,9 +55,8 @@ class TestClass
|
||||
}
|
||||
}";
|
||||
|
||||
await SpectreAnalyzerVerifier<UseSpectreInsteadOfSystemConsoleAnalyzer>
|
||||
.VerifyAnalyzerAsync(Source, _expectedDiagnostics.WithLocation(7, 9))
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
await SpectreAnalyzerVerifier<UseSpectreInsteadOfSystemConsoleAnalyzer>
|
||||
.VerifyAnalyzerAsync(Source, _expectedDiagnostics.WithLocation(7, 9))
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,20 +1,15 @@
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.Testing;
|
||||
using Xunit;
|
||||
namespace Spectre.Console.Analyzer.Tests.Unit.Fixes;
|
||||
|
||||
namespace Spectre.Console.Analyzer.Tests.Unit.Fixes
|
||||
public class UseInstanceOfStaticAnsiConsoleTests
|
||||
{
|
||||
public class UseInstanceOfStaticAnsiConsoleTests
|
||||
{
|
||||
private static readonly DiagnosticResult _expectedDiagnostic = new(
|
||||
Descriptors.S1010_FavorInstanceAnsiConsoleOverStatic.Id,
|
||||
DiagnosticSeverity.Info);
|
||||
private static readonly DiagnosticResult _expectedDiagnostic = new(
|
||||
Descriptors.S1010_FavorInstanceAnsiConsoleOverStatic.Id,
|
||||
DiagnosticSeverity.Info);
|
||||
|
||||
[Fact]
|
||||
public async Task Static_call_replaced_with_field_call()
|
||||
{
|
||||
const string Source = @"
|
||||
[Fact]
|
||||
public async Task Static_call_replaced_with_field_call()
|
||||
{
|
||||
const string Source = @"
|
||||
using Spectre.Console;
|
||||
|
||||
class TestClass
|
||||
@ -28,7 +23,7 @@ class TestClass
|
||||
}
|
||||
}";
|
||||
|
||||
const string FixedSource = @"
|
||||
const string FixedSource = @"
|
||||
using Spectre.Console;
|
||||
|
||||
class TestClass
|
||||
@ -42,15 +37,15 @@ class TestClass
|
||||
}
|
||||
}";
|
||||
|
||||
await SpectreAnalyzerVerifier<FavorInstanceAnsiConsoleOverStaticAnalyzer>
|
||||
.VerifyCodeFixAsync(Source, _expectedDiagnostic.WithLocation(11, 9), FixedSource)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
await SpectreAnalyzerVerifier<FavorInstanceAnsiConsoleOverStaticAnalyzer>
|
||||
.VerifyCodeFixAsync(Source, _expectedDiagnostic.WithLocation(11, 9), FixedSource)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Static_call_replaced_with_field_call_Should_Preserve_Trivia()
|
||||
{
|
||||
const string Source = @"
|
||||
[Fact]
|
||||
public async Task Static_call_replaced_with_field_call_Should_Preserve_Trivia()
|
||||
{
|
||||
const string Source = @"
|
||||
using Spectre.Console;
|
||||
|
||||
class TestClass
|
||||
@ -66,7 +61,7 @@ class TestClass
|
||||
}
|
||||
}";
|
||||
|
||||
const string FixedSource = @"
|
||||
const string FixedSource = @"
|
||||
using Spectre.Console;
|
||||
|
||||
class TestClass
|
||||
@ -82,15 +77,15 @@ class TestClass
|
||||
}
|
||||
}";
|
||||
|
||||
await SpectreAnalyzerVerifier<FavorInstanceAnsiConsoleOverStaticAnalyzer>
|
||||
.VerifyCodeFixAsync(Source, _expectedDiagnostic.WithLocation(12, 9), FixedSource)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
await SpectreAnalyzerVerifier<FavorInstanceAnsiConsoleOverStaticAnalyzer>
|
||||
.VerifyCodeFixAsync(Source, _expectedDiagnostic.WithLocation(12, 9), FixedSource)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Static_call_replaced_with_parameter_call()
|
||||
{
|
||||
const string Source = @"
|
||||
[Fact]
|
||||
public async Task Static_call_replaced_with_parameter_call()
|
||||
{
|
||||
const string Source = @"
|
||||
using Spectre.Console;
|
||||
|
||||
class TestClass
|
||||
@ -101,7 +96,7 @@ class TestClass
|
||||
}
|
||||
}";
|
||||
|
||||
const string FixedSource = @"
|
||||
const string FixedSource = @"
|
||||
using Spectre.Console;
|
||||
|
||||
class TestClass
|
||||
@ -112,15 +107,15 @@ class TestClass
|
||||
}
|
||||
}";
|
||||
|
||||
await SpectreAnalyzerVerifier<FavorInstanceAnsiConsoleOverStaticAnalyzer>
|
||||
.VerifyCodeFixAsync(Source, _expectedDiagnostic.WithLocation(8, 9), FixedSource)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
await SpectreAnalyzerVerifier<FavorInstanceAnsiConsoleOverStaticAnalyzer>
|
||||
.VerifyCodeFixAsync(Source, _expectedDiagnostic.WithLocation(8, 9), FixedSource)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Static_call_replaced_with_static_field_if_valid()
|
||||
{
|
||||
const string Source = @"
|
||||
[Fact]
|
||||
public async Task Static_call_replaced_with_static_field_if_valid()
|
||||
{
|
||||
const string Source = @"
|
||||
using Spectre.Console;
|
||||
|
||||
class TestClass
|
||||
@ -134,7 +129,7 @@ class TestClass
|
||||
}
|
||||
}";
|
||||
|
||||
const string FixedSource = @"
|
||||
const string FixedSource = @"
|
||||
using Spectre.Console;
|
||||
|
||||
class TestClass
|
||||
@ -148,9 +143,8 @@ class TestClass
|
||||
}
|
||||
}";
|
||||
|
||||
await SpectreAnalyzerVerifier<FavorInstanceAnsiConsoleOverStaticAnalyzer>
|
||||
.VerifyCodeFixAsync(Source, _expectedDiagnostic.WithLocation(11, 9), FixedSource)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
await SpectreAnalyzerVerifier<FavorInstanceAnsiConsoleOverStaticAnalyzer>
|
||||
.VerifyCodeFixAsync(Source, _expectedDiagnostic.WithLocation(11, 9), FixedSource)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,20 +1,15 @@
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.Testing;
|
||||
using Xunit;
|
||||
namespace Spectre.Console.Analyzer.Tests.Unit.Fixes;
|
||||
|
||||
namespace Spectre.Console.Analyzer.Tests.Unit.Fixes
|
||||
public class UseSpectreInsteadOfSystemConsoleFixTests
|
||||
{
|
||||
public class UseSpectreInsteadOfSystemConsoleFixTests
|
||||
{
|
||||
private static readonly DiagnosticResult _expectedDiagnostic = new(
|
||||
Descriptors.S1000_UseAnsiConsoleOverSystemConsole.Id,
|
||||
DiagnosticSeverity.Warning);
|
||||
private static readonly DiagnosticResult _expectedDiagnostic = new(
|
||||
Descriptors.S1000_UseAnsiConsoleOverSystemConsole.Id,
|
||||
DiagnosticSeverity.Warning);
|
||||
|
||||
[Fact]
|
||||
public async Task SystemConsole_replaced_with_AnsiConsole()
|
||||
{
|
||||
const string Source = @"
|
||||
[Fact]
|
||||
public async Task SystemConsole_replaced_with_AnsiConsole()
|
||||
{
|
||||
const string Source = @"
|
||||
using System;
|
||||
|
||||
class TestClass
|
||||
@ -25,7 +20,7 @@ class TestClass
|
||||
}
|
||||
}";
|
||||
|
||||
const string FixedSource = @"
|
||||
const string FixedSource = @"
|
||||
using System;
|
||||
using Spectre.Console;
|
||||
|
||||
@ -37,15 +32,15 @@ class TestClass
|
||||
}
|
||||
}";
|
||||
|
||||
await SpectreAnalyzerVerifier<UseSpectreInsteadOfSystemConsoleAnalyzer>
|
||||
.VerifyCodeFixAsync(Source, _expectedDiagnostic.WithLocation(8, 9), FixedSource)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
await SpectreAnalyzerVerifier<UseSpectreInsteadOfSystemConsoleAnalyzer>
|
||||
.VerifyCodeFixAsync(Source, _expectedDiagnostic.WithLocation(8, 9), FixedSource)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SystemConsole_replaced_with_imported_AnsiConsole()
|
||||
{
|
||||
const string Source = @"
|
||||
[Fact]
|
||||
public async Task SystemConsole_replaced_with_imported_AnsiConsole()
|
||||
{
|
||||
const string Source = @"
|
||||
using System;
|
||||
|
||||
class TestClass
|
||||
@ -56,7 +51,7 @@ class TestClass
|
||||
}
|
||||
}";
|
||||
|
||||
const string FixedSource = @"
|
||||
const string FixedSource = @"
|
||||
using System;
|
||||
using Spectre.Console;
|
||||
|
||||
@ -68,15 +63,15 @@ class TestClass
|
||||
}
|
||||
}";
|
||||
|
||||
await SpectreAnalyzerVerifier<UseSpectreInsteadOfSystemConsoleAnalyzer>
|
||||
.VerifyCodeFixAsync(Source, _expectedDiagnostic.WithLocation(8, 9), FixedSource)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
await SpectreAnalyzerVerifier<UseSpectreInsteadOfSystemConsoleAnalyzer>
|
||||
.VerifyCodeFixAsync(Source, _expectedDiagnostic.WithLocation(8, 9), FixedSource)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SystemConsole_replaced_with_field_AnsiConsole()
|
||||
{
|
||||
const string Source = @"
|
||||
[Fact]
|
||||
public async Task SystemConsole_replaced_with_field_AnsiConsole()
|
||||
{
|
||||
const string Source = @"
|
||||
using System;
|
||||
using Spectre.Console;
|
||||
|
||||
@ -90,7 +85,7 @@ class TestClass
|
||||
}
|
||||
}";
|
||||
|
||||
const string FixedSource = @"
|
||||
const string FixedSource = @"
|
||||
using System;
|
||||
using Spectre.Console;
|
||||
|
||||
@ -104,15 +99,15 @@ class TestClass
|
||||
}
|
||||
}";
|
||||
|
||||
await SpectreAnalyzerVerifier<UseSpectreInsteadOfSystemConsoleAnalyzer>
|
||||
.VerifyCodeFixAsync(Source, _expectedDiagnostic.WithLocation(11, 9), FixedSource)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
await SpectreAnalyzerVerifier<UseSpectreInsteadOfSystemConsoleAnalyzer>
|
||||
.VerifyCodeFixAsync(Source, _expectedDiagnostic.WithLocation(11, 9), FixedSource)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SystemConsole_replaced_with_static_field_AnsiConsole()
|
||||
{
|
||||
const string Source = @"
|
||||
[Fact]
|
||||
public async Task SystemConsole_replaced_with_static_field_AnsiConsole()
|
||||
{
|
||||
const string Source = @"
|
||||
using System;
|
||||
using Spectre.Console;
|
||||
|
||||
@ -126,7 +121,7 @@ class TestClass
|
||||
}
|
||||
}";
|
||||
|
||||
const string FixedSource = @"
|
||||
const string FixedSource = @"
|
||||
using System;
|
||||
using Spectre.Console;
|
||||
|
||||
@ -140,9 +135,8 @@ class TestClass
|
||||
}
|
||||
}";
|
||||
|
||||
await SpectreAnalyzerVerifier<UseSpectreInsteadOfSystemConsoleAnalyzer>
|
||||
.VerifyCodeFixAsync(Source, _expectedDiagnostic.WithLocation(11, 9), FixedSource)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
await SpectreAnalyzerVerifier<UseSpectreInsteadOfSystemConsoleAnalyzer>
|
||||
.VerifyCodeFixAsync(Source, _expectedDiagnostic.WithLocation(11, 9), FixedSource)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user