mirror of
https://github.com/Tyrrrz/CliFx.git
synced 2025-10-25 15:19:17 +00:00
Use CSharpier
This commit is contained in:
@@ -11,6 +11,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Basic.Reference.Assemblies.Net70" Version="1.4.2" />
|
<PackageReference Include="Basic.Reference.Assemblies.Net70" Version="1.4.2" />
|
||||||
<PackageReference Include="coverlet.collector" Version="6.0.0" PrivateAssets="all" />
|
<PackageReference Include="coverlet.collector" Version="6.0.0" PrivateAssets="all" />
|
||||||
|
<PackageReference Include="CSharpier.MsBuild" Version="0.25.0" PrivateAssets="all" />
|
||||||
<PackageReference Include="GitHubActionsTestLogger" Version="2.3.2" PrivateAssets="all" />
|
<PackageReference Include="GitHubActionsTestLogger" Version="2.3.2" PrivateAssets="all" />
|
||||||
<PackageReference Include="FluentAssertions" Version="6.11.0" />
|
<PackageReference Include="FluentAssertions" Version="6.11.0" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.7.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.7.0" />
|
||||||
|
|||||||
@@ -13,8 +13,7 @@ public class CommandMustBeAnnotatedAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
@@ -30,8 +29,7 @@ public class CommandMustBeAnnotatedAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public abstract class MyCommand : ICommand
|
public abstract class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -48,8 +46,7 @@ public class CommandMustBeAnnotatedAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
public abstract class MyCommand : ICommand
|
public abstract class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
@@ -65,8 +62,7 @@ public class CommandMustBeAnnotatedAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
public class Foo
|
public class Foo
|
||||||
{
|
{
|
||||||
public int Bar { get; init; } = 5;
|
public int Bar { get; init; } = 5;
|
||||||
@@ -76,4 +72,4 @@ public class CommandMustBeAnnotatedAnalyzerSpecs
|
|||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,15 +6,15 @@ namespace CliFx.Analyzers.Tests;
|
|||||||
|
|
||||||
public class CommandMustImplementInterfaceAnalyzerSpecs
|
public class CommandMustImplementInterfaceAnalyzerSpecs
|
||||||
{
|
{
|
||||||
private static DiagnosticAnalyzer Analyzer { get; } = new CommandMustImplementInterfaceAnalyzer();
|
private static DiagnosticAnalyzer Analyzer { get; } =
|
||||||
|
new CommandMustImplementInterfaceAnalyzer();
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Analyzer_reports_an_error_if_a_command_does_not_implement_ICommand_interface()
|
public void Analyzer_reports_an_error_if_a_command_does_not_implement_ICommand_interface()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand
|
public class MyCommand
|
||||||
{
|
{
|
||||||
@@ -31,8 +31,7 @@ public class CommandMustImplementInterfaceAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -49,8 +48,7 @@ public class CommandMustImplementInterfaceAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
public class Foo
|
public class Foo
|
||||||
{
|
{
|
||||||
public int Bar { get; init; } = 5;
|
public int Bar { get; init; } = 5;
|
||||||
@@ -60,4 +58,4 @@ public class CommandMustImplementInterfaceAnalyzerSpecs
|
|||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,11 +12,10 @@ public class GeneralSpecs
|
|||||||
public void All_analyzers_have_unique_diagnostic_IDs()
|
public void All_analyzers_have_unique_diagnostic_IDs()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var analyzers = typeof(AnalyzerBase)
|
var analyzers = typeof(AnalyzerBase).Assembly
|
||||||
.Assembly
|
|
||||||
.GetTypes()
|
.GetTypes()
|
||||||
.Where(t => !t.IsAbstract && t.IsAssignableTo(typeof(DiagnosticAnalyzer)))
|
.Where(t => !t.IsAbstract && t.IsAssignableTo(typeof(DiagnosticAnalyzer)))
|
||||||
.Select(t => (DiagnosticAnalyzer) Activator.CreateInstance(t)!)
|
.Select(t => (DiagnosticAnalyzer)Activator.CreateInstance(t)!)
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
@@ -27,4 +26,4 @@ public class GeneralSpecs
|
|||||||
// Assert
|
// Assert
|
||||||
diagnosticIds.Should().OnlyHaveUniqueItems();
|
diagnosticIds.Should().OnlyHaveUniqueItems();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,8 +13,7 @@ public class OptionMustBeInsideCommandAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
public class MyClass
|
public class MyClass
|
||||||
{
|
{
|
||||||
[CommandOption("foo")]
|
[CommandOption("foo")]
|
||||||
@@ -31,8 +30,7 @@ public class OptionMustBeInsideCommandAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -52,8 +50,7 @@ public class OptionMustBeInsideCommandAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
public abstract class MyCommand
|
public abstract class MyCommand
|
||||||
{
|
{
|
||||||
[CommandOption("foo")]
|
[CommandOption("foo")]
|
||||||
@@ -70,8 +67,7 @@ public class OptionMustBeInsideCommandAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -84,4 +80,4 @@ public class OptionMustBeInsideCommandAnalyzerSpecs
|
|||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,15 +6,15 @@ namespace CliFx.Analyzers.Tests;
|
|||||||
|
|
||||||
public class OptionMustBeRequiredIfPropertyRequiredAnalyzerSpecs
|
public class OptionMustBeRequiredIfPropertyRequiredAnalyzerSpecs
|
||||||
{
|
{
|
||||||
private static DiagnosticAnalyzer Analyzer { get; } = new OptionMustBeRequiredIfPropertyRequiredAnalyzer();
|
private static DiagnosticAnalyzer Analyzer { get; } =
|
||||||
|
new OptionMustBeRequiredIfPropertyRequiredAnalyzer();
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Analyzer_reports_an_error_if_a_non_required_option_is_bound_to_a_required_property()
|
public void Analyzer_reports_an_error_if_a_non_required_option_is_bound_to_a_required_property()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -34,8 +34,7 @@ public class OptionMustBeRequiredIfPropertyRequiredAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -55,8 +54,7 @@ public class OptionMustBeRequiredIfPropertyRequiredAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -76,8 +74,7 @@ public class OptionMustBeRequiredIfPropertyRequiredAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -97,8 +94,7 @@ public class OptionMustBeRequiredIfPropertyRequiredAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -111,4 +107,4 @@ public class OptionMustBeRequiredIfPropertyRequiredAnalyzerSpecs
|
|||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,15 +6,15 @@ namespace CliFx.Analyzers.Tests;
|
|||||||
|
|
||||||
public class OptionMustHaveNameOrShortNameAnalyzerSpecs
|
public class OptionMustHaveNameOrShortNameAnalyzerSpecs
|
||||||
{
|
{
|
||||||
private static DiagnosticAnalyzer Analyzer { get; } = new OptionMustHaveNameOrShortNameAnalyzer();
|
private static DiagnosticAnalyzer Analyzer { get; } =
|
||||||
|
new OptionMustHaveNameOrShortNameAnalyzer();
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Analyzer_reports_an_error_if_an_option_does_not_have_a_name_or_short_name()
|
public void Analyzer_reports_an_error_if_an_option_does_not_have_a_name_or_short_name()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -34,8 +34,7 @@ public class OptionMustHaveNameOrShortNameAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -55,8 +54,7 @@ public class OptionMustHaveNameOrShortNameAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -76,8 +74,7 @@ public class OptionMustHaveNameOrShortNameAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -90,4 +87,4 @@ public class OptionMustHaveNameOrShortNameAnalyzerSpecs
|
|||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,8 +13,7 @@ public class OptionMustHaveUniqueNameAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -37,8 +36,7 @@ public class OptionMustHaveUniqueNameAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -61,8 +59,7 @@ public class OptionMustHaveUniqueNameAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -82,8 +79,7 @@ public class OptionMustHaveUniqueNameAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -96,4 +92,4 @@ public class OptionMustHaveUniqueNameAnalyzerSpecs
|
|||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,15 +6,15 @@ namespace CliFx.Analyzers.Tests;
|
|||||||
|
|
||||||
public class OptionMustHaveUniqueShortNameAnalyzerSpecs
|
public class OptionMustHaveUniqueShortNameAnalyzerSpecs
|
||||||
{
|
{
|
||||||
private static DiagnosticAnalyzer Analyzer { get; } = new OptionMustHaveUniqueShortNameAnalyzer();
|
private static DiagnosticAnalyzer Analyzer { get; } =
|
||||||
|
new OptionMustHaveUniqueShortNameAnalyzer();
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Analyzer_reports_an_error_if_an_option_has_the_same_short_name_as_another_option()
|
public void Analyzer_reports_an_error_if_an_option_has_the_same_short_name_as_another_option()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -37,8 +37,7 @@ public class OptionMustHaveUniqueShortNameAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -61,8 +60,7 @@ public class OptionMustHaveUniqueShortNameAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -85,8 +83,7 @@ public class OptionMustHaveUniqueShortNameAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -106,8 +103,7 @@ public class OptionMustHaveUniqueShortNameAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -120,4 +116,4 @@ public class OptionMustHaveUniqueShortNameAnalyzerSpecs
|
|||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,15 +6,15 @@ namespace CliFx.Analyzers.Tests;
|
|||||||
|
|
||||||
public class OptionMustHaveValidConverterAnalyzerSpecs
|
public class OptionMustHaveValidConverterAnalyzerSpecs
|
||||||
{
|
{
|
||||||
private static DiagnosticAnalyzer Analyzer { get; } = new OptionMustHaveValidConverterAnalyzer();
|
private static DiagnosticAnalyzer Analyzer { get; } =
|
||||||
|
new OptionMustHaveValidConverterAnalyzer();
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Analyzer_reports_an_error_if_an_option_has_a_converter_that_does_not_derive_from_BindingConverter()
|
public void Analyzer_reports_an_error_if_an_option_has_a_converter_that_does_not_derive_from_BindingConverter()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
public class MyConverter
|
public class MyConverter
|
||||||
{
|
{
|
||||||
public string Convert(string? rawValue) => rawValue;
|
public string Convert(string? rawValue) => rawValue;
|
||||||
@@ -39,8 +39,7 @@ public class OptionMustHaveValidConverterAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
public class MyConverter : BindingConverter<int>
|
public class MyConverter : BindingConverter<int>
|
||||||
{
|
{
|
||||||
public override int Convert(string? rawValue) => 42;
|
public override int Convert(string? rawValue) => 42;
|
||||||
@@ -65,8 +64,7 @@ public class OptionMustHaveValidConverterAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
public class MyConverter : BindingConverter<string>
|
public class MyConverter : BindingConverter<string>
|
||||||
{
|
{
|
||||||
public override string Convert(string? rawValue) => rawValue;
|
public override string Convert(string? rawValue) => rawValue;
|
||||||
@@ -91,8 +89,7 @@ public class OptionMustHaveValidConverterAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
public class MyConverter : BindingConverter<int>
|
public class MyConverter : BindingConverter<int>
|
||||||
{
|
{
|
||||||
public override int Convert(string? rawValue) => 42;
|
public override int Convert(string? rawValue) => 42;
|
||||||
@@ -117,8 +114,7 @@ public class OptionMustHaveValidConverterAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
public class MyConverter : BindingConverter<string>
|
public class MyConverter : BindingConverter<string>
|
||||||
{
|
{
|
||||||
public override string Convert(string? rawValue) => rawValue;
|
public override string Convert(string? rawValue) => rawValue;
|
||||||
@@ -143,8 +139,7 @@ public class OptionMustHaveValidConverterAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -164,8 +159,7 @@ public class OptionMustHaveValidConverterAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -178,4 +172,4 @@ public class OptionMustHaveValidConverterAnalyzerSpecs
|
|||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,8 +13,7 @@ public class OptionMustHaveValidNameAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -34,8 +33,7 @@ public class OptionMustHaveValidNameAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -55,8 +53,7 @@ public class OptionMustHaveValidNameAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -76,8 +73,7 @@ public class OptionMustHaveValidNameAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -97,8 +93,7 @@ public class OptionMustHaveValidNameAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -111,4 +106,4 @@ public class OptionMustHaveValidNameAnalyzerSpecs
|
|||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,15 +6,15 @@ namespace CliFx.Analyzers.Tests;
|
|||||||
|
|
||||||
public class OptionMustHaveValidShortNameAnalyzerSpecs
|
public class OptionMustHaveValidShortNameAnalyzerSpecs
|
||||||
{
|
{
|
||||||
private static DiagnosticAnalyzer Analyzer { get; } = new OptionMustHaveValidShortNameAnalyzer();
|
private static DiagnosticAnalyzer Analyzer { get; } =
|
||||||
|
new OptionMustHaveValidShortNameAnalyzer();
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Analyzer_reports_an_error_if_an_option_has_a_short_name_which_is_not_a_letter_character()
|
public void Analyzer_reports_an_error_if_an_option_has_a_short_name_which_is_not_a_letter_character()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -34,8 +34,7 @@ public class OptionMustHaveValidShortNameAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -55,8 +54,7 @@ public class OptionMustHaveValidShortNameAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -76,8 +74,7 @@ public class OptionMustHaveValidShortNameAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -90,4 +87,4 @@ public class OptionMustHaveValidShortNameAnalyzerSpecs
|
|||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,15 +6,15 @@ namespace CliFx.Analyzers.Tests;
|
|||||||
|
|
||||||
public class OptionMustHaveValidValidatorsAnalyzerSpecs
|
public class OptionMustHaveValidValidatorsAnalyzerSpecs
|
||||||
{
|
{
|
||||||
private static DiagnosticAnalyzer Analyzer { get; } = new OptionMustHaveValidValidatorsAnalyzer();
|
private static DiagnosticAnalyzer Analyzer { get; } =
|
||||||
|
new OptionMustHaveValidValidatorsAnalyzer();
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Analyzer_reports_an_error_if_an_option_has_a_validator_that_does_not_derive_from_BindingValidator()
|
public void Analyzer_reports_an_error_if_an_option_has_a_validator_that_does_not_derive_from_BindingValidator()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
public class MyValidator
|
public class MyValidator
|
||||||
{
|
{
|
||||||
public void Validate(string value) {}
|
public void Validate(string value) {}
|
||||||
@@ -39,8 +39,7 @@ public class OptionMustHaveValidValidatorsAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
public class MyValidator : BindingValidator<int>
|
public class MyValidator : BindingValidator<int>
|
||||||
{
|
{
|
||||||
public override BindingValidationError Validate(int value) => Ok();
|
public override BindingValidationError Validate(int value) => Ok();
|
||||||
@@ -65,8 +64,7 @@ public class OptionMustHaveValidValidatorsAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
public class MyValidator : BindingValidator<string>
|
public class MyValidator : BindingValidator<string>
|
||||||
{
|
{
|
||||||
public override BindingValidationError Validate(string value) => Ok();
|
public override BindingValidationError Validate(string value) => Ok();
|
||||||
@@ -91,8 +89,7 @@ public class OptionMustHaveValidValidatorsAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -112,8 +109,7 @@ public class OptionMustHaveValidValidatorsAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -126,4 +122,4 @@ public class OptionMustHaveValidValidatorsAnalyzerSpecs
|
|||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,15 +6,15 @@ namespace CliFx.Analyzers.Tests;
|
|||||||
|
|
||||||
public class ParameterMustBeInsideCommandAnalyzerSpecs
|
public class ParameterMustBeInsideCommandAnalyzerSpecs
|
||||||
{
|
{
|
||||||
private static DiagnosticAnalyzer Analyzer { get; } = new ParameterMustBeInsideCommandAnalyzer();
|
private static DiagnosticAnalyzer Analyzer { get; } =
|
||||||
|
new ParameterMustBeInsideCommandAnalyzer();
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Analyzer_reports_an_error_if_a_parameter_is_inside_a_class_that_is_not_a_command()
|
public void Analyzer_reports_an_error_if_a_parameter_is_inside_a_class_that_is_not_a_command()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
public class MyClass
|
public class MyClass
|
||||||
{
|
{
|
||||||
[CommandParameter(0)]
|
[CommandParameter(0)]
|
||||||
@@ -31,8 +31,7 @@ public class ParameterMustBeInsideCommandAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -52,8 +51,7 @@ public class ParameterMustBeInsideCommandAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
public abstract class MyCommand
|
public abstract class MyCommand
|
||||||
{
|
{
|
||||||
[CommandParameter(0)]
|
[CommandParameter(0)]
|
||||||
@@ -70,8 +68,7 @@ public class ParameterMustBeInsideCommandAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -84,4 +81,4 @@ public class ParameterMustBeInsideCommandAnalyzerSpecs
|
|||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,15 +6,15 @@ namespace CliFx.Analyzers.Tests;
|
|||||||
|
|
||||||
public class ParameterMustBeLastIfNonRequiredAnalyzerSpecs
|
public class ParameterMustBeLastIfNonRequiredAnalyzerSpecs
|
||||||
{
|
{
|
||||||
private static DiagnosticAnalyzer Analyzer { get; } = new ParameterMustBeLastIfNonRequiredAnalyzer();
|
private static DiagnosticAnalyzer Analyzer { get; } =
|
||||||
|
new ParameterMustBeLastIfNonRequiredAnalyzer();
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Analyzer_reports_an_error_if_a_non_required_parameter_is_not_the_last_in_order()
|
public void Analyzer_reports_an_error_if_a_non_required_parameter_is_not_the_last_in_order()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -37,8 +37,7 @@ public class ParameterMustBeLastIfNonRequiredAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -61,8 +60,7 @@ public class ParameterMustBeLastIfNonRequiredAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -85,8 +83,7 @@ public class ParameterMustBeLastIfNonRequiredAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -99,4 +96,4 @@ public class ParameterMustBeLastIfNonRequiredAnalyzerSpecs
|
|||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,15 +6,15 @@ namespace CliFx.Analyzers.Tests;
|
|||||||
|
|
||||||
public class ParameterMustBeLastIfNonScalarAnalyzerSpecs
|
public class ParameterMustBeLastIfNonScalarAnalyzerSpecs
|
||||||
{
|
{
|
||||||
private static DiagnosticAnalyzer Analyzer { get; } = new ParameterMustBeLastIfNonScalarAnalyzer();
|
private static DiagnosticAnalyzer Analyzer { get; } =
|
||||||
|
new ParameterMustBeLastIfNonScalarAnalyzer();
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Analyzer_reports_an_error_if_a_non_scalar_parameter_is_not_the_last_in_order()
|
public void Analyzer_reports_an_error_if_a_non_scalar_parameter_is_not_the_last_in_order()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -37,8 +37,7 @@ public class ParameterMustBeLastIfNonScalarAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -61,8 +60,7 @@ public class ParameterMustBeLastIfNonScalarAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -85,8 +83,7 @@ public class ParameterMustBeLastIfNonScalarAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -99,4 +96,4 @@ public class ParameterMustBeLastIfNonScalarAnalyzerSpecs
|
|||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,15 +6,15 @@ namespace CliFx.Analyzers.Tests;
|
|||||||
|
|
||||||
public class ParameterMustBeRequiredIfPropertyRequiredAnalyzerSpecs
|
public class ParameterMustBeRequiredIfPropertyRequiredAnalyzerSpecs
|
||||||
{
|
{
|
||||||
private static DiagnosticAnalyzer Analyzer { get; } = new ParameterMustBeRequiredIfPropertyRequiredAnalyzer();
|
private static DiagnosticAnalyzer Analyzer { get; } =
|
||||||
|
new ParameterMustBeRequiredIfPropertyRequiredAnalyzer();
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Analyzer_reports_an_error_if_a_non_required_parameter_is_bound_to_a_required_property()
|
public void Analyzer_reports_an_error_if_a_non_required_parameter_is_bound_to_a_required_property()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -34,8 +34,7 @@ public class ParameterMustBeRequiredIfPropertyRequiredAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -55,8 +54,7 @@ public class ParameterMustBeRequiredIfPropertyRequiredAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -76,8 +74,7 @@ public class ParameterMustBeRequiredIfPropertyRequiredAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -97,8 +94,7 @@ public class ParameterMustBeRequiredIfPropertyRequiredAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -111,4 +107,4 @@ public class ParameterMustBeRequiredIfPropertyRequiredAnalyzerSpecs
|
|||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,15 +6,15 @@ namespace CliFx.Analyzers.Tests;
|
|||||||
|
|
||||||
public class ParameterMustBeSingleIfNonRequiredAnalyzerSpecs
|
public class ParameterMustBeSingleIfNonRequiredAnalyzerSpecs
|
||||||
{
|
{
|
||||||
private static DiagnosticAnalyzer Analyzer { get; } = new ParameterMustBeSingleIfNonRequiredAnalyzer();
|
private static DiagnosticAnalyzer Analyzer { get; } =
|
||||||
|
new ParameterMustBeSingleIfNonRequiredAnalyzer();
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Analyzer_reports_an_error_if_more_than_one_non_required_parameters_are_defined()
|
public void Analyzer_reports_an_error_if_more_than_one_non_required_parameters_are_defined()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -37,8 +37,7 @@ public class ParameterMustBeSingleIfNonRequiredAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -61,8 +60,7 @@ public class ParameterMustBeSingleIfNonRequiredAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -85,8 +83,7 @@ public class ParameterMustBeSingleIfNonRequiredAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -99,4 +96,4 @@ public class ParameterMustBeSingleIfNonRequiredAnalyzerSpecs
|
|||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,15 +6,15 @@ namespace CliFx.Analyzers.Tests;
|
|||||||
|
|
||||||
public class ParameterMustBeSingleIfNonScalarAnalyzerSpecs
|
public class ParameterMustBeSingleIfNonScalarAnalyzerSpecs
|
||||||
{
|
{
|
||||||
private static DiagnosticAnalyzer Analyzer { get; } = new ParameterMustBeSingleIfNonScalarAnalyzer();
|
private static DiagnosticAnalyzer Analyzer { get; } =
|
||||||
|
new ParameterMustBeSingleIfNonScalarAnalyzer();
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Analyzer_reports_an_error_if_more_than_one_non_scalar_parameters_are_defined()
|
public void Analyzer_reports_an_error_if_more_than_one_non_scalar_parameters_are_defined()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -37,8 +37,7 @@ public class ParameterMustBeSingleIfNonScalarAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -61,8 +60,7 @@ public class ParameterMustBeSingleIfNonScalarAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -85,8 +83,7 @@ public class ParameterMustBeSingleIfNonScalarAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -99,4 +96,4 @@ public class ParameterMustBeSingleIfNonScalarAnalyzerSpecs
|
|||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,8 +13,7 @@ public class ParameterMustHaveUniqueNameAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -37,8 +36,7 @@ public class ParameterMustHaveUniqueNameAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -61,8 +59,7 @@ public class ParameterMustHaveUniqueNameAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -75,4 +72,4 @@ public class ParameterMustHaveUniqueNameAnalyzerSpecs
|
|||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,15 +6,15 @@ namespace CliFx.Analyzers.Tests;
|
|||||||
|
|
||||||
public class ParameterMustHaveUniqueOrderAnalyzerSpecs
|
public class ParameterMustHaveUniqueOrderAnalyzerSpecs
|
||||||
{
|
{
|
||||||
private static DiagnosticAnalyzer Analyzer { get; } = new ParameterMustHaveUniqueOrderAnalyzer();
|
private static DiagnosticAnalyzer Analyzer { get; } =
|
||||||
|
new ParameterMustHaveUniqueOrderAnalyzer();
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Analyzer_reports_an_error_if_a_parameter_has_the_same_order_as_another_parameter()
|
public void Analyzer_reports_an_error_if_a_parameter_has_the_same_order_as_another_parameter()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -37,8 +37,7 @@ public class ParameterMustHaveUniqueOrderAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -61,8 +60,7 @@ public class ParameterMustHaveUniqueOrderAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -75,4 +73,4 @@ public class ParameterMustHaveUniqueOrderAnalyzerSpecs
|
|||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,15 +6,15 @@ namespace CliFx.Analyzers.Tests;
|
|||||||
|
|
||||||
public class ParameterMustHaveValidConverterAnalyzerSpecs
|
public class ParameterMustHaveValidConverterAnalyzerSpecs
|
||||||
{
|
{
|
||||||
private static DiagnosticAnalyzer Analyzer { get; } = new ParameterMustHaveValidConverterAnalyzer();
|
private static DiagnosticAnalyzer Analyzer { get; } =
|
||||||
|
new ParameterMustHaveValidConverterAnalyzer();
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Analyzer_reports_an_error_if_a_parameter_has_a_converter_that_does_not_derive_from_BindingConverter()
|
public void Analyzer_reports_an_error_if_a_parameter_has_a_converter_that_does_not_derive_from_BindingConverter()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
public class MyConverter
|
public class MyConverter
|
||||||
{
|
{
|
||||||
public string Convert(string? rawValue) => rawValue;
|
public string Convert(string? rawValue) => rawValue;
|
||||||
@@ -39,8 +39,7 @@ public class ParameterMustHaveValidConverterAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
public class MyConverter : BindingConverter<int>
|
public class MyConverter : BindingConverter<int>
|
||||||
{
|
{
|
||||||
public override int Convert(string? rawValue) => 42;
|
public override int Convert(string? rawValue) => 42;
|
||||||
@@ -56,7 +55,6 @@ public class ParameterMustHaveValidConverterAnalyzerSpecs
|
|||||||
}
|
}
|
||||||
""";
|
""";
|
||||||
|
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().ProduceDiagnostics(code);
|
Analyzer.Should().ProduceDiagnostics(code);
|
||||||
}
|
}
|
||||||
@@ -66,8 +64,7 @@ public class ParameterMustHaveValidConverterAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
public class MyConverter : BindingConverter<string>
|
public class MyConverter : BindingConverter<string>
|
||||||
{
|
{
|
||||||
public override string Convert(string? rawValue) => rawValue;
|
public override string Convert(string? rawValue) => rawValue;
|
||||||
@@ -92,8 +89,7 @@ public class ParameterMustHaveValidConverterAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
public class MyConverter : BindingConverter<int>
|
public class MyConverter : BindingConverter<int>
|
||||||
{
|
{
|
||||||
public override int Convert(string? rawValue) => 42;
|
public override int Convert(string? rawValue) => 42;
|
||||||
@@ -118,8 +114,7 @@ public class ParameterMustHaveValidConverterAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
public class MyConverter : BindingConverter<string>
|
public class MyConverter : BindingConverter<string>
|
||||||
{
|
{
|
||||||
public override string Convert(string? rawValue) => rawValue;
|
public override string Convert(string? rawValue) => rawValue;
|
||||||
@@ -144,8 +139,7 @@ public class ParameterMustHaveValidConverterAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -165,8 +159,7 @@ public class ParameterMustHaveValidConverterAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -179,4 +172,4 @@ public class ParameterMustHaveValidConverterAnalyzerSpecs
|
|||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,15 +6,15 @@ namespace CliFx.Analyzers.Tests;
|
|||||||
|
|
||||||
public class ParameterMustHaveValidValidatorsAnalyzerSpecs
|
public class ParameterMustHaveValidValidatorsAnalyzerSpecs
|
||||||
{
|
{
|
||||||
private static DiagnosticAnalyzer Analyzer { get; } = new ParameterMustHaveValidValidatorsAnalyzer();
|
private static DiagnosticAnalyzer Analyzer { get; } =
|
||||||
|
new ParameterMustHaveValidValidatorsAnalyzer();
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Analyzer_reports_an_error_a_parameter_has_a_validator_that_does_not_derive_from_BindingValidator()
|
public void Analyzer_reports_an_error_a_parameter_has_a_validator_that_does_not_derive_from_BindingValidator()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
public class MyValidator
|
public class MyValidator
|
||||||
{
|
{
|
||||||
public void Validate(string value) {}
|
public void Validate(string value) {}
|
||||||
@@ -39,8 +39,7 @@ public class ParameterMustHaveValidValidatorsAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
public class MyValidator : BindingValidator<int>
|
public class MyValidator : BindingValidator<int>
|
||||||
{
|
{
|
||||||
public override BindingValidationError Validate(int value) => Ok();
|
public override BindingValidationError Validate(int value) => Ok();
|
||||||
@@ -65,8 +64,7 @@ public class ParameterMustHaveValidValidatorsAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
public class MyValidator : BindingValidator<string>
|
public class MyValidator : BindingValidator<string>
|
||||||
{
|
{
|
||||||
public override BindingValidationError Validate(string value) => Ok();
|
public override BindingValidationError Validate(string value) => Ok();
|
||||||
@@ -91,8 +89,7 @@ public class ParameterMustHaveValidValidatorsAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -112,8 +109,7 @@ public class ParameterMustHaveValidValidatorsAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -126,4 +122,4 @@ public class ParameterMustHaveValidValidatorsAnalyzerSpecs
|
|||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,15 +6,15 @@ namespace CliFx.Analyzers.Tests;
|
|||||||
|
|
||||||
public class SystemConsoleShouldBeAvoidedAnalyzerSpecs
|
public class SystemConsoleShouldBeAvoidedAnalyzerSpecs
|
||||||
{
|
{
|
||||||
private static DiagnosticAnalyzer Analyzer { get; } = new SystemConsoleShouldBeAvoidedAnalyzer();
|
private static DiagnosticAnalyzer Analyzer { get; } =
|
||||||
|
new SystemConsoleShouldBeAvoidedAnalyzer();
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Analyzer_reports_an_error_if_a_command_calls_a_method_on_SystemConsole()
|
public void Analyzer_reports_an_error_if_a_command_calls_a_method_on_SystemConsole()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -35,8 +35,7 @@ public class SystemConsoleShouldBeAvoidedAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -57,8 +56,7 @@ public class SystemConsoleShouldBeAvoidedAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -79,8 +77,7 @@ public class SystemConsoleShouldBeAvoidedAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -101,8 +98,7 @@ public class SystemConsoleShouldBeAvoidedAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -121,8 +117,7 @@ public class SystemConsoleShouldBeAvoidedAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// lang=csharp
|
// lang=csharp
|
||||||
const string code =
|
const string code = """
|
||||||
"""
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -136,4 +131,4 @@ public class SystemConsoleShouldBeAvoidedAnalyzerSpecs
|
|||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,9 +18,7 @@ internal class AnalyzerAssertions : ReferenceTypeAssertions<DiagnosticAnalyzer,
|
|||||||
protected override string Identifier { get; } = "analyzer";
|
protected override string Identifier { get; } = "analyzer";
|
||||||
|
|
||||||
public AnalyzerAssertions(DiagnosticAnalyzer analyzer)
|
public AnalyzerAssertions(DiagnosticAnalyzer analyzer)
|
||||||
: base(analyzer)
|
: base(analyzer) { }
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
private Compilation Compile(string sourceCode)
|
private Compilation Compile(string sourceCode)
|
||||||
{
|
{
|
||||||
@@ -33,8 +31,7 @@ internal class AnalyzerAssertions : ReferenceTypeAssertions<DiagnosticAnalyzer,
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Get default CliFx namespaces
|
// Get default CliFx namespaces
|
||||||
var defaultCliFxNamespaces = typeof(ICommand)
|
var defaultCliFxNamespaces = typeof(ICommand).Assembly
|
||||||
.Assembly
|
|
||||||
.GetTypes()
|
.GetTypes()
|
||||||
.Where(t => t.IsPublic)
|
.Where(t => t.IsPublic)
|
||||||
.Select(t => t.Namespace)
|
.Select(t => t.Namespace)
|
||||||
@@ -43,10 +40,10 @@ internal class AnalyzerAssertions : ReferenceTypeAssertions<DiagnosticAnalyzer,
|
|||||||
|
|
||||||
// Append default imports to the source code
|
// Append default imports to the source code
|
||||||
var sourceCodeWithUsings =
|
var sourceCodeWithUsings =
|
||||||
string.Join(Environment.NewLine, defaultSystemNamespaces.Select(n => $"using {n};")) +
|
string.Join(Environment.NewLine, defaultSystemNamespaces.Select(n => $"using {n};"))
|
||||||
string.Join(Environment.NewLine, defaultCliFxNamespaces.Select(n => $"using {n};")) +
|
+ string.Join(Environment.NewLine, defaultCliFxNamespaces.Select(n => $"using {n};"))
|
||||||
Environment.NewLine +
|
+ Environment.NewLine
|
||||||
sourceCode;
|
+ sourceCode;
|
||||||
|
|
||||||
// Parse the source code
|
// Parse the source code
|
||||||
var ast = SyntaxFactory.ParseSyntaxTree(
|
var ast = SyntaxFactory.ParseSyntaxTree(
|
||||||
@@ -58,8 +55,9 @@ internal class AnalyzerAssertions : ReferenceTypeAssertions<DiagnosticAnalyzer,
|
|||||||
var compilation = CSharpCompilation.Create(
|
var compilation = CSharpCompilation.Create(
|
||||||
"CliFxTests_DynamicAssembly_" + Guid.NewGuid(),
|
"CliFxTests_DynamicAssembly_" + Guid.NewGuid(),
|
||||||
new[] { ast },
|
new[] { ast },
|
||||||
Net70.References.All
|
Net70.References.All.Append(
|
||||||
.Append(MetadataReference.CreateFromFile(typeof(ICommand).Assembly.Location)),
|
MetadataReference.CreateFromFile(typeof(ICommand).Assembly.Location)
|
||||||
|
),
|
||||||
// DLL to avoid having to define the Main() method
|
// DLL to avoid having to define the Main() method
|
||||||
new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)
|
new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)
|
||||||
);
|
);
|
||||||
@@ -103,44 +101,46 @@ internal class AnalyzerAssertions : ReferenceTypeAssertions<DiagnosticAnalyzer,
|
|||||||
var producedDiagnosticIds = producedDiagnostics.Select(d => d.Id).Distinct().ToArray();
|
var producedDiagnosticIds = producedDiagnostics.Select(d => d.Id).Distinct().ToArray();
|
||||||
|
|
||||||
var isSuccessfulAssertion =
|
var isSuccessfulAssertion =
|
||||||
expectedDiagnosticIds.Intersect(producedDiagnosticIds).Count() ==
|
expectedDiagnosticIds.Intersect(producedDiagnosticIds).Count()
|
||||||
expectedDiagnosticIds.Length;
|
== expectedDiagnosticIds.Length;
|
||||||
|
|
||||||
Execute.Assertion.ForCondition(isSuccessfulAssertion).FailWith(() =>
|
Execute.Assertion
|
||||||
{
|
.ForCondition(isSuccessfulAssertion)
|
||||||
var buffer = new StringBuilder();
|
.FailWith(() =>
|
||||||
|
|
||||||
buffer.AppendLine("Expected and produced diagnostics do not match.");
|
|
||||||
buffer.AppendLine();
|
|
||||||
|
|
||||||
buffer.AppendLine("Expected diagnostics:");
|
|
||||||
|
|
||||||
foreach (var expectedDiagnostic in expectedDiagnostics)
|
|
||||||
{
|
{
|
||||||
buffer.Append(" - ");
|
var buffer = new StringBuilder();
|
||||||
buffer.Append(expectedDiagnostic.Id);
|
|
||||||
|
buffer.AppendLine("Expected and produced diagnostics do not match.");
|
||||||
buffer.AppendLine();
|
buffer.AppendLine();
|
||||||
}
|
|
||||||
|
|
||||||
buffer.AppendLine();
|
buffer.AppendLine("Expected diagnostics:");
|
||||||
|
|
||||||
buffer.AppendLine("Produced diagnostics:");
|
foreach (var expectedDiagnostic in expectedDiagnostics)
|
||||||
|
|
||||||
if (producedDiagnostics.Any())
|
|
||||||
{
|
|
||||||
foreach (var producedDiagnostic in producedDiagnostics)
|
|
||||||
{
|
{
|
||||||
buffer.Append(" - ");
|
buffer.Append(" - ");
|
||||||
buffer.Append(producedDiagnostic);
|
buffer.Append(expectedDiagnostic.Id);
|
||||||
|
buffer.AppendLine();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
buffer.AppendLine(" < none >");
|
|
||||||
}
|
|
||||||
|
|
||||||
return new FailReason(buffer.ToString());
|
buffer.AppendLine();
|
||||||
});
|
|
||||||
|
buffer.AppendLine("Produced diagnostics:");
|
||||||
|
|
||||||
|
if (producedDiagnostics.Any())
|
||||||
|
{
|
||||||
|
foreach (var producedDiagnostic in producedDiagnostics)
|
||||||
|
{
|
||||||
|
buffer.Append(" - ");
|
||||||
|
buffer.Append(producedDiagnostic);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
buffer.AppendLine(" < none >");
|
||||||
|
}
|
||||||
|
|
||||||
|
return new FailReason(buffer.ToString());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void NotProduceDiagnostics(string sourceCode)
|
public void NotProduceDiagnostics(string sourceCode)
|
||||||
@@ -148,27 +148,29 @@ internal class AnalyzerAssertions : ReferenceTypeAssertions<DiagnosticAnalyzer,
|
|||||||
var producedDiagnostics = GetProducedDiagnostics(sourceCode);
|
var producedDiagnostics = GetProducedDiagnostics(sourceCode);
|
||||||
var isSuccessfulAssertion = !producedDiagnostics.Any();
|
var isSuccessfulAssertion = !producedDiagnostics.Any();
|
||||||
|
|
||||||
Execute.Assertion.ForCondition(isSuccessfulAssertion).FailWith(() =>
|
Execute.Assertion
|
||||||
{
|
.ForCondition(isSuccessfulAssertion)
|
||||||
var buffer = new StringBuilder();
|
.FailWith(() =>
|
||||||
|
|
||||||
buffer.AppendLine("Expected no produced diagnostics.");
|
|
||||||
buffer.AppendLine();
|
|
||||||
|
|
||||||
buffer.AppendLine("Produced diagnostics:");
|
|
||||||
|
|
||||||
foreach (var producedDiagnostic in producedDiagnostics)
|
|
||||||
{
|
{
|
||||||
buffer.Append(" - ");
|
var buffer = new StringBuilder();
|
||||||
buffer.Append(producedDiagnostic);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new FailReason(buffer.ToString());
|
buffer.AppendLine("Expected no produced diagnostics.");
|
||||||
});
|
buffer.AppendLine();
|
||||||
|
|
||||||
|
buffer.AppendLine("Produced diagnostics:");
|
||||||
|
|
||||||
|
foreach (var producedDiagnostic in producedDiagnostics)
|
||||||
|
{
|
||||||
|
buffer.Append(" - ");
|
||||||
|
buffer.Append(producedDiagnostic);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new FailReason(buffer.ToString());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static class AnalyzerAssertionsExtensions
|
internal static class AnalyzerAssertionsExtensions
|
||||||
{
|
{
|
||||||
public static AnalyzerAssertions Should(this DiagnosticAnalyzer analyzer) => new(analyzer);
|
public static AnalyzerAssertions Should(this DiagnosticAnalyzer analyzer) => new(analyzer);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,8 @@ public abstract class AnalyzerBase : DiagnosticAnalyzer
|
|||||||
protected AnalyzerBase(
|
protected AnalyzerBase(
|
||||||
string diagnosticTitle,
|
string diagnosticTitle,
|
||||||
string diagnosticMessage,
|
string diagnosticMessage,
|
||||||
DiagnosticSeverity diagnosticSeverity = DiagnosticSeverity.Error)
|
DiagnosticSeverity diagnosticSeverity = DiagnosticSeverity.Error
|
||||||
|
)
|
||||||
{
|
{
|
||||||
SupportedDiagnostic = new DiagnosticDescriptor(
|
SupportedDiagnostic = new DiagnosticDescriptor(
|
||||||
"CliFx_" + GetType().Name.TrimEnd("Analyzer"),
|
"CliFx_" + GetType().Name.TrimEnd("Analyzer"),
|
||||||
@@ -36,4 +37,4 @@ public abstract class AnalyzerBase : DiagnosticAnalyzer
|
|||||||
context.EnableConcurrentExecution();
|
context.EnableConcurrentExecution();
|
||||||
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
|
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="CSharpier.MsBuild" Version="0.25.0" PrivateAssets="all" />
|
||||||
<!-- Make sure to target the lowest possible version of the compiler for wider support -->
|
<!-- Make sure to target the lowest possible version of the compiler for wider support -->
|
||||||
<PackageReference Include="Microsoft.CodeAnalysis" Version="3.0.0" PrivateAssets="all" />
|
<PackageReference Include="Microsoft.CodeAnalysis" Version="3.0.0" PrivateAssets="all" />
|
||||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.0.0" PrivateAssets="all" />
|
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.0.0" PrivateAssets="all" />
|
||||||
|
|||||||
@@ -13,14 +13,14 @@ public class CommandMustBeAnnotatedAnalyzer : AnalyzerBase
|
|||||||
public CommandMustBeAnnotatedAnalyzer()
|
public CommandMustBeAnnotatedAnalyzer()
|
||||||
: base(
|
: base(
|
||||||
$"Commands must be annotated with `{SymbolNames.CliFxCommandAttribute}`",
|
$"Commands must be annotated with `{SymbolNames.CliFxCommandAttribute}`",
|
||||||
$"This type must be annotated with `{SymbolNames.CliFxCommandAttribute}` in order to be a valid command.")
|
$"This type must be annotated with `{SymbolNames.CliFxCommandAttribute}` in order to be a valid command."
|
||||||
{
|
) { }
|
||||||
}
|
|
||||||
|
|
||||||
private void Analyze(
|
private void Analyze(
|
||||||
SyntaxNodeAnalysisContext context,
|
SyntaxNodeAnalysisContext context,
|
||||||
ClassDeclarationSyntax classDeclaration,
|
ClassDeclarationSyntax classDeclaration,
|
||||||
ITypeSymbol type)
|
ITypeSymbol type
|
||||||
|
)
|
||||||
{
|
{
|
||||||
// Ignore abstract classes, because they may be used to define
|
// Ignore abstract classes, because they may be used to define
|
||||||
// base implementations for commands, in which case the command
|
// base implementations for commands, in which case the command
|
||||||
@@ -28,12 +28,11 @@ public class CommandMustBeAnnotatedAnalyzer : AnalyzerBase
|
|||||||
if (type.IsAbstract)
|
if (type.IsAbstract)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var implementsCommandInterface = type
|
var implementsCommandInterface = type.AllInterfaces.Any(
|
||||||
.AllInterfaces
|
i => i.DisplayNameMatches(SymbolNames.CliFxCommandInterface)
|
||||||
.Any(i => i.DisplayNameMatches(SymbolNames.CliFxCommandInterface));
|
);
|
||||||
|
|
||||||
var hasCommandAttribute = type
|
var hasCommandAttribute = type.GetAttributes()
|
||||||
.GetAttributes()
|
|
||||||
.Select(a => a.AttributeClass)
|
.Select(a => a.AttributeClass)
|
||||||
.Any(c => c.DisplayNameMatches(SymbolNames.CliFxCommandAttribute));
|
.Any(c => c.DisplayNameMatches(SymbolNames.CliFxCommandAttribute));
|
||||||
|
|
||||||
@@ -41,9 +40,7 @@ public class CommandMustBeAnnotatedAnalyzer : AnalyzerBase
|
|||||||
// then it's very likely a user error.
|
// then it's very likely a user error.
|
||||||
if (implementsCommandInterface && !hasCommandAttribute)
|
if (implementsCommandInterface && !hasCommandAttribute)
|
||||||
{
|
{
|
||||||
context.ReportDiagnostic(
|
context.ReportDiagnostic(CreateDiagnostic(classDeclaration.Identifier.GetLocation()));
|
||||||
CreateDiagnostic(classDeclaration.Identifier.GetLocation())
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,4 +49,4 @@ public class CommandMustBeAnnotatedAnalyzer : AnalyzerBase
|
|||||||
base.Initialize(context);
|
base.Initialize(context);
|
||||||
context.HandleClassDeclaration(Analyze);
|
context.HandleClassDeclaration(Analyze);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,31 +13,28 @@ public class CommandMustImplementInterfaceAnalyzer : AnalyzerBase
|
|||||||
public CommandMustImplementInterfaceAnalyzer()
|
public CommandMustImplementInterfaceAnalyzer()
|
||||||
: base(
|
: base(
|
||||||
$"Commands must implement `{SymbolNames.CliFxCommandInterface}` interface",
|
$"Commands must implement `{SymbolNames.CliFxCommandInterface}` interface",
|
||||||
$"This type must implement `{SymbolNames.CliFxCommandInterface}` interface in order to be a valid command.")
|
$"This type must implement `{SymbolNames.CliFxCommandInterface}` interface in order to be a valid command."
|
||||||
{
|
) { }
|
||||||
}
|
|
||||||
|
|
||||||
private void Analyze(
|
private void Analyze(
|
||||||
SyntaxNodeAnalysisContext context,
|
SyntaxNodeAnalysisContext context,
|
||||||
ClassDeclarationSyntax classDeclaration,
|
ClassDeclarationSyntax classDeclaration,
|
||||||
ITypeSymbol type)
|
ITypeSymbol type
|
||||||
|
)
|
||||||
{
|
{
|
||||||
var hasCommandAttribute = type
|
var hasCommandAttribute = type.GetAttributes()
|
||||||
.GetAttributes()
|
|
||||||
.Select(a => a.AttributeClass)
|
.Select(a => a.AttributeClass)
|
||||||
.Any(c => c.DisplayNameMatches(SymbolNames.CliFxCommandAttribute));
|
.Any(c => c.DisplayNameMatches(SymbolNames.CliFxCommandAttribute));
|
||||||
|
|
||||||
var implementsCommandInterface = type
|
var implementsCommandInterface = type.AllInterfaces.Any(
|
||||||
.AllInterfaces
|
i => i.DisplayNameMatches(SymbolNames.CliFxCommandInterface)
|
||||||
.Any(i => i.DisplayNameMatches(SymbolNames.CliFxCommandInterface));
|
);
|
||||||
|
|
||||||
// If the attribute is present, but the interface is not implemented,
|
// If the attribute is present, but the interface is not implemented,
|
||||||
// it's very likely a user error.
|
// it's very likely a user error.
|
||||||
if (hasCommandAttribute && !implementsCommandInterface)
|
if (hasCommandAttribute && !implementsCommandInterface)
|
||||||
{
|
{
|
||||||
context.ReportDiagnostic(
|
context.ReportDiagnostic(CreateDiagnostic(classDeclaration.Identifier.GetLocation()));
|
||||||
CreateDiagnostic(classDeclaration.Identifier.GetLocation())
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,4 +43,4 @@ public class CommandMustImplementInterfaceAnalyzer : AnalyzerBase
|
|||||||
base.Initialize(context);
|
base.Initialize(context);
|
||||||
context.HandleClassDeclaration(Analyze);
|
context.HandleClassDeclaration(Analyze);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,8 @@ internal partial class CommandOptionSymbol : ICommandMemberSymbol
|
|||||||
char? shortName,
|
char? shortName,
|
||||||
bool? isRequired,
|
bool? isRequired,
|
||||||
ITypeSymbol? converterType,
|
ITypeSymbol? converterType,
|
||||||
IReadOnlyList<ITypeSymbol> validatorTypes)
|
IReadOnlyList<ITypeSymbol> validatorTypes
|
||||||
|
)
|
||||||
{
|
{
|
||||||
Property = property;
|
Property = property;
|
||||||
Name = name;
|
Name = name;
|
||||||
@@ -38,9 +39,14 @@ internal partial class CommandOptionSymbol : ICommandMemberSymbol
|
|||||||
|
|
||||||
internal partial class CommandOptionSymbol
|
internal partial class CommandOptionSymbol
|
||||||
{
|
{
|
||||||
private static AttributeData? TryGetOptionAttribute(IPropertySymbol property) => property
|
private static AttributeData? TryGetOptionAttribute(IPropertySymbol property) =>
|
||||||
.GetAttributes()
|
property
|
||||||
.FirstOrDefault(a => a.AttributeClass?.DisplayNameMatches(SymbolNames.CliFxCommandOptionAttribute) == true);
|
.GetAttributes()
|
||||||
|
.FirstOrDefault(
|
||||||
|
a =>
|
||||||
|
a.AttributeClass?.DisplayNameMatches(SymbolNames.CliFxCommandOptionAttribute)
|
||||||
|
== true
|
||||||
|
);
|
||||||
|
|
||||||
public static CommandOptionSymbol? TryResolve(IPropertySymbol property)
|
public static CommandOptionSymbol? TryResolve(IPropertySymbol property)
|
||||||
{
|
{
|
||||||
@@ -48,42 +54,47 @@ internal partial class CommandOptionSymbol
|
|||||||
if (attribute is null)
|
if (attribute is null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
var name = attribute
|
var name =
|
||||||
.ConstructorArguments
|
attribute.ConstructorArguments
|
||||||
.Where(a => a.Type?.SpecialType == SpecialType.System_String)
|
.Where(a => a.Type?.SpecialType == SpecialType.System_String)
|
||||||
.Select(a => a.Value)
|
.Select(a => a.Value)
|
||||||
.FirstOrDefault() as string;
|
.FirstOrDefault() as string;
|
||||||
|
|
||||||
var shortName = attribute
|
var shortName =
|
||||||
.ConstructorArguments
|
attribute.ConstructorArguments
|
||||||
.Where(a => a.Type?.SpecialType == SpecialType.System_Char)
|
.Where(a => a.Type?.SpecialType == SpecialType.System_Char)
|
||||||
.Select(a => a.Value)
|
.Select(a => a.Value)
|
||||||
.FirstOrDefault() as char?;
|
.FirstOrDefault() as char?;
|
||||||
|
|
||||||
var isRequired = attribute
|
var isRequired =
|
||||||
.NamedArguments
|
attribute.NamedArguments
|
||||||
.Where(a => a.Key == "IsRequired")
|
.Where(a => a.Key == "IsRequired")
|
||||||
.Select(a => a.Value.Value)
|
.Select(a => a.Value.Value)
|
||||||
.FirstOrDefault() as bool?;
|
.FirstOrDefault() as bool?;
|
||||||
|
|
||||||
var converter = attribute
|
var converter = attribute.NamedArguments
|
||||||
.NamedArguments
|
|
||||||
.Where(a => a.Key == "Converter")
|
.Where(a => a.Key == "Converter")
|
||||||
.Select(a => a.Value.Value)
|
.Select(a => a.Value.Value)
|
||||||
.Cast<ITypeSymbol?>()
|
.Cast<ITypeSymbol?>()
|
||||||
.FirstOrDefault();
|
.FirstOrDefault();
|
||||||
|
|
||||||
var validators = attribute
|
var validators = attribute.NamedArguments
|
||||||
.NamedArguments
|
|
||||||
.Where(a => a.Key == "Validators")
|
.Where(a => a.Key == "Validators")
|
||||||
.SelectMany(a => a.Value.Values)
|
.SelectMany(a => a.Value.Values)
|
||||||
.Select(c => c.Value)
|
.Select(c => c.Value)
|
||||||
.Cast<ITypeSymbol>()
|
.Cast<ITypeSymbol>()
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
return new CommandOptionSymbol(property, name, shortName, isRequired, converter, validators);
|
return new CommandOptionSymbol(
|
||||||
|
property,
|
||||||
|
name,
|
||||||
|
shortName,
|
||||||
|
isRequired,
|
||||||
|
converter,
|
||||||
|
validators
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool IsOptionProperty(IPropertySymbol property) =>
|
public static bool IsOptionProperty(IPropertySymbol property) =>
|
||||||
TryGetOptionAttribute(property) is not null;
|
TryGetOptionAttribute(property) is not null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,8 @@ internal partial class CommandParameterSymbol : ICommandMemberSymbol
|
|||||||
string? name,
|
string? name,
|
||||||
bool? isRequired,
|
bool? isRequired,
|
||||||
ITypeSymbol? converterType,
|
ITypeSymbol? converterType,
|
||||||
IReadOnlyList<ITypeSymbol> validatorTypes)
|
IReadOnlyList<ITypeSymbol> validatorTypes
|
||||||
|
)
|
||||||
{
|
{
|
||||||
Property = property;
|
Property = property;
|
||||||
Order = order;
|
Order = order;
|
||||||
@@ -38,9 +39,14 @@ internal partial class CommandParameterSymbol : ICommandMemberSymbol
|
|||||||
|
|
||||||
internal partial class CommandParameterSymbol
|
internal partial class CommandParameterSymbol
|
||||||
{
|
{
|
||||||
private static AttributeData? TryGetParameterAttribute(IPropertySymbol property) => property
|
private static AttributeData? TryGetParameterAttribute(IPropertySymbol property) =>
|
||||||
.GetAttributes()
|
property
|
||||||
.FirstOrDefault(a => a.AttributeClass?.DisplayNameMatches(SymbolNames.CliFxCommandParameterAttribute) == true);
|
.GetAttributes()
|
||||||
|
.FirstOrDefault(
|
||||||
|
a =>
|
||||||
|
a.AttributeClass?.DisplayNameMatches(SymbolNames.CliFxCommandParameterAttribute)
|
||||||
|
== true
|
||||||
|
);
|
||||||
|
|
||||||
public static CommandParameterSymbol? TryResolve(IPropertySymbol property)
|
public static CommandParameterSymbol? TryResolve(IPropertySymbol property)
|
||||||
{
|
{
|
||||||
@@ -48,32 +54,27 @@ internal partial class CommandParameterSymbol
|
|||||||
if (attribute is null)
|
if (attribute is null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
var order = (int)attribute
|
var order = (int)attribute.ConstructorArguments.Select(a => a.Value).First()!;
|
||||||
.ConstructorArguments
|
|
||||||
.Select(a => a.Value)
|
|
||||||
.First()!;
|
|
||||||
|
|
||||||
var name = attribute
|
var name =
|
||||||
.NamedArguments
|
attribute.NamedArguments
|
||||||
.Where(a => a.Key == "Name")
|
.Where(a => a.Key == "Name")
|
||||||
.Select(a => a.Value.Value)
|
.Select(a => a.Value.Value)
|
||||||
.FirstOrDefault() as string;
|
.FirstOrDefault() as string;
|
||||||
|
|
||||||
var isRequired = attribute
|
var isRequired =
|
||||||
.NamedArguments
|
attribute.NamedArguments
|
||||||
.Where(a => a.Key == "IsRequired")
|
.Where(a => a.Key == "IsRequired")
|
||||||
.Select(a => a.Value.Value)
|
.Select(a => a.Value.Value)
|
||||||
.FirstOrDefault() as bool?;
|
.FirstOrDefault() as bool?;
|
||||||
|
|
||||||
var converter = attribute
|
var converter = attribute.NamedArguments
|
||||||
.NamedArguments
|
|
||||||
.Where(a => a.Key == "Converter")
|
.Where(a => a.Key == "Converter")
|
||||||
.Select(a => a.Value.Value)
|
.Select(a => a.Value.Value)
|
||||||
.Cast<ITypeSymbol?>()
|
.Cast<ITypeSymbol?>()
|
||||||
.FirstOrDefault();
|
.FirstOrDefault();
|
||||||
|
|
||||||
var validators = attribute
|
var validators = attribute.NamedArguments
|
||||||
.NamedArguments
|
|
||||||
.Where(a => a.Key == "Validators")
|
.Where(a => a.Key == "Validators")
|
||||||
.SelectMany(a => a.Value.Values)
|
.SelectMany(a => a.Value.Values)
|
||||||
.Select(c => c.Value)
|
.Select(c => c.Value)
|
||||||
@@ -85,4 +86,4 @@ internal partial class CommandParameterSymbol
|
|||||||
|
|
||||||
public static bool IsParameterProperty(IPropertySymbol property) =>
|
public static bool IsParameterProperty(IPropertySymbol property) =>
|
||||||
TryGetParameterAttribute(property) is not null;
|
TryGetParameterAttribute(property) is not null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,6 @@ internal interface ICommandMemberSymbol
|
|||||||
internal static class CommandMemberSymbolExtensions
|
internal static class CommandMemberSymbolExtensions
|
||||||
{
|
{
|
||||||
public static bool IsScalar(this ICommandMemberSymbol member) =>
|
public static bool IsScalar(this ICommandMemberSymbol member) =>
|
||||||
member.Property.Type.SpecialType == SpecialType.System_String ||
|
member.Property.Type.SpecialType == SpecialType.System_String
|
||||||
member.Property.Type.TryGetEnumerableUnderlyingType() is null;
|
|| member.Property.Type.TryGetEnumerableUnderlyingType() is null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,9 +4,10 @@ internal static class SymbolNames
|
|||||||
{
|
{
|
||||||
public const string CliFxCommandInterface = "CliFx.ICommand";
|
public const string CliFxCommandInterface = "CliFx.ICommand";
|
||||||
public const string CliFxCommandAttribute = "CliFx.Attributes.CommandAttribute";
|
public const string CliFxCommandAttribute = "CliFx.Attributes.CommandAttribute";
|
||||||
public const string CliFxCommandParameterAttribute = "CliFx.Attributes.CommandParameterAttribute";
|
public const string CliFxCommandParameterAttribute =
|
||||||
|
"CliFx.Attributes.CommandParameterAttribute";
|
||||||
public const string CliFxCommandOptionAttribute = "CliFx.Attributes.CommandOptionAttribute";
|
public const string CliFxCommandOptionAttribute = "CliFx.Attributes.CommandOptionAttribute";
|
||||||
public const string CliFxConsoleInterface = "CliFx.Infrastructure.IConsole";
|
public const string CliFxConsoleInterface = "CliFx.Infrastructure.IConsole";
|
||||||
public const string CliFxBindingConverterClass = "CliFx.Extensibility.BindingConverter<T>";
|
public const string CliFxBindingConverterClass = "CliFx.Extensibility.BindingConverter<T>";
|
||||||
public const string CliFxBindingValidatorClass = "CliFx.Extensibility.BindingValidator<T>";
|
public const string CliFxBindingValidatorClass = "CliFx.Extensibility.BindingValidator<T>";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,14 +13,14 @@ public class OptionMustBeInsideCommandAnalyzer : AnalyzerBase
|
|||||||
public OptionMustBeInsideCommandAnalyzer()
|
public OptionMustBeInsideCommandAnalyzer()
|
||||||
: base(
|
: base(
|
||||||
"Options must be defined inside commands",
|
"Options must be defined inside commands",
|
||||||
$"This option must be defined inside a class that implements `{SymbolNames.CliFxCommandInterface}`.")
|
$"This option must be defined inside a class that implements `{SymbolNames.CliFxCommandInterface}`."
|
||||||
{
|
) { }
|
||||||
}
|
|
||||||
|
|
||||||
private void Analyze(
|
private void Analyze(
|
||||||
SyntaxNodeAnalysisContext context,
|
SyntaxNodeAnalysisContext context,
|
||||||
PropertyDeclarationSyntax propertyDeclaration,
|
PropertyDeclarationSyntax propertyDeclaration,
|
||||||
IPropertySymbol property)
|
IPropertySymbol property
|
||||||
|
)
|
||||||
{
|
{
|
||||||
if (property.ContainingType is null)
|
if (property.ContainingType is null)
|
||||||
return;
|
return;
|
||||||
@@ -31,10 +31,9 @@ public class OptionMustBeInsideCommandAnalyzer : AnalyzerBase
|
|||||||
if (!CommandOptionSymbol.IsOptionProperty(property))
|
if (!CommandOptionSymbol.IsOptionProperty(property))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var isInsideCommand = property
|
var isInsideCommand = property.ContainingType.AllInterfaces.Any(
|
||||||
.ContainingType
|
i => i.DisplayNameMatches(SymbolNames.CliFxCommandInterface)
|
||||||
.AllInterfaces
|
);
|
||||||
.Any(i => i.DisplayNameMatches(SymbolNames.CliFxCommandInterface));
|
|
||||||
|
|
||||||
if (!isInsideCommand)
|
if (!isInsideCommand)
|
||||||
{
|
{
|
||||||
@@ -49,4 +48,4 @@ public class OptionMustBeInsideCommandAnalyzer : AnalyzerBase
|
|||||||
base.Initialize(context);
|
base.Initialize(context);
|
||||||
context.HandlePropertyDeclaration(Analyze);
|
context.HandlePropertyDeclaration(Analyze);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,14 +12,14 @@ public class OptionMustBeRequiredIfPropertyRequiredAnalyzer : AnalyzerBase
|
|||||||
public OptionMustBeRequiredIfPropertyRequiredAnalyzer()
|
public OptionMustBeRequiredIfPropertyRequiredAnalyzer()
|
||||||
: base(
|
: base(
|
||||||
"Options bound to required properties cannot be marked as non-required",
|
"Options bound to required properties cannot be marked as non-required",
|
||||||
"This option cannot be marked as non-required because it's bound to a required property.")
|
"This option cannot be marked as non-required because it's bound to a required property."
|
||||||
{
|
) { }
|
||||||
}
|
|
||||||
|
|
||||||
private void Analyze(
|
private void Analyze(
|
||||||
SyntaxNodeAnalysisContext context,
|
SyntaxNodeAnalysisContext context,
|
||||||
PropertyDeclarationSyntax propertyDeclaration,
|
PropertyDeclarationSyntax propertyDeclaration,
|
||||||
IPropertySymbol property)
|
IPropertySymbol property
|
||||||
|
)
|
||||||
{
|
{
|
||||||
if (property.ContainingType is null)
|
if (property.ContainingType is null)
|
||||||
return;
|
return;
|
||||||
@@ -34,11 +34,7 @@ public class OptionMustBeRequiredIfPropertyRequiredAnalyzer : AnalyzerBase
|
|||||||
if (option.IsRequired != false)
|
if (option.IsRequired != false)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
context.ReportDiagnostic(
|
context.ReportDiagnostic(CreateDiagnostic(propertyDeclaration.Identifier.GetLocation()));
|
||||||
CreateDiagnostic(
|
|
||||||
propertyDeclaration.Identifier.GetLocation()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Initialize(AnalysisContext context)
|
public override void Initialize(AnalysisContext context)
|
||||||
@@ -46,4 +42,4 @@ public class OptionMustBeRequiredIfPropertyRequiredAnalyzer : AnalyzerBase
|
|||||||
base.Initialize(context);
|
base.Initialize(context);
|
||||||
context.HandlePropertyDeclaration(Analyze);
|
context.HandlePropertyDeclaration(Analyze);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,14 +12,14 @@ public class OptionMustHaveNameOrShortNameAnalyzer : AnalyzerBase
|
|||||||
public OptionMustHaveNameOrShortNameAnalyzer()
|
public OptionMustHaveNameOrShortNameAnalyzer()
|
||||||
: base(
|
: base(
|
||||||
"Options must have either a name or short name specified",
|
"Options must have either a name or short name specified",
|
||||||
"This option must have either a name or short name specified.")
|
"This option must have either a name or short name specified."
|
||||||
{
|
) { }
|
||||||
}
|
|
||||||
|
|
||||||
private void Analyze(
|
private void Analyze(
|
||||||
SyntaxNodeAnalysisContext context,
|
SyntaxNodeAnalysisContext context,
|
||||||
PropertyDeclarationSyntax propertyDeclaration,
|
PropertyDeclarationSyntax propertyDeclaration,
|
||||||
IPropertySymbol property)
|
IPropertySymbol property
|
||||||
|
)
|
||||||
{
|
{
|
||||||
var option = CommandOptionSymbol.TryResolve(property);
|
var option = CommandOptionSymbol.TryResolve(property);
|
||||||
if (option is null)
|
if (option is null)
|
||||||
@@ -38,4 +38,4 @@ public class OptionMustHaveNameOrShortNameAnalyzer : AnalyzerBase
|
|||||||
base.Initialize(context);
|
base.Initialize(context);
|
||||||
context.HandlePropertyDeclaration(Analyze);
|
context.HandlePropertyDeclaration(Analyze);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,16 +14,16 @@ public class OptionMustHaveUniqueNameAnalyzer : AnalyzerBase
|
|||||||
public OptionMustHaveUniqueNameAnalyzer()
|
public OptionMustHaveUniqueNameAnalyzer()
|
||||||
: base(
|
: base(
|
||||||
"Options must have unique names",
|
"Options must have unique names",
|
||||||
"This option's name must be unique within the command (comparison IS NOT case sensitive). " +
|
"This option's name must be unique within the command (comparison IS NOT case sensitive). "
|
||||||
"Specified name: `{0}`. " +
|
+ "Specified name: `{0}`. "
|
||||||
"Property bound to another option with the same name: `{1}`.")
|
+ "Property bound to another option with the same name: `{1}`."
|
||||||
{
|
) { }
|
||||||
}
|
|
||||||
|
|
||||||
private void Analyze(
|
private void Analyze(
|
||||||
SyntaxNodeAnalysisContext context,
|
SyntaxNodeAnalysisContext context,
|
||||||
PropertyDeclarationSyntax propertyDeclaration,
|
PropertyDeclarationSyntax propertyDeclaration,
|
||||||
IPropertySymbol property)
|
IPropertySymbol property
|
||||||
|
)
|
||||||
{
|
{
|
||||||
if (property.ContainingType is null)
|
if (property.ContainingType is null)
|
||||||
return;
|
return;
|
||||||
@@ -35,8 +35,7 @@ public class OptionMustHaveUniqueNameAnalyzer : AnalyzerBase
|
|||||||
if (string.IsNullOrWhiteSpace(option.Name))
|
if (string.IsNullOrWhiteSpace(option.Name))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var otherProperties = property
|
var otherProperties = property.ContainingType
|
||||||
.ContainingType
|
|
||||||
.GetMembers()
|
.GetMembers()
|
||||||
.OfType<IPropertySymbol>()
|
.OfType<IPropertySymbol>()
|
||||||
.Where(m => !m.Equals(property))
|
.Where(m => !m.Equals(property))
|
||||||
@@ -69,4 +68,4 @@ public class OptionMustHaveUniqueNameAnalyzer : AnalyzerBase
|
|||||||
base.Initialize(context);
|
base.Initialize(context);
|
||||||
context.HandlePropertyDeclaration(Analyze);
|
context.HandlePropertyDeclaration(Analyze);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,16 +13,16 @@ public class OptionMustHaveUniqueShortNameAnalyzer : AnalyzerBase
|
|||||||
public OptionMustHaveUniqueShortNameAnalyzer()
|
public OptionMustHaveUniqueShortNameAnalyzer()
|
||||||
: base(
|
: base(
|
||||||
"Options must have unique short names",
|
"Options must have unique short names",
|
||||||
"This option's short name must be unique within the command (comparison IS case sensitive). " +
|
"This option's short name must be unique within the command (comparison IS case sensitive). "
|
||||||
"Specified short name: `{0}` " +
|
+ "Specified short name: `{0}` "
|
||||||
"Property bound to another option with the same short name: `{1}`.")
|
+ "Property bound to another option with the same short name: `{1}`."
|
||||||
{
|
) { }
|
||||||
}
|
|
||||||
|
|
||||||
private void Analyze(
|
private void Analyze(
|
||||||
SyntaxNodeAnalysisContext context,
|
SyntaxNodeAnalysisContext context,
|
||||||
PropertyDeclarationSyntax propertyDeclaration,
|
PropertyDeclarationSyntax propertyDeclaration,
|
||||||
IPropertySymbol property)
|
IPropertySymbol property
|
||||||
|
)
|
||||||
{
|
{
|
||||||
if (property.ContainingType is null)
|
if (property.ContainingType is null)
|
||||||
return;
|
return;
|
||||||
@@ -34,8 +34,7 @@ public class OptionMustHaveUniqueShortNameAnalyzer : AnalyzerBase
|
|||||||
if (option.ShortName is null)
|
if (option.ShortName is null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var otherProperties = property
|
var otherProperties = property.ContainingType
|
||||||
.ContainingType
|
|
||||||
.GetMembers()
|
.GetMembers()
|
||||||
.OfType<IPropertySymbol>()
|
.OfType<IPropertySymbol>()
|
||||||
.Where(m => !m.Equals(property))
|
.Where(m => !m.Equals(property))
|
||||||
@@ -68,4 +67,4 @@ public class OptionMustHaveUniqueShortNameAnalyzer : AnalyzerBase
|
|||||||
base.Initialize(context);
|
base.Initialize(context);
|
||||||
context.HandlePropertyDeclaration(Analyze);
|
context.HandlePropertyDeclaration(Analyze);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,14 +13,14 @@ public class OptionMustHaveValidConverterAnalyzer : AnalyzerBase
|
|||||||
public OptionMustHaveValidConverterAnalyzer()
|
public OptionMustHaveValidConverterAnalyzer()
|
||||||
: base(
|
: base(
|
||||||
$"Option converters must derive from `{SymbolNames.CliFxBindingConverterClass}`",
|
$"Option converters must derive from `{SymbolNames.CliFxBindingConverterClass}`",
|
||||||
$"Converter specified for this option must derive from a compatible `{SymbolNames.CliFxBindingConverterClass}`.")
|
$"Converter specified for this option must derive from a compatible `{SymbolNames.CliFxBindingConverterClass}`."
|
||||||
{
|
) { }
|
||||||
}
|
|
||||||
|
|
||||||
private void Analyze(
|
private void Analyze(
|
||||||
SyntaxNodeAnalysisContext context,
|
SyntaxNodeAnalysisContext context,
|
||||||
PropertyDeclarationSyntax propertyDeclaration,
|
PropertyDeclarationSyntax propertyDeclaration,
|
||||||
IPropertySymbol property)
|
IPropertySymbol property
|
||||||
|
)
|
||||||
{
|
{
|
||||||
var option = CommandOptionSymbol.TryResolve(property);
|
var option = CommandOptionSymbol.TryResolve(property);
|
||||||
if (option is null)
|
if (option is null)
|
||||||
@@ -29,21 +29,26 @@ public class OptionMustHaveValidConverterAnalyzer : AnalyzerBase
|
|||||||
if (option.ConverterType is null)
|
if (option.ConverterType is null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var converterValueType = option
|
var converterValueType = option.ConverterType
|
||||||
.ConverterType
|
|
||||||
.GetBaseTypes()
|
.GetBaseTypes()
|
||||||
.FirstOrDefault(t => t.ConstructedFrom.DisplayNameMatches(SymbolNames.CliFxBindingConverterClass))?
|
.FirstOrDefault(
|
||||||
.TypeArguments
|
t => t.ConstructedFrom.DisplayNameMatches(SymbolNames.CliFxBindingConverterClass)
|
||||||
.FirstOrDefault();
|
)
|
||||||
|
?.TypeArguments.FirstOrDefault();
|
||||||
|
|
||||||
// Value returned by the converter must be assignable to the property type
|
// Value returned by the converter must be assignable to the property type
|
||||||
var isCompatible =
|
var isCompatible =
|
||||||
converterValueType is not null && (option.IsScalar()
|
converterValueType is not null
|
||||||
// Scalar
|
&& (
|
||||||
? context.Compilation.IsAssignable(converterValueType, property.Type)
|
option.IsScalar()
|
||||||
// Non-scalar (assume we can handle all IEnumerable types for simplicity)
|
// Scalar
|
||||||
: property.Type.TryGetEnumerableUnderlyingType() is { } enumerableUnderlyingType &&
|
? context.Compilation.IsAssignable(converterValueType, property.Type)
|
||||||
context.Compilation.IsAssignable(converterValueType, enumerableUnderlyingType)
|
// Non-scalar (assume we can handle all IEnumerable types for simplicity)
|
||||||
|
: property.Type.TryGetEnumerableUnderlyingType() is { } enumerableUnderlyingType
|
||||||
|
&& context.Compilation.IsAssignable(
|
||||||
|
converterValueType,
|
||||||
|
enumerableUnderlyingType
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!isCompatible)
|
if (!isCompatible)
|
||||||
@@ -59,4 +64,4 @@ public class OptionMustHaveValidConverterAnalyzer : AnalyzerBase
|
|||||||
base.Initialize(context);
|
base.Initialize(context);
|
||||||
context.HandlePropertyDeclaration(Analyze);
|
context.HandlePropertyDeclaration(Analyze);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,15 +12,15 @@ public class OptionMustHaveValidNameAnalyzer : AnalyzerBase
|
|||||||
public OptionMustHaveValidNameAnalyzer()
|
public OptionMustHaveValidNameAnalyzer()
|
||||||
: base(
|
: base(
|
||||||
"Options must have valid names",
|
"Options must have valid names",
|
||||||
"This option's name must be at least 2 characters long and must start with a letter. " +
|
"This option's name must be at least 2 characters long and must start with a letter. "
|
||||||
"Specified name: `{0}`.")
|
+ "Specified name: `{0}`."
|
||||||
{
|
) { }
|
||||||
}
|
|
||||||
|
|
||||||
private void Analyze(
|
private void Analyze(
|
||||||
SyntaxNodeAnalysisContext context,
|
SyntaxNodeAnalysisContext context,
|
||||||
PropertyDeclarationSyntax propertyDeclaration,
|
PropertyDeclarationSyntax propertyDeclaration,
|
||||||
IPropertySymbol property)
|
IPropertySymbol property
|
||||||
|
)
|
||||||
{
|
{
|
||||||
var option = CommandOptionSymbol.TryResolve(property);
|
var option = CommandOptionSymbol.TryResolve(property);
|
||||||
if (option is null)
|
if (option is null)
|
||||||
@@ -32,10 +32,7 @@ public class OptionMustHaveValidNameAnalyzer : AnalyzerBase
|
|||||||
if (option.Name.Length < 2 || !char.IsLetter(option.Name[0]))
|
if (option.Name.Length < 2 || !char.IsLetter(option.Name[0]))
|
||||||
{
|
{
|
||||||
context.ReportDiagnostic(
|
context.ReportDiagnostic(
|
||||||
CreateDiagnostic(
|
CreateDiagnostic(propertyDeclaration.Identifier.GetLocation(), option.Name)
|
||||||
propertyDeclaration.Identifier.GetLocation(),
|
|
||||||
option.Name
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -45,4 +42,4 @@ public class OptionMustHaveValidNameAnalyzer : AnalyzerBase
|
|||||||
base.Initialize(context);
|
base.Initialize(context);
|
||||||
context.HandlePropertyDeclaration(Analyze);
|
context.HandlePropertyDeclaration(Analyze);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,15 +12,15 @@ public class OptionMustHaveValidShortNameAnalyzer : AnalyzerBase
|
|||||||
public OptionMustHaveValidShortNameAnalyzer()
|
public OptionMustHaveValidShortNameAnalyzer()
|
||||||
: base(
|
: base(
|
||||||
"Option short names must be letter characters",
|
"Option short names must be letter characters",
|
||||||
"This option's short name must be a single letter character. " +
|
"This option's short name must be a single letter character. "
|
||||||
"Specified short name: `{0}`.")
|
+ "Specified short name: `{0}`."
|
||||||
{
|
) { }
|
||||||
}
|
|
||||||
|
|
||||||
private void Analyze(
|
private void Analyze(
|
||||||
SyntaxNodeAnalysisContext context,
|
SyntaxNodeAnalysisContext context,
|
||||||
PropertyDeclarationSyntax propertyDeclaration,
|
PropertyDeclarationSyntax propertyDeclaration,
|
||||||
IPropertySymbol property)
|
IPropertySymbol property
|
||||||
|
)
|
||||||
{
|
{
|
||||||
var option = CommandOptionSymbol.TryResolve(property);
|
var option = CommandOptionSymbol.TryResolve(property);
|
||||||
if (option is null)
|
if (option is null)
|
||||||
@@ -32,10 +32,7 @@ public class OptionMustHaveValidShortNameAnalyzer : AnalyzerBase
|
|||||||
if (!char.IsLetter(option.ShortName.Value))
|
if (!char.IsLetter(option.ShortName.Value))
|
||||||
{
|
{
|
||||||
context.ReportDiagnostic(
|
context.ReportDiagnostic(
|
||||||
CreateDiagnostic(
|
CreateDiagnostic(propertyDeclaration.Identifier.GetLocation(), option.ShortName)
|
||||||
propertyDeclaration.Identifier.GetLocation(),
|
|
||||||
option.ShortName
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -45,4 +42,4 @@ public class OptionMustHaveValidShortNameAnalyzer : AnalyzerBase
|
|||||||
base.Initialize(context);
|
base.Initialize(context);
|
||||||
context.HandlePropertyDeclaration(Analyze);
|
context.HandlePropertyDeclaration(Analyze);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,14 +13,14 @@ public class OptionMustHaveValidValidatorsAnalyzer : AnalyzerBase
|
|||||||
public OptionMustHaveValidValidatorsAnalyzer()
|
public OptionMustHaveValidValidatorsAnalyzer()
|
||||||
: base(
|
: base(
|
||||||
$"Option validators must derive from `{SymbolNames.CliFxBindingValidatorClass}`",
|
$"Option validators must derive from `{SymbolNames.CliFxBindingValidatorClass}`",
|
||||||
$"Each validator specified for this option must derive from a compatible `{SymbolNames.CliFxBindingValidatorClass}`.")
|
$"Each validator specified for this option must derive from a compatible `{SymbolNames.CliFxBindingValidatorClass}`."
|
||||||
{
|
) { }
|
||||||
}
|
|
||||||
|
|
||||||
private void Analyze(
|
private void Analyze(
|
||||||
SyntaxNodeAnalysisContext context,
|
SyntaxNodeAnalysisContext context,
|
||||||
PropertyDeclarationSyntax propertyDeclaration,
|
PropertyDeclarationSyntax propertyDeclaration,
|
||||||
IPropertySymbol property)
|
IPropertySymbol property
|
||||||
|
)
|
||||||
{
|
{
|
||||||
var option = CommandOptionSymbol.TryResolve(property);
|
var option = CommandOptionSymbol.TryResolve(property);
|
||||||
if (option is null)
|
if (option is null)
|
||||||
@@ -30,14 +30,16 @@ public class OptionMustHaveValidValidatorsAnalyzer : AnalyzerBase
|
|||||||
{
|
{
|
||||||
var validatorValueType = validatorType
|
var validatorValueType = validatorType
|
||||||
.GetBaseTypes()
|
.GetBaseTypes()
|
||||||
.FirstOrDefault(t => t.ConstructedFrom.DisplayNameMatches(SymbolNames.CliFxBindingValidatorClass))?
|
.FirstOrDefault(
|
||||||
.TypeArguments
|
t =>
|
||||||
.FirstOrDefault();
|
t.ConstructedFrom.DisplayNameMatches(SymbolNames.CliFxBindingValidatorClass)
|
||||||
|
)
|
||||||
|
?.TypeArguments.FirstOrDefault();
|
||||||
|
|
||||||
// Value passed to the validator must be assignable from the property type
|
// Value passed to the validator must be assignable from the property type
|
||||||
var isCompatible =
|
var isCompatible =
|
||||||
validatorValueType is not null &&
|
validatorValueType is not null
|
||||||
context.Compilation.IsAssignable(property.Type, validatorValueType);
|
&& context.Compilation.IsAssignable(property.Type, validatorValueType);
|
||||||
|
|
||||||
if (!isCompatible)
|
if (!isCompatible)
|
||||||
{
|
{
|
||||||
@@ -56,4 +58,4 @@ public class OptionMustHaveValidValidatorsAnalyzer : AnalyzerBase
|
|||||||
base.Initialize(context);
|
base.Initialize(context);
|
||||||
context.HandlePropertyDeclaration(Analyze);
|
context.HandlePropertyDeclaration(Analyze);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,14 +13,14 @@ public class ParameterMustBeInsideCommandAnalyzer : AnalyzerBase
|
|||||||
public ParameterMustBeInsideCommandAnalyzer()
|
public ParameterMustBeInsideCommandAnalyzer()
|
||||||
: base(
|
: base(
|
||||||
"Parameters must be defined inside commands",
|
"Parameters must be defined inside commands",
|
||||||
$"This parameter must be defined inside a class that implements `{SymbolNames.CliFxCommandInterface}`.")
|
$"This parameter must be defined inside a class that implements `{SymbolNames.CliFxCommandInterface}`."
|
||||||
{
|
) { }
|
||||||
}
|
|
||||||
|
|
||||||
private void Analyze(
|
private void Analyze(
|
||||||
SyntaxNodeAnalysisContext context,
|
SyntaxNodeAnalysisContext context,
|
||||||
PropertyDeclarationSyntax propertyDeclaration,
|
PropertyDeclarationSyntax propertyDeclaration,
|
||||||
IPropertySymbol property)
|
IPropertySymbol property
|
||||||
|
)
|
||||||
{
|
{
|
||||||
if (property.ContainingType is null)
|
if (property.ContainingType is null)
|
||||||
return;
|
return;
|
||||||
@@ -31,10 +31,9 @@ public class ParameterMustBeInsideCommandAnalyzer : AnalyzerBase
|
|||||||
if (!CommandParameterSymbol.IsParameterProperty(property))
|
if (!CommandParameterSymbol.IsParameterProperty(property))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var isInsideCommand = property
|
var isInsideCommand = property.ContainingType.AllInterfaces.Any(
|
||||||
.ContainingType
|
i => i.DisplayNameMatches(SymbolNames.CliFxCommandInterface)
|
||||||
.AllInterfaces
|
);
|
||||||
.Any(i => i.DisplayNameMatches(SymbolNames.CliFxCommandInterface));
|
|
||||||
|
|
||||||
if (!isInsideCommand)
|
if (!isInsideCommand)
|
||||||
{
|
{
|
||||||
@@ -49,4 +48,4 @@ public class ParameterMustBeInsideCommandAnalyzer : AnalyzerBase
|
|||||||
base.Initialize(context);
|
base.Initialize(context);
|
||||||
context.HandlePropertyDeclaration(Analyze);
|
context.HandlePropertyDeclaration(Analyze);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,15 +13,15 @@ public class ParameterMustBeLastIfNonRequiredAnalyzer : AnalyzerBase
|
|||||||
public ParameterMustBeLastIfNonRequiredAnalyzer()
|
public ParameterMustBeLastIfNonRequiredAnalyzer()
|
||||||
: base(
|
: base(
|
||||||
"Parameters marked as non-required must be the last in order",
|
"Parameters marked as non-required must be the last in order",
|
||||||
"This parameter is non-required so it must be the last in order (its order must be highest within the command). " +
|
"This parameter is non-required so it must be the last in order (its order must be highest within the command). "
|
||||||
"Property bound to another non-required parameter: `{0}`.")
|
+ "Property bound to another non-required parameter: `{0}`."
|
||||||
{
|
) { }
|
||||||
}
|
|
||||||
|
|
||||||
private void Analyze(
|
private void Analyze(
|
||||||
SyntaxNodeAnalysisContext context,
|
SyntaxNodeAnalysisContext context,
|
||||||
PropertyDeclarationSyntax propertyDeclaration,
|
PropertyDeclarationSyntax propertyDeclaration,
|
||||||
IPropertySymbol property)
|
IPropertySymbol property
|
||||||
|
)
|
||||||
{
|
{
|
||||||
if (property.ContainingType is null)
|
if (property.ContainingType is null)
|
||||||
return;
|
return;
|
||||||
@@ -33,8 +33,7 @@ public class ParameterMustBeLastIfNonRequiredAnalyzer : AnalyzerBase
|
|||||||
if (parameter.IsRequired != false)
|
if (parameter.IsRequired != false)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var otherProperties = property
|
var otherProperties = property.ContainingType
|
||||||
.ContainingType
|
|
||||||
.GetMembers()
|
.GetMembers()
|
||||||
.OfType<IPropertySymbol>()
|
.OfType<IPropertySymbol>()
|
||||||
.Where(m => !m.Equals(property))
|
.Where(m => !m.Equals(property))
|
||||||
@@ -63,4 +62,4 @@ public class ParameterMustBeLastIfNonRequiredAnalyzer : AnalyzerBase
|
|||||||
base.Initialize(context);
|
base.Initialize(context);
|
||||||
context.HandlePropertyDeclaration(Analyze);
|
context.HandlePropertyDeclaration(Analyze);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,15 +13,15 @@ public class ParameterMustBeLastIfNonScalarAnalyzer : AnalyzerBase
|
|||||||
public ParameterMustBeLastIfNonScalarAnalyzer()
|
public ParameterMustBeLastIfNonScalarAnalyzer()
|
||||||
: base(
|
: base(
|
||||||
"Parameters of non-scalar types must be the last in order",
|
"Parameters of non-scalar types must be the last in order",
|
||||||
"This parameter has a non-scalar type so it must be the last in order (its order must be highest within the command). " +
|
"This parameter has a non-scalar type so it must be the last in order (its order must be highest within the command). "
|
||||||
"Property bound to another non-scalar parameter: `{0}`.")
|
+ "Property bound to another non-scalar parameter: `{0}`."
|
||||||
{
|
) { }
|
||||||
}
|
|
||||||
|
|
||||||
private void Analyze(
|
private void Analyze(
|
||||||
SyntaxNodeAnalysisContext context,
|
SyntaxNodeAnalysisContext context,
|
||||||
PropertyDeclarationSyntax propertyDeclaration,
|
PropertyDeclarationSyntax propertyDeclaration,
|
||||||
IPropertySymbol property)
|
IPropertySymbol property
|
||||||
|
)
|
||||||
{
|
{
|
||||||
if (property.ContainingType is null)
|
if (property.ContainingType is null)
|
||||||
return;
|
return;
|
||||||
@@ -33,8 +33,7 @@ public class ParameterMustBeLastIfNonScalarAnalyzer : AnalyzerBase
|
|||||||
if (parameter.IsScalar())
|
if (parameter.IsScalar())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var otherProperties = property
|
var otherProperties = property.ContainingType
|
||||||
.ContainingType
|
|
||||||
.GetMembers()
|
.GetMembers()
|
||||||
.OfType<IPropertySymbol>()
|
.OfType<IPropertySymbol>()
|
||||||
.Where(m => !m.Equals(property))
|
.Where(m => !m.Equals(property))
|
||||||
@@ -63,4 +62,4 @@ public class ParameterMustBeLastIfNonScalarAnalyzer : AnalyzerBase
|
|||||||
base.Initialize(context);
|
base.Initialize(context);
|
||||||
context.HandlePropertyDeclaration(Analyze);
|
context.HandlePropertyDeclaration(Analyze);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,14 +12,14 @@ public class ParameterMustBeRequiredIfPropertyRequiredAnalyzer : AnalyzerBase
|
|||||||
public ParameterMustBeRequiredIfPropertyRequiredAnalyzer()
|
public ParameterMustBeRequiredIfPropertyRequiredAnalyzer()
|
||||||
: base(
|
: base(
|
||||||
"Parameters bound to required properties cannot be marked as non-required",
|
"Parameters bound to required properties cannot be marked as non-required",
|
||||||
"This parameter cannot be marked as non-required because it's bound to a required property.")
|
"This parameter cannot be marked as non-required because it's bound to a required property."
|
||||||
{
|
) { }
|
||||||
}
|
|
||||||
|
|
||||||
private void Analyze(
|
private void Analyze(
|
||||||
SyntaxNodeAnalysisContext context,
|
SyntaxNodeAnalysisContext context,
|
||||||
PropertyDeclarationSyntax propertyDeclaration,
|
PropertyDeclarationSyntax propertyDeclaration,
|
||||||
IPropertySymbol property)
|
IPropertySymbol property
|
||||||
|
)
|
||||||
{
|
{
|
||||||
if (property.ContainingType is null)
|
if (property.ContainingType is null)
|
||||||
return;
|
return;
|
||||||
@@ -34,11 +34,7 @@ public class ParameterMustBeRequiredIfPropertyRequiredAnalyzer : AnalyzerBase
|
|||||||
if (parameter.IsRequired != false)
|
if (parameter.IsRequired != false)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
context.ReportDiagnostic(
|
context.ReportDiagnostic(CreateDiagnostic(propertyDeclaration.Identifier.GetLocation()));
|
||||||
CreateDiagnostic(
|
|
||||||
propertyDeclaration.Identifier.GetLocation()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Initialize(AnalysisContext context)
|
public override void Initialize(AnalysisContext context)
|
||||||
@@ -46,4 +42,4 @@ public class ParameterMustBeRequiredIfPropertyRequiredAnalyzer : AnalyzerBase
|
|||||||
base.Initialize(context);
|
base.Initialize(context);
|
||||||
context.HandlePropertyDeclaration(Analyze);
|
context.HandlePropertyDeclaration(Analyze);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,15 +13,15 @@ public class ParameterMustBeSingleIfNonRequiredAnalyzer : AnalyzerBase
|
|||||||
public ParameterMustBeSingleIfNonRequiredAnalyzer()
|
public ParameterMustBeSingleIfNonRequiredAnalyzer()
|
||||||
: base(
|
: base(
|
||||||
"Parameters marked as non-required are limited to one per command",
|
"Parameters marked as non-required are limited to one per command",
|
||||||
"This parameter is non-required so it must be the only such parameter in the command. " +
|
"This parameter is non-required so it must be the only such parameter in the command. "
|
||||||
"Property bound to another non-required parameter: `{0}`.")
|
+ "Property bound to another non-required parameter: `{0}`."
|
||||||
{
|
) { }
|
||||||
}
|
|
||||||
|
|
||||||
private void Analyze(
|
private void Analyze(
|
||||||
SyntaxNodeAnalysisContext context,
|
SyntaxNodeAnalysisContext context,
|
||||||
PropertyDeclarationSyntax propertyDeclaration,
|
PropertyDeclarationSyntax propertyDeclaration,
|
||||||
IPropertySymbol property)
|
IPropertySymbol property
|
||||||
|
)
|
||||||
{
|
{
|
||||||
if (property.ContainingType is null)
|
if (property.ContainingType is null)
|
||||||
return;
|
return;
|
||||||
@@ -33,8 +33,7 @@ public class ParameterMustBeSingleIfNonRequiredAnalyzer : AnalyzerBase
|
|||||||
if (parameter.IsRequired != false)
|
if (parameter.IsRequired != false)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var otherProperties = property
|
var otherProperties = property.ContainingType
|
||||||
.ContainingType
|
|
||||||
.GetMembers()
|
.GetMembers()
|
||||||
.OfType<IPropertySymbol>()
|
.OfType<IPropertySymbol>()
|
||||||
.Where(m => !m.Equals(property))
|
.Where(m => !m.Equals(property))
|
||||||
@@ -63,4 +62,4 @@ public class ParameterMustBeSingleIfNonRequiredAnalyzer : AnalyzerBase
|
|||||||
base.Initialize(context);
|
base.Initialize(context);
|
||||||
context.HandlePropertyDeclaration(Analyze);
|
context.HandlePropertyDeclaration(Analyze);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,15 +13,15 @@ public class ParameterMustBeSingleIfNonScalarAnalyzer : AnalyzerBase
|
|||||||
public ParameterMustBeSingleIfNonScalarAnalyzer()
|
public ParameterMustBeSingleIfNonScalarAnalyzer()
|
||||||
: base(
|
: base(
|
||||||
"Parameters of non-scalar types are limited to one per command",
|
"Parameters of non-scalar types are limited to one per command",
|
||||||
"This parameter has a non-scalar type so it must be the only such parameter in the command. " +
|
"This parameter has a non-scalar type so it must be the only such parameter in the command. "
|
||||||
"Property bound to another non-scalar parameter: `{0}`.")
|
+ "Property bound to another non-scalar parameter: `{0}`."
|
||||||
{
|
) { }
|
||||||
}
|
|
||||||
|
|
||||||
private void Analyze(
|
private void Analyze(
|
||||||
SyntaxNodeAnalysisContext context,
|
SyntaxNodeAnalysisContext context,
|
||||||
PropertyDeclarationSyntax propertyDeclaration,
|
PropertyDeclarationSyntax propertyDeclaration,
|
||||||
IPropertySymbol property)
|
IPropertySymbol property
|
||||||
|
)
|
||||||
{
|
{
|
||||||
if (property.ContainingType is null)
|
if (property.ContainingType is null)
|
||||||
return;
|
return;
|
||||||
@@ -33,8 +33,7 @@ public class ParameterMustBeSingleIfNonScalarAnalyzer : AnalyzerBase
|
|||||||
if (parameter.IsScalar())
|
if (parameter.IsScalar())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var otherProperties = property
|
var otherProperties = property.ContainingType
|
||||||
.ContainingType
|
|
||||||
.GetMembers()
|
.GetMembers()
|
||||||
.OfType<IPropertySymbol>()
|
.OfType<IPropertySymbol>()
|
||||||
.Where(m => !m.Equals(property))
|
.Where(m => !m.Equals(property))
|
||||||
@@ -63,4 +62,4 @@ public class ParameterMustBeSingleIfNonScalarAnalyzer : AnalyzerBase
|
|||||||
base.Initialize(context);
|
base.Initialize(context);
|
||||||
context.HandlePropertyDeclaration(Analyze);
|
context.HandlePropertyDeclaration(Analyze);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,16 +14,16 @@ public class ParameterMustHaveUniqueNameAnalyzer : AnalyzerBase
|
|||||||
public ParameterMustHaveUniqueNameAnalyzer()
|
public ParameterMustHaveUniqueNameAnalyzer()
|
||||||
: base(
|
: base(
|
||||||
"Parameters must have unique names",
|
"Parameters must have unique names",
|
||||||
"This parameter's name must be unique within the command (comparison IS NOT case sensitive). " +
|
"This parameter's name must be unique within the command (comparison IS NOT case sensitive). "
|
||||||
"Specified name: `{0}`. " +
|
+ "Specified name: `{0}`. "
|
||||||
"Property bound to another parameter with the same name: `{1}`.")
|
+ "Property bound to another parameter with the same name: `{1}`."
|
||||||
{
|
) { }
|
||||||
}
|
|
||||||
|
|
||||||
private void Analyze(
|
private void Analyze(
|
||||||
SyntaxNodeAnalysisContext context,
|
SyntaxNodeAnalysisContext context,
|
||||||
PropertyDeclarationSyntax propertyDeclaration,
|
PropertyDeclarationSyntax propertyDeclaration,
|
||||||
IPropertySymbol property)
|
IPropertySymbol property
|
||||||
|
)
|
||||||
{
|
{
|
||||||
if (property.ContainingType is null)
|
if (property.ContainingType is null)
|
||||||
return;
|
return;
|
||||||
@@ -35,8 +35,7 @@ public class ParameterMustHaveUniqueNameAnalyzer : AnalyzerBase
|
|||||||
if (string.IsNullOrWhiteSpace(parameter.Name))
|
if (string.IsNullOrWhiteSpace(parameter.Name))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var otherProperties = property
|
var otherProperties = property.ContainingType
|
||||||
.ContainingType
|
|
||||||
.GetMembers()
|
.GetMembers()
|
||||||
.OfType<IPropertySymbol>()
|
.OfType<IPropertySymbol>()
|
||||||
.Where(m => !m.Equals(property))
|
.Where(m => !m.Equals(property))
|
||||||
@@ -51,7 +50,13 @@ public class ParameterMustHaveUniqueNameAnalyzer : AnalyzerBase
|
|||||||
if (string.IsNullOrWhiteSpace(otherParameter.Name))
|
if (string.IsNullOrWhiteSpace(otherParameter.Name))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (string.Equals(parameter.Name, otherParameter.Name, StringComparison.OrdinalIgnoreCase))
|
if (
|
||||||
|
string.Equals(
|
||||||
|
parameter.Name,
|
||||||
|
otherParameter.Name,
|
||||||
|
StringComparison.OrdinalIgnoreCase
|
||||||
|
)
|
||||||
|
)
|
||||||
{
|
{
|
||||||
context.ReportDiagnostic(
|
context.ReportDiagnostic(
|
||||||
CreateDiagnostic(
|
CreateDiagnostic(
|
||||||
@@ -69,4 +74,4 @@ public class ParameterMustHaveUniqueNameAnalyzer : AnalyzerBase
|
|||||||
base.Initialize(context);
|
base.Initialize(context);
|
||||||
context.HandlePropertyDeclaration(Analyze);
|
context.HandlePropertyDeclaration(Analyze);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,16 +13,16 @@ public class ParameterMustHaveUniqueOrderAnalyzer : AnalyzerBase
|
|||||||
public ParameterMustHaveUniqueOrderAnalyzer()
|
public ParameterMustHaveUniqueOrderAnalyzer()
|
||||||
: base(
|
: base(
|
||||||
"Parameters must have unique order",
|
"Parameters must have unique order",
|
||||||
"This parameter's order must be unique within the command. " +
|
"This parameter's order must be unique within the command. "
|
||||||
"Specified order: {0}. " +
|
+ "Specified order: {0}. "
|
||||||
"Property bound to another parameter with the same order: `{1}`.")
|
+ "Property bound to another parameter with the same order: `{1}`."
|
||||||
{
|
) { }
|
||||||
}
|
|
||||||
|
|
||||||
private void Analyze(
|
private void Analyze(
|
||||||
SyntaxNodeAnalysisContext context,
|
SyntaxNodeAnalysisContext context,
|
||||||
PropertyDeclarationSyntax propertyDeclaration,
|
PropertyDeclarationSyntax propertyDeclaration,
|
||||||
IPropertySymbol property)
|
IPropertySymbol property
|
||||||
|
)
|
||||||
{
|
{
|
||||||
if (property.ContainingType is null)
|
if (property.ContainingType is null)
|
||||||
return;
|
return;
|
||||||
@@ -31,8 +31,7 @@ public class ParameterMustHaveUniqueOrderAnalyzer : AnalyzerBase
|
|||||||
if (parameter is null)
|
if (parameter is null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var otherProperties = property
|
var otherProperties = property.ContainingType
|
||||||
.ContainingType
|
|
||||||
.GetMembers()
|
.GetMembers()
|
||||||
.OfType<IPropertySymbol>()
|
.OfType<IPropertySymbol>()
|
||||||
.Where(m => !m.Equals(property))
|
.Where(m => !m.Equals(property))
|
||||||
@@ -62,4 +61,4 @@ public class ParameterMustHaveUniqueOrderAnalyzer : AnalyzerBase
|
|||||||
base.Initialize(context);
|
base.Initialize(context);
|
||||||
context.HandlePropertyDeclaration(Analyze);
|
context.HandlePropertyDeclaration(Analyze);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,14 +13,14 @@ public class ParameterMustHaveValidConverterAnalyzer : AnalyzerBase
|
|||||||
public ParameterMustHaveValidConverterAnalyzer()
|
public ParameterMustHaveValidConverterAnalyzer()
|
||||||
: base(
|
: base(
|
||||||
$"Parameter converters must derive from `{SymbolNames.CliFxBindingConverterClass}`",
|
$"Parameter converters must derive from `{SymbolNames.CliFxBindingConverterClass}`",
|
||||||
$"Converter specified for this parameter must derive from a compatible `{SymbolNames.CliFxBindingConverterClass}`.")
|
$"Converter specified for this parameter must derive from a compatible `{SymbolNames.CliFxBindingConverterClass}`."
|
||||||
{
|
) { }
|
||||||
}
|
|
||||||
|
|
||||||
private void Analyze(
|
private void Analyze(
|
||||||
SyntaxNodeAnalysisContext context,
|
SyntaxNodeAnalysisContext context,
|
||||||
PropertyDeclarationSyntax propertyDeclaration,
|
PropertyDeclarationSyntax propertyDeclaration,
|
||||||
IPropertySymbol property)
|
IPropertySymbol property
|
||||||
|
)
|
||||||
{
|
{
|
||||||
var parameter = CommandParameterSymbol.TryResolve(property);
|
var parameter = CommandParameterSymbol.TryResolve(property);
|
||||||
if (parameter is null)
|
if (parameter is null)
|
||||||
@@ -29,21 +29,26 @@ public class ParameterMustHaveValidConverterAnalyzer : AnalyzerBase
|
|||||||
if (parameter.ConverterType is null)
|
if (parameter.ConverterType is null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var converterValueType = parameter
|
var converterValueType = parameter.ConverterType
|
||||||
.ConverterType
|
|
||||||
.GetBaseTypes()
|
.GetBaseTypes()
|
||||||
.FirstOrDefault(t => t.ConstructedFrom.DisplayNameMatches(SymbolNames.CliFxBindingConverterClass))?
|
.FirstOrDefault(
|
||||||
.TypeArguments
|
t => t.ConstructedFrom.DisplayNameMatches(SymbolNames.CliFxBindingConverterClass)
|
||||||
.FirstOrDefault();
|
)
|
||||||
|
?.TypeArguments.FirstOrDefault();
|
||||||
|
|
||||||
// Value returned by the converter must be assignable to the property type
|
// Value returned by the converter must be assignable to the property type
|
||||||
var isCompatible =
|
var isCompatible =
|
||||||
converterValueType is not null && (parameter.IsScalar()
|
converterValueType is not null
|
||||||
// Scalar
|
&& (
|
||||||
? context.Compilation.IsAssignable(converterValueType, property.Type)
|
parameter.IsScalar()
|
||||||
// Non-scalar (assume we can handle all IEnumerable types for simplicity)
|
// Scalar
|
||||||
: property.Type.TryGetEnumerableUnderlyingType() is { } enumerableUnderlyingType &&
|
? context.Compilation.IsAssignable(converterValueType, property.Type)
|
||||||
context.Compilation.IsAssignable(converterValueType, enumerableUnderlyingType)
|
// Non-scalar (assume we can handle all IEnumerable types for simplicity)
|
||||||
|
: property.Type.TryGetEnumerableUnderlyingType() is { } enumerableUnderlyingType
|
||||||
|
&& context.Compilation.IsAssignable(
|
||||||
|
converterValueType,
|
||||||
|
enumerableUnderlyingType
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!isCompatible)
|
if (!isCompatible)
|
||||||
@@ -59,4 +64,4 @@ public class ParameterMustHaveValidConverterAnalyzer : AnalyzerBase
|
|||||||
base.Initialize(context);
|
base.Initialize(context);
|
||||||
context.HandlePropertyDeclaration(Analyze);
|
context.HandlePropertyDeclaration(Analyze);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,14 +13,14 @@ public class ParameterMustHaveValidValidatorsAnalyzer : AnalyzerBase
|
|||||||
public ParameterMustHaveValidValidatorsAnalyzer()
|
public ParameterMustHaveValidValidatorsAnalyzer()
|
||||||
: base(
|
: base(
|
||||||
$"Parameter validators must derive from `{SymbolNames.CliFxBindingValidatorClass}`",
|
$"Parameter validators must derive from `{SymbolNames.CliFxBindingValidatorClass}`",
|
||||||
$"Each validator specified for this parameter must derive from a compatible `{SymbolNames.CliFxBindingValidatorClass}`.")
|
$"Each validator specified for this parameter must derive from a compatible `{SymbolNames.CliFxBindingValidatorClass}`."
|
||||||
{
|
) { }
|
||||||
}
|
|
||||||
|
|
||||||
private void Analyze(
|
private void Analyze(
|
||||||
SyntaxNodeAnalysisContext context,
|
SyntaxNodeAnalysisContext context,
|
||||||
PropertyDeclarationSyntax propertyDeclaration,
|
PropertyDeclarationSyntax propertyDeclaration,
|
||||||
IPropertySymbol property)
|
IPropertySymbol property
|
||||||
|
)
|
||||||
{
|
{
|
||||||
var parameter = CommandParameterSymbol.TryResolve(property);
|
var parameter = CommandParameterSymbol.TryResolve(property);
|
||||||
if (parameter is null)
|
if (parameter is null)
|
||||||
@@ -30,14 +30,16 @@ public class ParameterMustHaveValidValidatorsAnalyzer : AnalyzerBase
|
|||||||
{
|
{
|
||||||
var validatorValueType = validatorType
|
var validatorValueType = validatorType
|
||||||
.GetBaseTypes()
|
.GetBaseTypes()
|
||||||
.FirstOrDefault(t => t.ConstructedFrom.DisplayNameMatches(SymbolNames.CliFxBindingValidatorClass))?
|
.FirstOrDefault(
|
||||||
.TypeArguments
|
t =>
|
||||||
.FirstOrDefault();
|
t.ConstructedFrom.DisplayNameMatches(SymbolNames.CliFxBindingValidatorClass)
|
||||||
|
)
|
||||||
|
?.TypeArguments.FirstOrDefault();
|
||||||
|
|
||||||
// Value passed to the validator must be assignable from the property type
|
// Value passed to the validator must be assignable from the property type
|
||||||
var isCompatible =
|
var isCompatible =
|
||||||
validatorValueType is not null &&
|
validatorValueType is not null
|
||||||
context.Compilation.IsAssignable(property.Type, validatorValueType);
|
&& context.Compilation.IsAssignable(property.Type, validatorValueType);
|
||||||
|
|
||||||
if (!isCompatible)
|
if (!isCompatible)
|
||||||
{
|
{
|
||||||
@@ -56,4 +58,4 @@ public class ParameterMustHaveValidValidatorsAnalyzer : AnalyzerBase
|
|||||||
base.Initialize(context);
|
base.Initialize(context);
|
||||||
context.HandlePropertyDeclaration(Analyze);
|
context.HandlePropertyDeclaration(Analyze);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,13 +15,13 @@ public class SystemConsoleShouldBeAvoidedAnalyzer : AnalyzerBase
|
|||||||
: base(
|
: base(
|
||||||
$"Avoid calling `System.Console` where `{SymbolNames.CliFxConsoleInterface}` is available",
|
$"Avoid calling `System.Console` where `{SymbolNames.CliFxConsoleInterface}` is available",
|
||||||
$"Use the provided `{SymbolNames.CliFxConsoleInterface}` abstraction instead of `System.Console` to ensure that the command can be tested in isolation.",
|
$"Use the provided `{SymbolNames.CliFxConsoleInterface}` abstraction instead of `System.Console` to ensure that the command can be tested in isolation.",
|
||||||
DiagnosticSeverity.Warning)
|
DiagnosticSeverity.Warning
|
||||||
{
|
) { }
|
||||||
}
|
|
||||||
|
|
||||||
private MemberAccessExpressionSyntax? TryGetSystemConsoleMemberAccess(
|
private MemberAccessExpressionSyntax? TryGetSystemConsoleMemberAccess(
|
||||||
SyntaxNodeAnalysisContext context,
|
SyntaxNodeAnalysisContext context,
|
||||||
SyntaxNode node)
|
SyntaxNode node
|
||||||
|
)
|
||||||
{
|
{
|
||||||
var currentNode = node;
|
var currentNode = node;
|
||||||
|
|
||||||
@@ -53,8 +53,7 @@ public class SystemConsoleShouldBeAvoidedAnalyzer : AnalyzerBase
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// Check if IConsole is available in scope as an alternative to System.Console
|
// Check if IConsole is available in scope as an alternative to System.Console
|
||||||
var isConsoleInterfaceAvailable = context
|
var isConsoleInterfaceAvailable = context.Node
|
||||||
.Node
|
|
||||||
.Ancestors()
|
.Ancestors()
|
||||||
.OfType<MethodDeclarationSyntax>()
|
.OfType<MethodDeclarationSyntax>()
|
||||||
.SelectMany(m => m.ParameterList.Parameters)
|
.SelectMany(m => m.ParameterList.Parameters)
|
||||||
@@ -65,9 +64,7 @@ public class SystemConsoleShouldBeAvoidedAnalyzer : AnalyzerBase
|
|||||||
|
|
||||||
if (isConsoleInterfaceAvailable)
|
if (isConsoleInterfaceAvailable)
|
||||||
{
|
{
|
||||||
context.ReportDiagnostic(
|
context.ReportDiagnostic(CreateDiagnostic(systemConsoleMemberAccess.GetLocation()));
|
||||||
CreateDiagnostic(systemConsoleMemberAccess.GetLocation())
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,4 +73,4 @@ public class SystemConsoleShouldBeAvoidedAnalyzer : AnalyzerBase
|
|||||||
base.Initialize(context);
|
base.Initialize(context);
|
||||||
context.RegisterSyntaxNodeAction(Analyze, SyntaxKind.SimpleMemberAccessExpression);
|
context.RegisterSyntaxNodeAction(Analyze, SyntaxKind.SimpleMemberAccessExpression);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,56 +29,72 @@ internal static class RoslynExtensions
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ITypeSymbol? TryGetEnumerableUnderlyingType(this ITypeSymbol type) => type
|
public static ITypeSymbol? TryGetEnumerableUnderlyingType(this ITypeSymbol type) =>
|
||||||
.AllInterfaces
|
type.AllInterfaces
|
||||||
.FirstOrDefault(i => i.ConstructedFrom.SpecialType == SpecialType.System_Collections_Generic_IEnumerable_T)?
|
.FirstOrDefault(
|
||||||
.TypeArguments[0];
|
i =>
|
||||||
|
i.ConstructedFrom.SpecialType
|
||||||
|
== SpecialType.System_Collections_Generic_IEnumerable_T
|
||||||
|
)
|
||||||
|
?.TypeArguments[0];
|
||||||
|
|
||||||
// Detect if the property is required through roundabout means so as to not have to take dependency
|
// Detect if the property is required through roundabout means so as to not have to take dependency
|
||||||
// on higher versions of the C# compiler.
|
// on higher versions of the C# compiler.
|
||||||
public static bool IsRequired(this IPropertySymbol property) => property
|
public static bool IsRequired(this IPropertySymbol property) =>
|
||||||
|
property
|
||||||
// Can't rely on the RequiredMemberAttribute because it's generated by the compiler, not added by the user,
|
// Can't rely on the RequiredMemberAttribute because it's generated by the compiler, not added by the user,
|
||||||
// so we have to check for the presence of the `required` modifier in the syntax tree instead.
|
// so we have to check for the presence of the `required` modifier in the syntax tree instead.
|
||||||
.DeclaringSyntaxReferences
|
.DeclaringSyntaxReferences
|
||||||
.Select(r => r.GetSyntax())
|
.Select(r => r.GetSyntax())
|
||||||
.OfType<PropertyDeclarationSyntax>()
|
.OfType<PropertyDeclarationSyntax>()
|
||||||
.SelectMany(p => p.Modifiers)
|
.SelectMany(p => p.Modifiers)
|
||||||
.Any(m => m.IsKind((SyntaxKind)8447));
|
.Any(m => m.IsKind((SyntaxKind)8447));
|
||||||
|
|
||||||
public static bool IsAssignable(this Compilation compilation, ITypeSymbol source, ITypeSymbol destination) =>
|
public static bool IsAssignable(
|
||||||
compilation.ClassifyConversion(source, destination).Exists;
|
this Compilation compilation,
|
||||||
|
ITypeSymbol source,
|
||||||
|
ITypeSymbol destination
|
||||||
|
) => compilation.ClassifyConversion(source, destination).Exists;
|
||||||
|
|
||||||
public static void HandleClassDeclaration(
|
public static void HandleClassDeclaration(
|
||||||
this AnalysisContext analysisContext,
|
this AnalysisContext analysisContext,
|
||||||
Action<SyntaxNodeAnalysisContext, ClassDeclarationSyntax, ITypeSymbol> analyze)
|
Action<SyntaxNodeAnalysisContext, ClassDeclarationSyntax, ITypeSymbol> analyze
|
||||||
|
)
|
||||||
{
|
{
|
||||||
analysisContext.RegisterSyntaxNodeAction(ctx =>
|
analysisContext.RegisterSyntaxNodeAction(
|
||||||
{
|
ctx =>
|
||||||
if (ctx.Node is not ClassDeclarationSyntax classDeclaration)
|
{
|
||||||
return;
|
if (ctx.Node is not ClassDeclarationSyntax classDeclaration)
|
||||||
|
return;
|
||||||
|
|
||||||
var type = ctx.SemanticModel.GetDeclaredSymbol(classDeclaration);
|
var type = ctx.SemanticModel.GetDeclaredSymbol(classDeclaration);
|
||||||
if (type is null)
|
if (type is null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
analyze(ctx, classDeclaration, type);
|
analyze(ctx, classDeclaration, type);
|
||||||
}, SyntaxKind.ClassDeclaration);
|
},
|
||||||
|
SyntaxKind.ClassDeclaration
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void HandlePropertyDeclaration(
|
public static void HandlePropertyDeclaration(
|
||||||
this AnalysisContext analysisContext,
|
this AnalysisContext analysisContext,
|
||||||
Action<SyntaxNodeAnalysisContext, PropertyDeclarationSyntax, IPropertySymbol> analyze)
|
Action<SyntaxNodeAnalysisContext, PropertyDeclarationSyntax, IPropertySymbol> analyze
|
||||||
|
)
|
||||||
{
|
{
|
||||||
analysisContext.RegisterSyntaxNodeAction(ctx =>
|
analysisContext.RegisterSyntaxNodeAction(
|
||||||
{
|
ctx =>
|
||||||
if (ctx.Node is not PropertyDeclarationSyntax propertyDeclaration)
|
{
|
||||||
return;
|
if (ctx.Node is not PropertyDeclarationSyntax propertyDeclaration)
|
||||||
|
return;
|
||||||
|
|
||||||
var property = ctx.SemanticModel.GetDeclaredSymbol(propertyDeclaration);
|
var property = ctx.SemanticModel.GetDeclaredSymbol(propertyDeclaration);
|
||||||
if (property is null)
|
if (property is null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
analyze(ctx, propertyDeclaration, property);
|
analyze(ctx, propertyDeclaration, property);
|
||||||
}, SyntaxKind.PropertyDeclaration);
|
},
|
||||||
|
SyntaxKind.PropertyDeclaration
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,11 +7,12 @@ internal static class StringExtensions
|
|||||||
public static string TrimEnd(
|
public static string TrimEnd(
|
||||||
this string str,
|
this string str,
|
||||||
string sub,
|
string sub,
|
||||||
StringComparison comparison = StringComparison.Ordinal)
|
StringComparison comparison = StringComparison.Ordinal
|
||||||
|
)
|
||||||
{
|
{
|
||||||
while (str.EndsWith(sub, comparison))
|
while (str.EndsWith(sub, comparison))
|
||||||
str = str[..^sub.Length];
|
str = str[..^sub.Length];
|
||||||
|
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,4 +29,4 @@ public partial class Benchmarks
|
|||||||
.AddCommand<CliFxCommand>()
|
.AddCommand<CliFxCommand>()
|
||||||
.Build()
|
.Build()
|
||||||
.RunAsync(Arguments, new Dictionary<string, string>());
|
.RunAsync(Arguments, new Dictionary<string, string>());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,11 +16,9 @@ public partial class Benchmarks
|
|||||||
[NamedArgument('b', "bool", Constraint = NumArgsConstraint.Optional, Const = true)]
|
[NamedArgument('b', "bool", Constraint = NumArgsConstraint.Optional, Const = true)]
|
||||||
public bool BoolOption { get; set; }
|
public bool BoolOption { get; set; }
|
||||||
|
|
||||||
public void Execute()
|
public void Execute() { }
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Benchmark(Description = "Clipr")]
|
[Benchmark(Description = "Clipr")]
|
||||||
public void ExecuteWithClipr() => CliParser.Parse<CliprCommand>(Arguments).Execute();
|
public void ExecuteWithClipr() => CliParser.Parse<CliprCommand>(Arguments).Execute();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,16 +8,12 @@ public partial class Benchmarks
|
|||||||
public class CoconaCommand
|
public class CoconaCommand
|
||||||
{
|
{
|
||||||
public void Execute(
|
public void Execute(
|
||||||
[Option("str", new []{'s'})]
|
[Option("str", new[] { 's' })] string? strOption,
|
||||||
string? strOption,
|
[Option("int", new[] { 'i' })] int intOption,
|
||||||
[Option("int", new []{'i'})]
|
[Option("bool", new[] { 'b' })] bool boolOption
|
||||||
int intOption,
|
) { }
|
||||||
[Option("bool", new []{'b'})]
|
|
||||||
bool boolOption)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Benchmark(Description = "Cocona")]
|
[Benchmark(Description = "Cocona")]
|
||||||
public void ExecuteWithCocona() => CoconaApp.Run<CoconaCommand>(Arguments);
|
public void ExecuteWithCocona() => CoconaApp.Run<CoconaCommand>(Arguments);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,9 +16,7 @@ public partial class Benchmarks
|
|||||||
[Option('b', "bool")]
|
[Option('b', "bool")]
|
||||||
public bool BoolOption { get; set; }
|
public bool BoolOption { get; set; }
|
||||||
|
|
||||||
public void Execute()
|
public void Execute() { }
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Benchmark(Description = "CommandLineParser")]
|
[Benchmark(Description = "CommandLineParser")]
|
||||||
@@ -26,4 +24,4 @@ public partial class Benchmarks
|
|||||||
new Parser()
|
new Parser()
|
||||||
.ParseArguments(Arguments, typeof(CommandLineParserCommand))
|
.ParseArguments(Arguments, typeof(CommandLineParserCommand))
|
||||||
.WithParsed<CommandLineParserCommand>(c => c.Execute());
|
.WithParsed<CommandLineParserCommand>(c => c.Execute());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,4 +21,4 @@ public partial class Benchmarks
|
|||||||
|
|
||||||
[Benchmark(Description = "McMaster.Extensions.CommandLineUtils")]
|
[Benchmark(Description = "McMaster.Extensions.CommandLineUtils")]
|
||||||
public int ExecuteWithMcMaster() => CommandLineApplication.Execute<McMasterCommand>(Arguments);
|
public int ExecuteWithMcMaster() => CommandLineApplication.Execute<McMasterCommand>(Arguments);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,11 +16,9 @@ public partial class Benchmarks
|
|||||||
[ArgShortcut("--bool"), ArgShortcut("-b")]
|
[ArgShortcut("--bool"), ArgShortcut("-b")]
|
||||||
public bool BoolOption { get; set; }
|
public bool BoolOption { get; set; }
|
||||||
|
|
||||||
public void Main()
|
public void Main() { }
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Benchmark(Description = "PowerArgs")]
|
[Benchmark(Description = "PowerArgs")]
|
||||||
public void ExecuteWithPowerArgs() => Args.InvokeMain<PowerArgsCommand>(Arguments);
|
public void ExecuteWithPowerArgs() => Args.InvokeMain<PowerArgsCommand>(Arguments);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,18 +15,9 @@ public partial class Benchmarks
|
|||||||
{
|
{
|
||||||
var command = new RootCommand
|
var command = new RootCommand
|
||||||
{
|
{
|
||||||
new Option(new[] {"--str", "-s"})
|
new Option(new[] { "--str", "-s" }) { Argument = new Argument<string?>() },
|
||||||
{
|
new Option(new[] { "--int", "-i" }) { Argument = new Argument<int>() },
|
||||||
Argument = new Argument<string?>()
|
new Option(new[] { "--bool", "-b" }) { Argument = new Argument<bool>() }
|
||||||
},
|
|
||||||
new Option(new[] {"--int", "-i"})
|
|
||||||
{
|
|
||||||
Argument = new Argument<int>()
|
|
||||||
},
|
|
||||||
new Option(new[] {"--bool", "-b"})
|
|
||||||
{
|
|
||||||
Argument = new Argument<bool>()
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
command.Handler = CommandHandler.Create(
|
command.Handler = CommandHandler.Create(
|
||||||
@@ -40,4 +31,4 @@ public partial class Benchmarks
|
|||||||
[Benchmark(Description = "System.CommandLine")]
|
[Benchmark(Description = "System.CommandLine")]
|
||||||
public async Task<int> ExecuteWithSystemCommandLine() =>
|
public async Task<int> ExecuteWithSystemCommandLine() =>
|
||||||
await new SystemCommandLineCommand().ExecuteAsync(Arguments);
|
await new SystemCommandLineCommand().ExecuteAsync(Arguments);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,11 +9,10 @@ namespace CliFx.Benchmarks;
|
|||||||
[Orderer(SummaryOrderPolicy.FastestToSlowest)]
|
[Orderer(SummaryOrderPolicy.FastestToSlowest)]
|
||||||
public partial class Benchmarks
|
public partial class Benchmarks
|
||||||
{
|
{
|
||||||
private static readonly string[] Arguments = {"--str", "hello world", "-i", "13", "-b"};
|
private static readonly string[] Arguments = { "--str", "hello world", "-i", "13", "-b" };
|
||||||
|
|
||||||
public static void Main() => BenchmarkRunner.Run<Benchmarks>(
|
public static void Main() =>
|
||||||
DefaultConfig
|
BenchmarkRunner.Run<Benchmarks>(
|
||||||
.Instance
|
DefaultConfig.Instance.WithOptions(ConfigOptions.DisableOptimizationsValidator)
|
||||||
.WithOptions(ConfigOptions.DisableOptimizationsValidator)
|
);
|
||||||
);
|
}
|
||||||
}
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
<PackageReference Include="clipr" Version="1.6.1" />
|
<PackageReference Include="clipr" Version="1.6.1" />
|
||||||
<PackageReference Include="Cocona" Version="2.2.0" />
|
<PackageReference Include="Cocona" Version="2.2.0" />
|
||||||
<PackageReference Include="CommandLineParser" Version="2.9.1" />
|
<PackageReference Include="CommandLineParser" Version="2.9.1" />
|
||||||
|
<PackageReference Include="CSharpier.MsBuild" Version="0.25.0" PrivateAssets="all" />
|
||||||
<PackageReference Include="McMaster.Extensions.CommandLineUtils" Version="4.0.2" />
|
<PackageReference Include="McMaster.Extensions.CommandLineUtils" Version="4.0.2" />
|
||||||
<PackageReference Include="PowerArgs" Version="4.0.2" />
|
<PackageReference Include="PowerArgs" Version="4.0.2" />
|
||||||
<PackageReference Include="System.CommandLine" Version="2.0.0-beta1.20574.7" />
|
<PackageReference Include="System.CommandLine" Version="2.0.0-beta1.20574.7" />
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="CSharpier.MsBuild" Version="0.25.0" PrivateAssets="all" />
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" />
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -49,21 +49,23 @@ public partial class BookAddCommand
|
|||||||
{
|
{
|
||||||
private static readonly Random Random = new();
|
private static readonly Random Random = new();
|
||||||
|
|
||||||
private static DateTimeOffset CreateRandomDate() => new(
|
private static DateTimeOffset CreateRandomDate() =>
|
||||||
Random.Next(1800, 2020),
|
new(
|
||||||
Random.Next(1, 12),
|
Random.Next(1800, 2020),
|
||||||
Random.Next(1, 28),
|
Random.Next(1, 12),
|
||||||
Random.Next(1, 23),
|
Random.Next(1, 28),
|
||||||
Random.Next(1, 59),
|
Random.Next(1, 23),
|
||||||
Random.Next(1, 59),
|
Random.Next(1, 59),
|
||||||
TimeSpan.Zero
|
Random.Next(1, 59),
|
||||||
);
|
TimeSpan.Zero
|
||||||
|
);
|
||||||
|
|
||||||
private static Isbn CreateRandomIsbn() => new(
|
private static Isbn CreateRandomIsbn() =>
|
||||||
Random.Next(0, 999),
|
new(
|
||||||
Random.Next(0, 99),
|
Random.Next(0, 999),
|
||||||
Random.Next(0, 99999),
|
Random.Next(0, 99),
|
||||||
Random.Next(0, 99),
|
Random.Next(0, 99999),
|
||||||
Random.Next(0, 9)
|
Random.Next(0, 99),
|
||||||
);
|
Random.Next(0, 9)
|
||||||
}
|
);
|
||||||
|
}
|
||||||
|
|||||||
@@ -31,4 +31,4 @@ public class BookCommand : ICommand
|
|||||||
|
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,4 +33,4 @@ public class BookListCommand : ICommand
|
|||||||
|
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,4 +32,4 @@ public class BookRemoveCommand : ICommand
|
|||||||
|
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,4 +2,4 @@
|
|||||||
|
|
||||||
namespace CliFx.Demo.Domain;
|
namespace CliFx.Demo.Domain;
|
||||||
|
|
||||||
public record Book(string Title, string Author, DateTimeOffset Published, Isbn Isbn);
|
public record Book(string Title, string Author, DateTimeOffset Published, Isbn Isbn);
|
||||||
|
|||||||
@@ -2,7 +2,13 @@
|
|||||||
|
|
||||||
namespace CliFx.Demo.Domain;
|
namespace CliFx.Demo.Domain;
|
||||||
|
|
||||||
public partial record Isbn(int EanPrefix, int RegistrationGroup, int Registrant, int Publication, int CheckDigit)
|
public partial record Isbn(
|
||||||
|
int EanPrefix,
|
||||||
|
int RegistrationGroup,
|
||||||
|
int Registrant,
|
||||||
|
int Publication,
|
||||||
|
int CheckDigit
|
||||||
|
)
|
||||||
{
|
{
|
||||||
public override string ToString() =>
|
public override string ToString() =>
|
||||||
$"{EanPrefix:000}-{RegistrationGroup:00}-{Registrant:00000}-{Publication:00}-{CheckDigit:0}";
|
$"{EanPrefix:000}-{RegistrationGroup:00}-{Registrant:00000}-{Publication:00}-{CheckDigit:0}";
|
||||||
@@ -22,4 +28,4 @@ public partial record Isbn
|
|||||||
int.Parse(components[4], formatProvider)
|
int.Parse(components[4], formatProvider)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,4 +25,4 @@ public partial record Library(IReadOnlyList<Book> Books)
|
|||||||
public partial record Library
|
public partial record Library
|
||||||
{
|
{
|
||||||
public static Library Empty { get; } = new(Array.Empty<Book>());
|
public static Library Empty { get; } = new(Array.Empty<Book>());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,8 @@ namespace CliFx.Demo.Domain;
|
|||||||
|
|
||||||
public class LibraryProvider
|
public class LibraryProvider
|
||||||
{
|
{
|
||||||
private static string StorageFilePath { get; } = Path.Combine(Directory.GetCurrentDirectory(), "Library.json");
|
private static string StorageFilePath { get; } =
|
||||||
|
Path.Combine(Directory.GetCurrentDirectory(), "Library.json");
|
||||||
|
|
||||||
private void StoreLibrary(Library library)
|
private void StoreLibrary(Library library)
|
||||||
{
|
{
|
||||||
@@ -24,7 +25,8 @@ public class LibraryProvider
|
|||||||
return JsonSerializer.Deserialize<Library>(data) ?? Library.Empty;
|
return JsonSerializer.Deserialize<Library>(data) ?? Library.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Book? TryGetBook(string title) => GetLibrary().Books.FirstOrDefault(b => b.Title == title);
|
public Book? TryGetBook(string title) =>
|
||||||
|
GetLibrary().Books.FirstOrDefault(b => b.Title == title);
|
||||||
|
|
||||||
public void AddBook(Book book)
|
public void AddBook(Book book)
|
||||||
{
|
{
|
||||||
@@ -37,4 +39,4 @@ public class LibraryProvider
|
|||||||
var updatedLibrary = GetLibrary().WithoutBook(book);
|
var updatedLibrary = GetLibrary().WithoutBook(book);
|
||||||
StoreLibrary(updatedLibrary);
|
StoreLibrary(updatedLibrary);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,4 +18,4 @@ return await new CliApplicationBuilder()
|
|||||||
return services.BuildServiceProvider();
|
return services.BuildServiceProvider();
|
||||||
})
|
})
|
||||||
.Build()
|
.Build()
|
||||||
.RunAsync();
|
.RunAsync();
|
||||||
|
|||||||
@@ -33,4 +33,4 @@ internal static class ConsoleExtensions
|
|||||||
using (writer.Console.WithForegroundColor(ConsoleColor.White))
|
using (writer.Console.WithForegroundColor(ConsoleColor.White))
|
||||||
writer.WriteLine(book.Isbn);
|
writer.WriteLine(book.Isbn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,10 @@
|
|||||||
<ApplicationIcon>../favicon.ico</ApplicationIcon>
|
<ApplicationIcon>../favicon.ico</ApplicationIcon>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="CSharpier.MsBuild" Version="0.25.0" PrivateAssets="all" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\CliFx\CliFx.csproj" />
|
<ProjectReference Include="..\CliFx\CliFx.csproj" />
|
||||||
<ProjectReference Include="..\CliFx.Analyzers\CliFx.Analyzers.csproj" ReferenceOutputAssembly="false" OutputItemType="analyzer" />
|
<ProjectReference Include="..\CliFx.Analyzers\CliFx.Analyzers.csproj" ReferenceOutputAssembly="false" OutputItemType="analyzer" />
|
||||||
|
|||||||
@@ -14,10 +14,7 @@ public class CancellationTestCommand : ICommand
|
|||||||
{
|
{
|
||||||
console.Output.WriteLine("Started.");
|
console.Output.WriteLine("Started.");
|
||||||
|
|
||||||
await Task.Delay(
|
await Task.Delay(TimeSpan.FromSeconds(3), console.RegisterCancellationHandler());
|
||||||
TimeSpan.FromSeconds(3),
|
|
||||||
console.RegisterCancellationHandler()
|
|
||||||
);
|
|
||||||
|
|
||||||
console.Output.WriteLine("Completed.");
|
console.Output.WriteLine("Completed.");
|
||||||
}
|
}
|
||||||
@@ -27,4 +24,4 @@ public class CancellationTestCommand : ICommand
|
|||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,4 +20,4 @@ public class ConsoleTestCommand : ICommand
|
|||||||
|
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,4 +16,4 @@ public class EnvironmentTestCommand : ICommand
|
|||||||
|
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,10 +10,11 @@ namespace CliFx.Tests.Dummy;
|
|||||||
public static class Program
|
public static class Program
|
||||||
{
|
{
|
||||||
// Path to the apphost
|
// Path to the apphost
|
||||||
public static string FilePath { get; } = Path.ChangeExtension(
|
public static string FilePath { get; } =
|
||||||
Assembly.GetExecutingAssembly().Location,
|
Path.ChangeExtension(
|
||||||
RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "exe" : null
|
Assembly.GetExecutingAssembly().Location,
|
||||||
);
|
RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "exe" : null
|
||||||
|
);
|
||||||
|
|
||||||
public static async Task Main()
|
public static async Task Main()
|
||||||
{
|
{
|
||||||
@@ -23,9 +24,6 @@ public static class Program
|
|||||||
"false"
|
"false"
|
||||||
);
|
);
|
||||||
|
|
||||||
await new CliApplicationBuilder()
|
await new CliApplicationBuilder().AddCommandsFromThisAssembly().Build().RunAsync();
|
||||||
.AddCommandsFromThisAssembly()
|
|
||||||
.Build()
|
|
||||||
.RunAsync();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,9 +11,7 @@ namespace CliFx.Tests;
|
|||||||
public class ApplicationSpecs : SpecsBase
|
public class ApplicationSpecs : SpecsBase
|
||||||
{
|
{
|
||||||
public ApplicationSpecs(ITestOutputHelper testOutput)
|
public ApplicationSpecs(ITestOutputHelper testOutput)
|
||||||
: base(testOutput)
|
: base(testOutput) { }
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task I_can_create_an_application_with_the_default_configuration()
|
public async Task I_can_create_an_application_with_the_default_configuration()
|
||||||
@@ -24,10 +22,7 @@ public class ApplicationSpecs : SpecsBase
|
|||||||
.UseConsole(FakeConsole)
|
.UseConsole(FakeConsole)
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
var exitCode = await app.RunAsync(
|
var exitCode = await app.RunAsync(Array.Empty<string>(), new Dictionary<string, string>());
|
||||||
Array.Empty<string>(),
|
|
||||||
new Dictionary<string, string>()
|
|
||||||
);
|
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
exitCode.Should().Be(0);
|
exitCode.Should().Be(0);
|
||||||
@@ -40,8 +35,8 @@ public class ApplicationSpecs : SpecsBase
|
|||||||
var app = new CliApplicationBuilder()
|
var app = new CliApplicationBuilder()
|
||||||
.AddCommand<NoOpCommand>()
|
.AddCommand<NoOpCommand>()
|
||||||
.AddCommandsFrom(typeof(NoOpCommand).Assembly)
|
.AddCommandsFrom(typeof(NoOpCommand).Assembly)
|
||||||
.AddCommands(new[] {typeof(NoOpCommand)})
|
.AddCommands(new[] { typeof(NoOpCommand) })
|
||||||
.AddCommandsFrom(new[] {typeof(NoOpCommand).Assembly})
|
.AddCommandsFrom(new[] { typeof(NoOpCommand).Assembly })
|
||||||
.AddCommandsFromThisAssembly()
|
.AddCommandsFromThisAssembly()
|
||||||
.AllowDebugMode()
|
.AllowDebugMode()
|
||||||
.AllowPreviewMode()
|
.AllowPreviewMode()
|
||||||
@@ -53,10 +48,7 @@ public class ApplicationSpecs : SpecsBase
|
|||||||
.UseTypeActivator(Activator.CreateInstance!)
|
.UseTypeActivator(Activator.CreateInstance!)
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
var exitCode = await app.RunAsync(
|
var exitCode = await app.RunAsync(Array.Empty<string>(), new Dictionary<string, string>());
|
||||||
Array.Empty<string>(),
|
|
||||||
new Dictionary<string, string>()
|
|
||||||
);
|
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
exitCode.Should().Be(0);
|
exitCode.Should().Be(0);
|
||||||
@@ -71,10 +63,7 @@ public class ApplicationSpecs : SpecsBase
|
|||||||
.UseConsole(FakeConsole)
|
.UseConsole(FakeConsole)
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
var exitCode = await app.RunAsync(
|
var exitCode = await app.RunAsync(Array.Empty<string>(), new Dictionary<string, string>());
|
||||||
Array.Empty<string>(),
|
|
||||||
new Dictionary<string, string>()
|
|
||||||
);
|
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
exitCode.Should().NotBe(0);
|
exitCode.Should().NotBe(0);
|
||||||
@@ -82,4 +71,4 @@ public class ApplicationSpecs : SpecsBase
|
|||||||
var stdErr = FakeConsole.ReadErrorString();
|
var stdErr = FakeConsole.ReadErrorString();
|
||||||
stdErr.Should().Contain("not a valid command");
|
stdErr.Should().Contain("not a valid command");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,9 +15,7 @@ namespace CliFx.Tests;
|
|||||||
public class CancellationSpecs : SpecsBase
|
public class CancellationSpecs : SpecsBase
|
||||||
{
|
{
|
||||||
public CancellationSpecs(ITestOutputHelper testOutput)
|
public CancellationSpecs(ITestOutputHelper testOutput)
|
||||||
: base(testOutput)
|
: base(testOutput) { }
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact(Timeout = 15000)]
|
[Fact(Timeout = 15000)]
|
||||||
public async Task I_can_configure_the_command_to_listen_to_the_interrupt_signal()
|
public async Task I_can_configure_the_command_to_listen_to_the_interrupt_signal()
|
||||||
@@ -41,24 +39,20 @@ public class CancellationSpecs : SpecsBase
|
|||||||
PipeTarget.ToStringBuilder(stdOutBuffer)
|
PipeTarget.ToStringBuilder(stdOutBuffer)
|
||||||
);
|
);
|
||||||
|
|
||||||
var command =
|
var command = Cli.Wrap(Dummy.Program.FilePath).WithArguments("cancel-test") | pipeTarget;
|
||||||
Cli.Wrap(Dummy.Program.FilePath).WithArguments("cancel-test") |
|
|
||||||
pipeTarget;
|
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
await Assert.ThrowsAnyAsync<OperationCanceledException>(async () =>
|
await Assert.ThrowsAnyAsync<OperationCanceledException>(
|
||||||
await command.ExecuteAsync(
|
async () =>
|
||||||
// Forceful cancellation (not required because we have a timeout)
|
await command.ExecuteAsync(
|
||||||
CancellationToken.None,
|
// Forceful cancellation (not required because we have a timeout)
|
||||||
// Graceful cancellation
|
CancellationToken.None,
|
||||||
cts.Token
|
// Graceful cancellation
|
||||||
)
|
cts.Token
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
stdOutBuffer.ToString().Trim().Should().ConsistOfLines(
|
stdOutBuffer.ToString().Trim().Should().ConsistOfLines("Started.", "Cancelled.");
|
||||||
"Started.",
|
|
||||||
"Cancelled."
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -111,9 +105,6 @@ public class CancellationSpecs : SpecsBase
|
|||||||
exitCode.Should().NotBe(0);
|
exitCode.Should().NotBe(0);
|
||||||
|
|
||||||
var stdOut = FakeConsole.ReadOutputString();
|
var stdOut = FakeConsole.ReadOutputString();
|
||||||
stdOut.Trim().Should().ConsistOfLines(
|
stdOut.Trim().Should().ConsistOfLines("Started.", "Cancelled.");
|
||||||
"Started.",
|
|
||||||
"Cancelled."
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
<PackageReference Include="Basic.Reference.Assemblies.Net70" Version="1.4.2" />
|
<PackageReference Include="Basic.Reference.Assemblies.Net70" Version="1.4.2" />
|
||||||
<PackageReference Include="CliWrap" Version="3.6.4" />
|
<PackageReference Include="CliWrap" Version="3.6.4" />
|
||||||
<PackageReference Include="coverlet.collector" Version="6.0.0" PrivateAssets="all" />
|
<PackageReference Include="coverlet.collector" Version="6.0.0" PrivateAssets="all" />
|
||||||
|
<PackageReference Include="CSharpier.MsBuild" Version="0.25.0" PrivateAssets="all" />
|
||||||
<PackageReference Include="FluentAssertions" Version="6.11.0" />
|
<PackageReference Include="FluentAssertions" Version="6.11.0" />
|
||||||
<PackageReference Include="GitHubActionsTestLogger" Version="2.3.2" PrivateAssets="all" />
|
<PackageReference Include="GitHubActionsTestLogger" Version="2.3.2" PrivateAssets="all" />
|
||||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.6.0" />
|
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.6.0" />
|
||||||
|
|||||||
@@ -17,9 +17,7 @@ namespace CliFx.Tests;
|
|||||||
public class ConsoleSpecs : SpecsBase
|
public class ConsoleSpecs : SpecsBase
|
||||||
{
|
{
|
||||||
public ConsoleSpecs(ITestOutputHelper testOutput)
|
public ConsoleSpecs(ITestOutputHelper testOutput)
|
||||||
: base(testOutput)
|
: base(testOutput) { }
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact(Timeout = 15000)]
|
[Fact(Timeout = 15000)]
|
||||||
public async Task I_can_run_the_application_with_the_default_console_implementation_to_interact_with_the_system_console()
|
public async Task I_can_run_the_application_with_the_default_console_implementation_to_interact_with_the_system_console()
|
||||||
@@ -28,8 +26,7 @@ public class ConsoleSpecs : SpecsBase
|
|||||||
|
|
||||||
// Arrange
|
// Arrange
|
||||||
var command =
|
var command =
|
||||||
"Hello world" |
|
"Hello world" | Cli.Wrap(Dummy.Program.FilePath).WithArguments("console-test");
|
||||||
Cli.Wrap(Dummy.Program.FilePath).WithArguments("console-test");
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = await command.ExecuteBufferedAsync();
|
var result = await command.ExecuteBufferedAsync();
|
||||||
@@ -205,10 +202,6 @@ public class ConsoleSpecs : SpecsBase
|
|||||||
exitCode.Should().Be(0);
|
exitCode.Should().Be(0);
|
||||||
|
|
||||||
var stdOut = FakeConsole.ReadOutputString();
|
var stdOut = FakeConsole.ReadOutputString();
|
||||||
stdOut.Trim().Should().ConsistOfLines(
|
stdOut.Trim().Should().ConsistOfLines("D0", "A", "Backspace");
|
||||||
"D0",
|
|
||||||
"A",
|
|
||||||
"Backspace"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,9 +11,7 @@ namespace CliFx.Tests;
|
|||||||
public class ConversionSpecs : SpecsBase
|
public class ConversionSpecs : SpecsBase
|
||||||
{
|
{
|
||||||
public ConversionSpecs(ITestOutputHelper testOutput)
|
public ConversionSpecs(ITestOutputHelper testOutput)
|
||||||
: base(testOutput)
|
: base(testOutput) { }
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task I_can_bind_a_parameter_or_an_option_to_a_string_property()
|
public async Task I_can_bind_a_parameter_or_an_option_to_a_string_property()
|
||||||
@@ -44,7 +42,7 @@ public class ConversionSpecs : SpecsBase
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
var exitCode = await application.RunAsync(
|
var exitCode = await application.RunAsync(
|
||||||
new[] {"-f", "xyz"},
|
new[] { "-f", "xyz" },
|
||||||
new Dictionary<string, string>()
|
new Dictionary<string, string>()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -84,7 +82,7 @@ public class ConversionSpecs : SpecsBase
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
var exitCode = await application.RunAsync(
|
var exitCode = await application.RunAsync(
|
||||||
new[] {"-f", "xyz"},
|
new[] { "-f", "xyz" },
|
||||||
new Dictionary<string, string>()
|
new Dictionary<string, string>()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -133,12 +131,7 @@ public class ConversionSpecs : SpecsBase
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
var exitCode = await application.RunAsync(
|
var exitCode = await application.RunAsync(
|
||||||
new[]
|
new[] { "-f", "true", "-b", "false", "-c" },
|
||||||
{
|
|
||||||
"-f", "true",
|
|
||||||
"-b", "false",
|
|
||||||
"-c"
|
|
||||||
},
|
|
||||||
new Dictionary<string, string>()
|
new Dictionary<string, string>()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -146,11 +139,7 @@ public class ConversionSpecs : SpecsBase
|
|||||||
exitCode.Should().Be(0);
|
exitCode.Should().Be(0);
|
||||||
|
|
||||||
var stdOut = FakeConsole.ReadOutputString();
|
var stdOut = FakeConsole.ReadOutputString();
|
||||||
stdOut.Should().ConsistOfLines(
|
stdOut.Should().ConsistOfLines("Foo = True", "Bar = False", "Baz = True");
|
||||||
"Foo = True",
|
|
||||||
"Bar = False",
|
|
||||||
"Baz = True"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -182,7 +171,7 @@ public class ConversionSpecs : SpecsBase
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
var exitCode = await application.RunAsync(
|
var exitCode = await application.RunAsync(
|
||||||
new[] {"-f", "32"},
|
new[] { "-f", "32" },
|
||||||
new Dictionary<string, string>()
|
new Dictionary<string, string>()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -222,7 +211,7 @@ public class ConversionSpecs : SpecsBase
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
var exitCode = await application.RunAsync(
|
var exitCode = await application.RunAsync(
|
||||||
new[] {"-f", "32.14"},
|
new[] { "-f", "32.14" },
|
||||||
new Dictionary<string, string>()
|
new Dictionary<string, string>()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -262,7 +251,7 @@ public class ConversionSpecs : SpecsBase
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
var exitCode = await application.RunAsync(
|
var exitCode = await application.RunAsync(
|
||||||
new[] {"-f", "1995-04-28Z"},
|
new[] { "-f", "1995-04-28Z" },
|
||||||
new Dictionary<string, string>()
|
new Dictionary<string, string>()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -302,7 +291,7 @@ public class ConversionSpecs : SpecsBase
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
var exitCode = await application.RunAsync(
|
var exitCode = await application.RunAsync(
|
||||||
new[] {"-f", "12:34:56"},
|
new[] { "-f", "12:34:56" },
|
||||||
new Dictionary<string, string>()
|
new Dictionary<string, string>()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -344,7 +333,7 @@ public class ConversionSpecs : SpecsBase
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
var exitCode = await application.RunAsync(
|
var exitCode = await application.RunAsync(
|
||||||
new[] {"-f", "two"},
|
new[] { "-f", "two" },
|
||||||
new Dictionary<string, string>()
|
new Dictionary<string, string>()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -389,7 +378,7 @@ public class ConversionSpecs : SpecsBase
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
var exitCode = await application.RunAsync(
|
var exitCode = await application.RunAsync(
|
||||||
new[] {"-b", "123"},
|
new[] { "-b", "123" },
|
||||||
new Dictionary<string, string>()
|
new Dictionary<string, string>()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -397,10 +386,7 @@ public class ConversionSpecs : SpecsBase
|
|||||||
exitCode.Should().Be(0);
|
exitCode.Should().Be(0);
|
||||||
|
|
||||||
var stdOut = FakeConsole.ReadOutputString();
|
var stdOut = FakeConsole.ReadOutputString();
|
||||||
stdOut.Should().ConsistOfLines(
|
stdOut.Should().ConsistOfLines("Foo = ", "Bar = 123");
|
||||||
"Foo = ",
|
|
||||||
"Bar = 123"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -439,7 +425,7 @@ public class ConversionSpecs : SpecsBase
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
var exitCode = await application.RunAsync(
|
var exitCode = await application.RunAsync(
|
||||||
new[] {"-b", "two"},
|
new[] { "-b", "two" },
|
||||||
new Dictionary<string, string>()
|
new Dictionary<string, string>()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -447,10 +433,7 @@ public class ConversionSpecs : SpecsBase
|
|||||||
exitCode.Should().Be(0);
|
exitCode.Should().Be(0);
|
||||||
|
|
||||||
var stdOut = FakeConsole.ReadOutputString();
|
var stdOut = FakeConsole.ReadOutputString();
|
||||||
stdOut.Should().ConsistOfLines(
|
stdOut.Should().ConsistOfLines("Foo = ", "Bar = 2");
|
||||||
"Foo = ",
|
|
||||||
"Bar = 2"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -489,7 +472,7 @@ public class ConversionSpecs : SpecsBase
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
var exitCode = await application.RunAsync(
|
var exitCode = await application.RunAsync(
|
||||||
new[] {"-f", "xyz"},
|
new[] { "-f", "xyz" },
|
||||||
new Dictionary<string, string>()
|
new Dictionary<string, string>()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -554,7 +537,7 @@ public class ConversionSpecs : SpecsBase
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
var exitCode = await application.RunAsync(
|
var exitCode = await application.RunAsync(
|
||||||
new[] {"-f", "hello", "-b", "world"},
|
new[] { "-f", "hello", "-b", "world" },
|
||||||
new Dictionary<string, string>()
|
new Dictionary<string, string>()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -562,10 +545,7 @@ public class ConversionSpecs : SpecsBase
|
|||||||
exitCode.Should().Be(0);
|
exitCode.Should().Be(0);
|
||||||
|
|
||||||
var stdOut = FakeConsole.ReadOutputString();
|
var stdOut = FakeConsole.ReadOutputString();
|
||||||
stdOut.Should().ConsistOfLines(
|
stdOut.Should().ConsistOfLines("Foo = hello", "Bar = world");
|
||||||
"Foo = hello",
|
|
||||||
"Bar = world"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -603,7 +583,7 @@ public class ConversionSpecs : SpecsBase
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
var exitCode = await application.RunAsync(
|
var exitCode = await application.RunAsync(
|
||||||
new[] {"-f", "hello world"},
|
new[] { "-f", "hello world" },
|
||||||
new Dictionary<string, string>()
|
new Dictionary<string, string>()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -645,7 +625,7 @@ public class ConversionSpecs : SpecsBase
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
var exitCode = await application.RunAsync(
|
var exitCode = await application.RunAsync(
|
||||||
new[] {"-f", "one", "two", "three"},
|
new[] { "-f", "one", "two", "three" },
|
||||||
new Dictionary<string, string>()
|
new Dictionary<string, string>()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -653,11 +633,7 @@ public class ConversionSpecs : SpecsBase
|
|||||||
exitCode.Should().Be(0);
|
exitCode.Should().Be(0);
|
||||||
|
|
||||||
var stdOut = FakeConsole.ReadOutputString();
|
var stdOut = FakeConsole.ReadOutputString();
|
||||||
stdOut.Should().ConsistOfLines(
|
stdOut.Should().ConsistOfLines("one", "two", "three");
|
||||||
"one",
|
|
||||||
"two",
|
|
||||||
"three"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -691,7 +667,7 @@ public class ConversionSpecs : SpecsBase
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
var exitCode = await application.RunAsync(
|
var exitCode = await application.RunAsync(
|
||||||
new[] {"-f", "one", "two", "three"},
|
new[] { "-f", "one", "two", "three" },
|
||||||
new Dictionary<string, string>()
|
new Dictionary<string, string>()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -699,11 +675,7 @@ public class ConversionSpecs : SpecsBase
|
|||||||
exitCode.Should().Be(0);
|
exitCode.Should().Be(0);
|
||||||
|
|
||||||
var stdOut = FakeConsole.ReadOutputString();
|
var stdOut = FakeConsole.ReadOutputString();
|
||||||
stdOut.Should().ConsistOfLines(
|
stdOut.Should().ConsistOfLines("one", "two", "three");
|
||||||
"one",
|
|
||||||
"two",
|
|
||||||
"three"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -737,7 +709,7 @@ public class ConversionSpecs : SpecsBase
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
var exitCode = await application.RunAsync(
|
var exitCode = await application.RunAsync(
|
||||||
new[] {"-f", "one", "two", "three"},
|
new[] { "-f", "one", "two", "three" },
|
||||||
new Dictionary<string, string>()
|
new Dictionary<string, string>()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -745,11 +717,7 @@ public class ConversionSpecs : SpecsBase
|
|||||||
exitCode.Should().Be(0);
|
exitCode.Should().Be(0);
|
||||||
|
|
||||||
var stdOut = FakeConsole.ReadOutputString();
|
var stdOut = FakeConsole.ReadOutputString();
|
||||||
stdOut.Should().ConsistOfLines(
|
stdOut.Should().ConsistOfLines("one", "two", "three");
|
||||||
"one",
|
|
||||||
"two",
|
|
||||||
"three"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -783,7 +751,7 @@ public class ConversionSpecs : SpecsBase
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
var exitCode = await application.RunAsync(
|
var exitCode = await application.RunAsync(
|
||||||
new[] {"-f", "1", "13", "27"},
|
new[] { "-f", "1", "13", "27" },
|
||||||
new Dictionary<string, string>()
|
new Dictionary<string, string>()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -791,11 +759,7 @@ public class ConversionSpecs : SpecsBase
|
|||||||
exitCode.Should().Be(0);
|
exitCode.Should().Be(0);
|
||||||
|
|
||||||
var stdOut = FakeConsole.ReadOutputString();
|
var stdOut = FakeConsole.ReadOutputString();
|
||||||
stdOut.Should().ConsistOfLines(
|
stdOut.Should().ConsistOfLines("1", "13", "27");
|
||||||
"1",
|
|
||||||
"13",
|
|
||||||
"27"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -827,7 +791,7 @@ public class ConversionSpecs : SpecsBase
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
var exitCode = await application.RunAsync(
|
var exitCode = await application.RunAsync(
|
||||||
new[] {"-f", "xyz"},
|
new[] { "-f", "xyz" },
|
||||||
new Dictionary<string, string>()
|
new Dictionary<string, string>()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -870,7 +834,7 @@ public class ConversionSpecs : SpecsBase
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
var exitCode = await application.RunAsync(
|
var exitCode = await application.RunAsync(
|
||||||
new[] {"-f", "one", "two"},
|
new[] { "-f", "one", "two" },
|
||||||
new Dictionary<string, string>()
|
new Dictionary<string, string>()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -906,7 +870,7 @@ public class ConversionSpecs : SpecsBase
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
var exitCode = await application.RunAsync(
|
var exitCode = await application.RunAsync(
|
||||||
new[] {"-f", "12.34"},
|
new[] { "-f", "12.34" },
|
||||||
new Dictionary<string, string>()
|
new Dictionary<string, string>()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -952,7 +916,7 @@ public class ConversionSpecs : SpecsBase
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
var exitCode = await application.RunAsync(
|
var exitCode = await application.RunAsync(
|
||||||
new[] {"-f", "12"},
|
new[] { "-f", "12" },
|
||||||
new Dictionary<string, string>()
|
new Dictionary<string, string>()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -997,7 +961,7 @@ public class ConversionSpecs : SpecsBase
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
var exitCode = await application.RunAsync(
|
var exitCode = await application.RunAsync(
|
||||||
new[] {"-f", "bar"},
|
new[] { "-f", "bar" },
|
||||||
new Dictionary<string, string>()
|
new Dictionary<string, string>()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -1007,4 +971,4 @@ public class ConversionSpecs : SpecsBase
|
|||||||
var stdErr = FakeConsole.ReadErrorString();
|
var stdErr = FakeConsole.ReadErrorString();
|
||||||
stdErr.Should().Contain("Hello world");
|
stdErr.Should().Contain("Hello world");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,9 +14,7 @@ namespace CliFx.Tests;
|
|||||||
public class DirectivesSpecs : SpecsBase
|
public class DirectivesSpecs : SpecsBase
|
||||||
{
|
{
|
||||||
public DirectivesSpecs(ITestOutputHelper testOutput)
|
public DirectivesSpecs(ITestOutputHelper testOutput)
|
||||||
: base(testOutput)
|
: base(testOutput) { }
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact(Timeout = 15000)]
|
[Fact(Timeout = 15000)]
|
||||||
public async Task I_can_use_the_debug_directive_to_make_the_application_wait_for_the_debugger_to_attach()
|
public async Task I_can_use_the_debug_directive_to_make_the_application_wait_for_the_debugger_to_attach()
|
||||||
@@ -32,9 +30,7 @@ public class DirectivesSpecs : SpecsBase
|
|||||||
cts.Cancel();
|
cts.Cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
var command =
|
var command = Cli.Wrap(Dummy.Program.FilePath).WithArguments("[debug]") | HandleStdOut;
|
||||||
Cli.Wrap(Dummy.Program.FilePath).WithArguments("[debug]") |
|
|
||||||
HandleStdOut;
|
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
try
|
try
|
||||||
@@ -70,22 +66,29 @@ public class DirectivesSpecs : SpecsBase
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
var exitCode = await application.RunAsync(
|
var exitCode = await application.RunAsync(
|
||||||
new[] {"[preview]", "cmd", "param", "-abc", "--option", "foo"},
|
new[] { "[preview]", "cmd", "param", "-abc", "--option", "foo" },
|
||||||
new Dictionary<string, string>
|
new Dictionary<string, string> { ["ENV_QOP"] = "hello", ["ENV_KIL"] = "world" }
|
||||||
{
|
|
||||||
["ENV_QOP"] = "hello",
|
|
||||||
["ENV_KIL"] = "world"
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
exitCode.Should().Be(0);
|
exitCode.Should().Be(0);
|
||||||
|
|
||||||
var stdOut = FakeConsole.ReadOutputString();
|
var stdOut = FakeConsole.ReadOutputString();
|
||||||
stdOut.Should().ContainAllInOrder(
|
stdOut
|
||||||
"cmd", "<param>", "[-a]", "[-b]", "[-c]", "[--option \"foo\"]",
|
.Should()
|
||||||
"ENV_QOP", "=", "\"hello\"",
|
.ContainAllInOrder(
|
||||||
"ENV_KIL", "=", "\"world\""
|
"cmd",
|
||||||
);
|
"<param>",
|
||||||
|
"[-a]",
|
||||||
|
"[-b]",
|
||||||
|
"[-c]",
|
||||||
|
"[--option \"foo\"]",
|
||||||
|
"ENV_QOP",
|
||||||
|
"=",
|
||||||
|
"\"hello\"",
|
||||||
|
"ENV_KIL",
|
||||||
|
"=",
|
||||||
|
"\"world\""
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,9 +15,7 @@ namespace CliFx.Tests;
|
|||||||
public class EnvironmentSpecs : SpecsBase
|
public class EnvironmentSpecs : SpecsBase
|
||||||
{
|
{
|
||||||
public EnvironmentSpecs(ITestOutputHelper testOutput)
|
public EnvironmentSpecs(ITestOutputHelper testOutput)
|
||||||
: base(testOutput)
|
: base(testOutput) { }
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task I_can_configure_an_option_to_fall_back_to_an_environment_variable_if_the_user_does_not_provide_the_corresponding_argument()
|
public async Task I_can_configure_an_option_to_fall_back_to_an_environment_variable_if_the_user_does_not_provide_the_corresponding_argument()
|
||||||
@@ -53,22 +51,15 @@ public class EnvironmentSpecs : SpecsBase
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
var exitCode = await application.RunAsync(
|
var exitCode = await application.RunAsync(
|
||||||
new[] {"--foo", "42"},
|
new[] { "--foo", "42" },
|
||||||
new Dictionary<string, string>
|
new Dictionary<string, string> { ["ENV_FOO"] = "100", ["ENV_BAR"] = "200" }
|
||||||
{
|
|
||||||
["ENV_FOO"] = "100",
|
|
||||||
["ENV_BAR"] = "200"
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
exitCode.Should().Be(0);
|
exitCode.Should().Be(0);
|
||||||
|
|
||||||
var stdOut = FakeConsole.ReadOutputString();
|
var stdOut = FakeConsole.ReadOutputString();
|
||||||
stdOut.Trim().Should().ConsistOfLines(
|
stdOut.Trim().Should().ConsistOfLines("42", "200");
|
||||||
"42",
|
|
||||||
"200"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -103,20 +94,14 @@ public class EnvironmentSpecs : SpecsBase
|
|||||||
// Act
|
// Act
|
||||||
var exitCode = await application.RunAsync(
|
var exitCode = await application.RunAsync(
|
||||||
Array.Empty<string>(),
|
Array.Empty<string>(),
|
||||||
new Dictionary<string, string>
|
new Dictionary<string, string> { ["ENV_FOO"] = $"bar{Path.PathSeparator}baz" }
|
||||||
{
|
|
||||||
["ENV_FOO"] = $"bar{Path.PathSeparator}baz"
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
exitCode.Should().Be(0);
|
exitCode.Should().Be(0);
|
||||||
|
|
||||||
var stdOut = FakeConsole.ReadOutputString();
|
var stdOut = FakeConsole.ReadOutputString();
|
||||||
stdOut.Should().ConsistOfLines(
|
stdOut.Should().ConsistOfLines("bar", "baz");
|
||||||
"bar",
|
|
||||||
"baz"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -149,10 +134,7 @@ public class EnvironmentSpecs : SpecsBase
|
|||||||
// Act
|
// Act
|
||||||
var exitCode = await application.RunAsync(
|
var exitCode = await application.RunAsync(
|
||||||
Array.Empty<string>(),
|
Array.Empty<string>(),
|
||||||
new Dictionary<string, string>
|
new Dictionary<string, string> { ["ENV_FOO"] = $"bar{Path.PathSeparator}baz" }
|
||||||
{
|
|
||||||
["ENV_FOO"] = $"bar{Path.PathSeparator}baz"
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
@@ -171,9 +153,7 @@ public class EnvironmentSpecs : SpecsBase
|
|||||||
// Arrange
|
// Arrange
|
||||||
var command = Cli.Wrap(Dummy.Program.FilePath)
|
var command = Cli.Wrap(Dummy.Program.FilePath)
|
||||||
.WithArguments("env-test")
|
.WithArguments("env-test")
|
||||||
.WithEnvironmentVariables(e => e
|
.WithEnvironmentVariables(e => e.Set("ENV_TARGET", "Mars"));
|
||||||
.Set("ENV_TARGET", "Mars")
|
|
||||||
);
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = await command.ExecuteBufferedAsync();
|
var result = await command.ExecuteBufferedAsync();
|
||||||
@@ -181,4 +161,4 @@ public class EnvironmentSpecs : SpecsBase
|
|||||||
// Assert
|
// Assert
|
||||||
result.StandardOutput.Trim().Should().Be("Hello Mars!");
|
result.StandardOutput.Trim().Should().Be("Hello Mars!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,9 +12,7 @@ namespace CliFx.Tests;
|
|||||||
public class ErrorReportingSpecs : SpecsBase
|
public class ErrorReportingSpecs : SpecsBase
|
||||||
{
|
{
|
||||||
public ErrorReportingSpecs(ITestOutputHelper testOutput)
|
public ErrorReportingSpecs(ITestOutputHelper testOutput)
|
||||||
: base(testOutput)
|
: base(testOutput) { }
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task I_can_throw_an_exception_in_a_command_to_report_an_error_with_a_stacktrace()
|
public async Task I_can_throw_an_exception_in_a_command_to_report_an_error_with_a_stacktrace()
|
||||||
@@ -50,10 +48,9 @@ public class ErrorReportingSpecs : SpecsBase
|
|||||||
stdOut.Should().BeEmpty();
|
stdOut.Should().BeEmpty();
|
||||||
|
|
||||||
var stdErr = FakeConsole.ReadErrorString();
|
var stdErr = FakeConsole.ReadErrorString();
|
||||||
stdErr.Should().ContainAllInOrder(
|
stdErr
|
||||||
"System.Exception", "Something went wrong",
|
.Should()
|
||||||
"at", "CliFx."
|
.ContainAllInOrder("System.Exception", "Something went wrong", "at", "CliFx.");
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -90,11 +87,16 @@ public class ErrorReportingSpecs : SpecsBase
|
|||||||
stdOut.Should().BeEmpty();
|
stdOut.Should().BeEmpty();
|
||||||
|
|
||||||
var stdErr = FakeConsole.ReadErrorString();
|
var stdErr = FakeConsole.ReadErrorString();
|
||||||
stdErr.Should().ContainAllInOrder(
|
stdErr
|
||||||
"System.Exception", "Something went wrong",
|
.Should()
|
||||||
"System.Exception", "Another exception",
|
.ContainAllInOrder(
|
||||||
"at", "CliFx."
|
"System.Exception",
|
||||||
);
|
"Something went wrong",
|
||||||
|
"System.Exception",
|
||||||
|
"Another exception",
|
||||||
|
"at",
|
||||||
|
"CliFx."
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -168,10 +170,7 @@ public class ErrorReportingSpecs : SpecsBase
|
|||||||
stdOut.Should().BeEmpty();
|
stdOut.Should().BeEmpty();
|
||||||
|
|
||||||
var stdErr = FakeConsole.ReadErrorString();
|
var stdErr = FakeConsole.ReadErrorString();
|
||||||
stdErr.Should().ContainAllInOrder(
|
stdErr.Should().ContainAllInOrder("CliFx.Exceptions.CommandException", "at", "CliFx.");
|
||||||
"CliFx.Exceptions.CommandException",
|
|
||||||
"at", "CliFx."
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -211,4 +210,4 @@ public class ErrorReportingSpecs : SpecsBase
|
|||||||
var stdErr = FakeConsole.ReadErrorString();
|
var stdErr = FakeConsole.ReadErrorString();
|
||||||
stdErr.Trim().Should().Be("Something went wrong");
|
stdErr.Trim().Should().Be("Something went wrong");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,9 +12,7 @@ namespace CliFx.Tests;
|
|||||||
public class HelpTextSpecs : SpecsBase
|
public class HelpTextSpecs : SpecsBase
|
||||||
{
|
{
|
||||||
public HelpTextSpecs(ITestOutputHelper testOutput)
|
public HelpTextSpecs(ITestOutputHelper testOutput)
|
||||||
: base(testOutput)
|
: base(testOutput) { }
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task I_can_request_the_help_text_by_running_the_application_without_arguments_if_the_default_command_is_not_defined()
|
public async Task I_can_request_the_help_text_by_running_the_application_without_arguments_if_the_default_command_is_not_defined()
|
||||||
@@ -61,7 +59,7 @@ public class HelpTextSpecs : SpecsBase
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
var exitCode = await application.RunAsync(
|
var exitCode = await application.RunAsync(
|
||||||
new[] {"--help"},
|
new[] { "--help" },
|
||||||
new Dictionary<string, string>()
|
new Dictionary<string, string>()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -101,7 +99,7 @@ public class HelpTextSpecs : SpecsBase
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
var exitCode = await application.RunAsync(
|
var exitCode = await application.RunAsync(
|
||||||
new[] {"--help"},
|
new[] { "--help" },
|
||||||
new Dictionary<string, string>()
|
new Dictionary<string, string>()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -146,7 +144,7 @@ public class HelpTextSpecs : SpecsBase
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
var exitCode = await application.RunAsync(
|
var exitCode = await application.RunAsync(
|
||||||
new[] {"cmd", "--help"},
|
new[] { "cmd", "--help" },
|
||||||
new Dictionary<string, string>()
|
new Dictionary<string, string>()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -191,7 +189,7 @@ public class HelpTextSpecs : SpecsBase
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
var exitCode = await application.RunAsync(
|
var exitCode = await application.RunAsync(
|
||||||
new[] {"cmd", "sub", "--help"},
|
new[] { "cmd", "sub", "--help" },
|
||||||
new Dictionary<string, string>()
|
new Dictionary<string, string>()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -214,7 +212,7 @@ public class HelpTextSpecs : SpecsBase
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
var exitCode = await application.RunAsync(
|
var exitCode = await application.RunAsync(
|
||||||
new[] {"invalid-command", "--invalid-option"},
|
new[] { "invalid-command", "--invalid-option" },
|
||||||
new Dictionary<string, string>()
|
new Dictionary<string, string>()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -241,7 +239,7 @@ public class HelpTextSpecs : SpecsBase
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
var exitCode = await application.RunAsync(
|
var exitCode = await application.RunAsync(
|
||||||
new[] {"--help"},
|
new[] { "--help" },
|
||||||
new Dictionary<string, string>()
|
new Dictionary<string, string>()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -249,11 +247,7 @@ public class HelpTextSpecs : SpecsBase
|
|||||||
exitCode.Should().Be(0);
|
exitCode.Should().Be(0);
|
||||||
|
|
||||||
var stdOut = FakeConsole.ReadOutputString();
|
var stdOut = FakeConsole.ReadOutputString();
|
||||||
stdOut.Should().ContainAll(
|
stdOut.Should().ContainAll("App title", "App description", "App version");
|
||||||
"App title",
|
|
||||||
"App description",
|
|
||||||
"App version"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -278,7 +272,7 @@ public class HelpTextSpecs : SpecsBase
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
var exitCode = await application.RunAsync(
|
var exitCode = await application.RunAsync(
|
||||||
new[] {"--help"},
|
new[] { "--help" },
|
||||||
new Dictionary<string, string>()
|
new Dictionary<string, string>()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -286,10 +280,7 @@ public class HelpTextSpecs : SpecsBase
|
|||||||
exitCode.Should().Be(0);
|
exitCode.Should().Be(0);
|
||||||
|
|
||||||
var stdOut = FakeConsole.ReadOutputString();
|
var stdOut = FakeConsole.ReadOutputString();
|
||||||
stdOut.Should().ContainAllInOrder(
|
stdOut.Should().ContainAllInOrder("DESCRIPTION", "Description of the default command.");
|
||||||
"DESCRIPTION",
|
|
||||||
"Description of the default command."
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -320,7 +311,7 @@ public class HelpTextSpecs : SpecsBase
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
var exitCode = await application.RunAsync(
|
var exitCode = await application.RunAsync(
|
||||||
new[] {"--help"},
|
new[] { "--help" },
|
||||||
new Dictionary<string, string>()
|
new Dictionary<string, string>()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -328,10 +319,7 @@ public class HelpTextSpecs : SpecsBase
|
|||||||
exitCode.Should().Be(0);
|
exitCode.Should().Be(0);
|
||||||
|
|
||||||
var stdOut = FakeConsole.ReadOutputString();
|
var stdOut = FakeConsole.ReadOutputString();
|
||||||
stdOut.Should().ContainAllInOrder(
|
stdOut.Should().ContainAllInOrder("USAGE", "[command]", "[...]");
|
||||||
"USAGE",
|
|
||||||
"[command]", "[...]"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -365,7 +353,7 @@ public class HelpTextSpecs : SpecsBase
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
var exitCode = await application.RunAsync(
|
var exitCode = await application.RunAsync(
|
||||||
new[] {"--help"},
|
new[] { "--help" },
|
||||||
new Dictionary<string, string>()
|
new Dictionary<string, string>()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -373,10 +361,7 @@ public class HelpTextSpecs : SpecsBase
|
|||||||
exitCode.Should().Be(0);
|
exitCode.Should().Be(0);
|
||||||
|
|
||||||
var stdOut = FakeConsole.ReadOutputString();
|
var stdOut = FakeConsole.ReadOutputString();
|
||||||
stdOut.Should().ContainAllInOrder(
|
stdOut.Should().ContainAllInOrder("USAGE", "<foo>", "<bar>", "<baz...>");
|
||||||
"USAGE",
|
|
||||||
"<foo>", "<bar>", "<baz...>"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://github.com/Tyrrrz/CliFx/issues/117
|
// https://github.com/Tyrrrz/CliFx/issues/117
|
||||||
@@ -425,10 +410,7 @@ public class HelpTextSpecs : SpecsBase
|
|||||||
exitCode.Should().Be(0);
|
exitCode.Should().Be(0);
|
||||||
|
|
||||||
var stdOut = FakeConsole.ReadOutputString();
|
var stdOut = FakeConsole.ReadOutputString();
|
||||||
stdOut.Should().ContainAllInOrder(
|
stdOut.Should().ContainAllInOrder("USAGE", "<foo>", "<bar>", "<baz...>");
|
||||||
"USAGE",
|
|
||||||
"<foo>", "<bar>", "<baz...>"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -462,7 +444,7 @@ public class HelpTextSpecs : SpecsBase
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
var exitCode = await application.RunAsync(
|
var exitCode = await application.RunAsync(
|
||||||
new[] {"--help"},
|
new[] { "--help" },
|
||||||
new Dictionary<string, string>()
|
new Dictionary<string, string>()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -470,10 +452,9 @@ public class HelpTextSpecs : SpecsBase
|
|||||||
exitCode.Should().Be(0);
|
exitCode.Should().Be(0);
|
||||||
|
|
||||||
var stdOut = FakeConsole.ReadOutputString();
|
var stdOut = FakeConsole.ReadOutputString();
|
||||||
stdOut.Should().ContainAllInOrder(
|
stdOut
|
||||||
"USAGE",
|
.Should()
|
||||||
"--foo <value>", "--baz <values...>", "[options]"
|
.ContainAllInOrder("USAGE", "--foo <value>", "--baz <values...>", "[options]");
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -504,7 +485,7 @@ public class HelpTextSpecs : SpecsBase
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
var exitCode = await application.RunAsync(
|
var exitCode = await application.RunAsync(
|
||||||
new[] {"--help"},
|
new[] { "--help" },
|
||||||
new Dictionary<string, string>()
|
new Dictionary<string, string>()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -512,12 +493,16 @@ public class HelpTextSpecs : SpecsBase
|
|||||||
exitCode.Should().Be(0);
|
exitCode.Should().Be(0);
|
||||||
|
|
||||||
var stdOut = FakeConsole.ReadOutputString();
|
var stdOut = FakeConsole.ReadOutputString();
|
||||||
stdOut.Should().ContainAllInOrder(
|
stdOut
|
||||||
"PARAMETERS",
|
.Should()
|
||||||
"foo", "Description of foo.",
|
.ContainAllInOrder(
|
||||||
"OPTIONS",
|
"PARAMETERS",
|
||||||
"--bar", "Description of bar."
|
"foo",
|
||||||
);
|
"Description of foo.",
|
||||||
|
"OPTIONS",
|
||||||
|
"--bar",
|
||||||
|
"Description of bar."
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -542,7 +527,7 @@ public class HelpTextSpecs : SpecsBase
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
var exitCode = await application.RunAsync(
|
var exitCode = await application.RunAsync(
|
||||||
new[] {"--help"},
|
new[] { "--help" },
|
||||||
new Dictionary<string, string>()
|
new Dictionary<string, string>()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -550,11 +535,16 @@ public class HelpTextSpecs : SpecsBase
|
|||||||
exitCode.Should().Be(0);
|
exitCode.Should().Be(0);
|
||||||
|
|
||||||
var stdOut = FakeConsole.ReadOutputString();
|
var stdOut = FakeConsole.ReadOutputString();
|
||||||
stdOut.Should().ContainAllInOrder(
|
stdOut
|
||||||
"OPTIONS",
|
.Should()
|
||||||
"-h", "--help", "Shows help text",
|
.ContainAllInOrder(
|
||||||
"--version", "Shows version information"
|
"OPTIONS",
|
||||||
);
|
"-h",
|
||||||
|
"--help",
|
||||||
|
"Shows help text",
|
||||||
|
"--version",
|
||||||
|
"Shows version information"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -579,7 +569,7 @@ public class HelpTextSpecs : SpecsBase
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
var exitCode = await application.RunAsync(
|
var exitCode = await application.RunAsync(
|
||||||
new[] {"cmd", "--help"},
|
new[] { "cmd", "--help" },
|
||||||
new Dictionary<string, string>()
|
new Dictionary<string, string>()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -588,14 +578,9 @@ public class HelpTextSpecs : SpecsBase
|
|||||||
|
|
||||||
var stdOut = FakeConsole.ReadOutputString();
|
var stdOut = FakeConsole.ReadOutputString();
|
||||||
|
|
||||||
stdOut.Should().ContainAllInOrder(
|
stdOut.Should().ContainAllInOrder("OPTIONS", "-h", "--help", "Shows help text");
|
||||||
"OPTIONS",
|
|
||||||
"-h", "--help", "Shows help text"
|
|
||||||
);
|
|
||||||
|
|
||||||
stdOut.Should().NotContainAny(
|
stdOut.Should().NotContainAny("--version", "Shows version information");
|
||||||
"--version", "Shows version information"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -628,7 +613,7 @@ public class HelpTextSpecs : SpecsBase
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
var exitCode = await application.RunAsync(
|
var exitCode = await application.RunAsync(
|
||||||
new[] {"--help"},
|
new[] { "--help" },
|
||||||
new Dictionary<string, string>()
|
new Dictionary<string, string>()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -636,12 +621,22 @@ public class HelpTextSpecs : SpecsBase
|
|||||||
exitCode.Should().Be(0);
|
exitCode.Should().Be(0);
|
||||||
|
|
||||||
var stdOut = FakeConsole.ReadOutputString();
|
var stdOut = FakeConsole.ReadOutputString();
|
||||||
stdOut.Should().ContainAllInOrder(
|
stdOut
|
||||||
"PARAMETERS",
|
.Should()
|
||||||
"foo", "Choices:", "One", "Two", "Three",
|
.ContainAllInOrder(
|
||||||
"OPTIONS",
|
"PARAMETERS",
|
||||||
"--bar", "Choices:", "One", "Two", "Three"
|
"foo",
|
||||||
);
|
"Choices:",
|
||||||
|
"One",
|
||||||
|
"Two",
|
||||||
|
"Three",
|
||||||
|
"OPTIONS",
|
||||||
|
"--bar",
|
||||||
|
"Choices:",
|
||||||
|
"One",
|
||||||
|
"Two",
|
||||||
|
"Three"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -674,7 +669,7 @@ public class HelpTextSpecs : SpecsBase
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
var exitCode = await application.RunAsync(
|
var exitCode = await application.RunAsync(
|
||||||
new[] {"--help"},
|
new[] { "--help" },
|
||||||
new Dictionary<string, string>()
|
new Dictionary<string, string>()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -682,12 +677,22 @@ public class HelpTextSpecs : SpecsBase
|
|||||||
exitCode.Should().Be(0);
|
exitCode.Should().Be(0);
|
||||||
|
|
||||||
var stdOut = FakeConsole.ReadOutputString();
|
var stdOut = FakeConsole.ReadOutputString();
|
||||||
stdOut.Should().ContainAllInOrder(
|
stdOut
|
||||||
"PARAMETERS",
|
.Should()
|
||||||
"foo", "Choices:", "One", "Two", "Three",
|
.ContainAllInOrder(
|
||||||
"OPTIONS",
|
"PARAMETERS",
|
||||||
"--bar", "Choices:", "One", "Two", "Three"
|
"foo",
|
||||||
);
|
"Choices:",
|
||||||
|
"One",
|
||||||
|
"Two",
|
||||||
|
"Three",
|
||||||
|
"OPTIONS",
|
||||||
|
"--bar",
|
||||||
|
"Choices:",
|
||||||
|
"One",
|
||||||
|
"Two",
|
||||||
|
"Three"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -720,7 +725,7 @@ public class HelpTextSpecs : SpecsBase
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
var exitCode = await application.RunAsync(
|
var exitCode = await application.RunAsync(
|
||||||
new[] {"--help"},
|
new[] { "--help" },
|
||||||
new Dictionary<string, string>()
|
new Dictionary<string, string>()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -728,12 +733,22 @@ public class HelpTextSpecs : SpecsBase
|
|||||||
exitCode.Should().Be(0);
|
exitCode.Should().Be(0);
|
||||||
|
|
||||||
var stdOut = FakeConsole.ReadOutputString();
|
var stdOut = FakeConsole.ReadOutputString();
|
||||||
stdOut.Should().ContainAllInOrder(
|
stdOut
|
||||||
"PARAMETERS",
|
.Should()
|
||||||
"foo", "Choices:", "One", "Two", "Three",
|
.ContainAllInOrder(
|
||||||
"OPTIONS",
|
"PARAMETERS",
|
||||||
"--bar", "Choices:", "One", "Two", "Three"
|
"foo",
|
||||||
);
|
"Choices:",
|
||||||
|
"One",
|
||||||
|
"Two",
|
||||||
|
"Three",
|
||||||
|
"OPTIONS",
|
||||||
|
"--bar",
|
||||||
|
"Choices:",
|
||||||
|
"One",
|
||||||
|
"Two",
|
||||||
|
"Three"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -766,7 +781,7 @@ public class HelpTextSpecs : SpecsBase
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
var exitCode = await application.RunAsync(
|
var exitCode = await application.RunAsync(
|
||||||
new[] {"--help"},
|
new[] { "--help" },
|
||||||
new Dictionary<string, string>()
|
new Dictionary<string, string>()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -774,11 +789,17 @@ public class HelpTextSpecs : SpecsBase
|
|||||||
exitCode.Should().Be(0);
|
exitCode.Should().Be(0);
|
||||||
|
|
||||||
var stdOut = FakeConsole.ReadOutputString();
|
var stdOut = FakeConsole.ReadOutputString();
|
||||||
stdOut.Should().ContainAllInOrder(
|
stdOut
|
||||||
"OPTIONS",
|
.Should()
|
||||||
"--foo", "Environment variable:", "ENV_FOO",
|
.ContainAllInOrder(
|
||||||
"--bar", "Environment variable:", "ENV_BAR"
|
"OPTIONS",
|
||||||
);
|
"--foo",
|
||||||
|
"Environment variable:",
|
||||||
|
"ENV_FOO",
|
||||||
|
"--bar",
|
||||||
|
"Environment variable:",
|
||||||
|
"ENV_BAR"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -829,7 +850,7 @@ public class HelpTextSpecs : SpecsBase
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
var exitCode = await application.RunAsync(
|
var exitCode = await application.RunAsync(
|
||||||
new[] {"--help"},
|
new[] { "--help" },
|
||||||
new Dictionary<string, string>()
|
new Dictionary<string, string>()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -838,16 +859,34 @@ public class HelpTextSpecs : SpecsBase
|
|||||||
|
|
||||||
var stdOut = FakeConsole.ReadOutputString();
|
var stdOut = FakeConsole.ReadOutputString();
|
||||||
|
|
||||||
stdOut.Should().ContainAllInOrder(
|
stdOut
|
||||||
"OPTIONS",
|
.Should()
|
||||||
"--foo", "Default:", "42",
|
.ContainAllInOrder(
|
||||||
"--bar", "Default:", "hello",
|
"OPTIONS",
|
||||||
"--baz", "Default:", "one", "two", "three",
|
"--foo",
|
||||||
"--qwe", "Default:", "True",
|
"Default:",
|
||||||
"--qop", "Default:", "1337",
|
"42",
|
||||||
"--zor", "Default:", "02:03:00",
|
"--bar",
|
||||||
"--lol", "Default:", "Two"
|
"Default:",
|
||||||
);
|
"hello",
|
||||||
|
"--baz",
|
||||||
|
"Default:",
|
||||||
|
"one",
|
||||||
|
"two",
|
||||||
|
"three",
|
||||||
|
"--qwe",
|
||||||
|
"Default:",
|
||||||
|
"True",
|
||||||
|
"--qop",
|
||||||
|
"Default:",
|
||||||
|
"1337",
|
||||||
|
"--zor",
|
||||||
|
"Default:",
|
||||||
|
"02:03:00",
|
||||||
|
"--lol",
|
||||||
|
"Default:",
|
||||||
|
"Two"
|
||||||
|
);
|
||||||
|
|
||||||
stdOut.Should().NotContain("not printed");
|
stdOut.Should().NotContain("not printed");
|
||||||
}
|
}
|
||||||
@@ -892,7 +931,7 @@ public class HelpTextSpecs : SpecsBase
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
var exitCode = await application.RunAsync(
|
var exitCode = await application.RunAsync(
|
||||||
new[] {"--help"},
|
new[] { "--help" },
|
||||||
new Dictionary<string, string>()
|
new Dictionary<string, string>()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -901,20 +940,23 @@ public class HelpTextSpecs : SpecsBase
|
|||||||
|
|
||||||
var stdOut = FakeConsole.ReadOutputString();
|
var stdOut = FakeConsole.ReadOutputString();
|
||||||
|
|
||||||
stdOut.Should().ContainAllInOrder(
|
stdOut
|
||||||
"COMMANDS",
|
.Should()
|
||||||
"cmd1", "Description of one command.",
|
.ContainAllInOrder(
|
||||||
"cmd2", "Description of another command.",
|
"COMMANDS",
|
||||||
// `cmd2 child` will appear as an immediate command because it does not
|
"cmd1",
|
||||||
// have a more specific parent.
|
"Description of one command.",
|
||||||
"cmd3 child", "Description of an orphaned command."
|
"cmd2",
|
||||||
);
|
"Description of another command.",
|
||||||
|
// `cmd2 child` will appear as an immediate command because it does not
|
||||||
|
// have a more specific parent.
|
||||||
|
"cmd3 child",
|
||||||
|
"Description of an orphaned command."
|
||||||
|
);
|
||||||
|
|
||||||
// `cmd2 child` will still appear in the list of `cmd2` subcommands,
|
// `cmd2 child` will still appear in the list of `cmd2` subcommands,
|
||||||
// but its description will not be visible.
|
// but its description will not be visible.
|
||||||
stdOut.Should().NotContain(
|
stdOut.Should().NotContain("Description of another command's child command.");
|
||||||
"Description of another command's child command."
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -963,7 +1005,7 @@ public class HelpTextSpecs : SpecsBase
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
var exitCode = await application.RunAsync(
|
var exitCode = await application.RunAsync(
|
||||||
new[] {"--help"},
|
new[] { "--help" },
|
||||||
new Dictionary<string, string>()
|
new Dictionary<string, string>()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -971,11 +1013,18 @@ public class HelpTextSpecs : SpecsBase
|
|||||||
exitCode.Should().Be(0);
|
exitCode.Should().Be(0);
|
||||||
|
|
||||||
var stdOut = FakeConsole.ReadOutputString();
|
var stdOut = FakeConsole.ReadOutputString();
|
||||||
stdOut.Should().ContainAllInOrder(
|
stdOut
|
||||||
"COMMANDS",
|
.Should()
|
||||||
"cmd1", "Subcommands:", "cmd1 child1",
|
.ContainAllInOrder(
|
||||||
"cmd2", "Subcommands:", "cmd2 child1", "cmd2 child2"
|
"COMMANDS",
|
||||||
);
|
"cmd1",
|
||||||
|
"Subcommands:",
|
||||||
|
"cmd1 child1",
|
||||||
|
"cmd2",
|
||||||
|
"Subcommands:",
|
||||||
|
"cmd2 child1",
|
||||||
|
"cmd2 child2"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -990,7 +1039,7 @@ public class HelpTextSpecs : SpecsBase
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
var exitCode = await application.RunAsync(
|
var exitCode = await application.RunAsync(
|
||||||
new[] {"--version"},
|
new[] { "--version" },
|
||||||
new Dictionary<string, string>()
|
new Dictionary<string, string>()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -1000,4 +1049,4 @@ public class HelpTextSpecs : SpecsBase
|
|||||||
var stdOut = FakeConsole.ReadOutputString();
|
var stdOut = FakeConsole.ReadOutputString();
|
||||||
stdOut.Trim().Should().Be("v6.9");
|
stdOut.Trim().Should().Be("v6.9");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,9 +12,7 @@ namespace CliFx.Tests;
|
|||||||
public class OptionBindingSpecs : SpecsBase
|
public class OptionBindingSpecs : SpecsBase
|
||||||
{
|
{
|
||||||
public OptionBindingSpecs(ITestOutputHelper testOutput)
|
public OptionBindingSpecs(ITestOutputHelper testOutput)
|
||||||
: base(testOutput)
|
: base(testOutput) { }
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task I_can_bind_an_option_to_a_property_and_get_the_value_from_the_corresponding_argument_by_name()
|
public async Task I_can_bind_an_option_to_a_property_and_get_the_value_from_the_corresponding_argument_by_name()
|
||||||
@@ -45,7 +43,7 @@ public class OptionBindingSpecs : SpecsBase
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
var exitCode = await application.RunAsync(
|
var exitCode = await application.RunAsync(
|
||||||
new[] {"--foo"},
|
new[] { "--foo" },
|
||||||
new Dictionary<string, string>()
|
new Dictionary<string, string>()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -84,10 +82,7 @@ public class OptionBindingSpecs : SpecsBase
|
|||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var exitCode = await application.RunAsync(
|
var exitCode = await application.RunAsync(new[] { "-f" }, new Dictionary<string, string>());
|
||||||
new[] {"-f"},
|
|
||||||
new Dictionary<string, string>()
|
|
||||||
);
|
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
exitCode.Should().Be(0);
|
exitCode.Should().Be(0);
|
||||||
@@ -130,11 +125,7 @@ public class OptionBindingSpecs : SpecsBase
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
var exitCode = await application.RunAsync(
|
var exitCode = await application.RunAsync(
|
||||||
new[]
|
new[] { "--foo", "one", "--bar", "two" },
|
||||||
{
|
|
||||||
"--foo", "one",
|
|
||||||
"--bar", "two"
|
|
||||||
},
|
|
||||||
new Dictionary<string, string>()
|
new Dictionary<string, string>()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -142,10 +133,7 @@ public class OptionBindingSpecs : SpecsBase
|
|||||||
exitCode.Should().Be(0);
|
exitCode.Should().Be(0);
|
||||||
|
|
||||||
var stdOut = FakeConsole.ReadOutputString();
|
var stdOut = FakeConsole.ReadOutputString();
|
||||||
stdOut.Should().ConsistOfLines(
|
stdOut.Should().ConsistOfLines("Foo = one", "Bar = two");
|
||||||
"Foo = one",
|
|
||||||
"Bar = two"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -182,11 +170,7 @@ public class OptionBindingSpecs : SpecsBase
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
var exitCode = await application.RunAsync(
|
var exitCode = await application.RunAsync(
|
||||||
new[]
|
new[] { "-f", "one", "-b", "two" },
|
||||||
{
|
|
||||||
"-f", "one",
|
|
||||||
"-b", "two"
|
|
||||||
},
|
|
||||||
new Dictionary<string, string>()
|
new Dictionary<string, string>()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -194,10 +178,7 @@ public class OptionBindingSpecs : SpecsBase
|
|||||||
exitCode.Should().Be(0);
|
exitCode.Should().Be(0);
|
||||||
|
|
||||||
var stdOut = FakeConsole.ReadOutputString();
|
var stdOut = FakeConsole.ReadOutputString();
|
||||||
stdOut.Should().ConsistOfLines(
|
stdOut.Should().ConsistOfLines("Foo = one", "Bar = two");
|
||||||
"Foo = one",
|
|
||||||
"Bar = two"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -234,7 +215,7 @@ public class OptionBindingSpecs : SpecsBase
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
var exitCode = await application.RunAsync(
|
var exitCode = await application.RunAsync(
|
||||||
new[] {"-fb", "value"},
|
new[] { "-fb", "value" },
|
||||||
new Dictionary<string, string>()
|
new Dictionary<string, string>()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -242,10 +223,7 @@ public class OptionBindingSpecs : SpecsBase
|
|||||||
exitCode.Should().Be(0);
|
exitCode.Should().Be(0);
|
||||||
|
|
||||||
var stdOut = FakeConsole.ReadOutputString();
|
var stdOut = FakeConsole.ReadOutputString();
|
||||||
stdOut.Should().ConsistOfLines(
|
stdOut.Should().ConsistOfLines("Foo = ", "Bar = value");
|
||||||
"Foo = ",
|
|
||||||
"Bar = value"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -279,7 +257,7 @@ public class OptionBindingSpecs : SpecsBase
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
var exitCode = await application.RunAsync(
|
var exitCode = await application.RunAsync(
|
||||||
new[] {"--foo", "one", "two", "three"},
|
new[] { "--foo", "one", "two", "three" },
|
||||||
new Dictionary<string, string>()
|
new Dictionary<string, string>()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -287,11 +265,7 @@ public class OptionBindingSpecs : SpecsBase
|
|||||||
exitCode.Should().Be(0);
|
exitCode.Should().Be(0);
|
||||||
|
|
||||||
var stdOut = FakeConsole.ReadOutputString();
|
var stdOut = FakeConsole.ReadOutputString();
|
||||||
stdOut.Should().ConsistOfLines(
|
stdOut.Should().ConsistOfLines("one", "two", "three");
|
||||||
"one",
|
|
||||||
"two",
|
|
||||||
"three"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -325,7 +299,7 @@ public class OptionBindingSpecs : SpecsBase
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
var exitCode = await application.RunAsync(
|
var exitCode = await application.RunAsync(
|
||||||
new[] {"-f", "one", "two", "three"},
|
new[] { "-f", "one", "two", "three" },
|
||||||
new Dictionary<string, string>()
|
new Dictionary<string, string>()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -333,11 +307,7 @@ public class OptionBindingSpecs : SpecsBase
|
|||||||
exitCode.Should().Be(0);
|
exitCode.Should().Be(0);
|
||||||
|
|
||||||
var stdOut = FakeConsole.ReadOutputString();
|
var stdOut = FakeConsole.ReadOutputString();
|
||||||
stdOut.Should().ConsistOfLines(
|
stdOut.Should().ConsistOfLines("one", "two", "three");
|
||||||
"one",
|
|
||||||
"two",
|
|
||||||
"three"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -371,12 +341,7 @@ public class OptionBindingSpecs : SpecsBase
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
var exitCode = await application.RunAsync(
|
var exitCode = await application.RunAsync(
|
||||||
new[]
|
new[] { "--foo", "one", "--foo", "two", "--foo", "three" },
|
||||||
{
|
|
||||||
"--foo", "one",
|
|
||||||
"--foo", "two",
|
|
||||||
"--foo", "three"
|
|
||||||
},
|
|
||||||
new Dictionary<string, string>()
|
new Dictionary<string, string>()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -384,11 +349,7 @@ public class OptionBindingSpecs : SpecsBase
|
|||||||
exitCode.Should().Be(0);
|
exitCode.Should().Be(0);
|
||||||
|
|
||||||
var stdOut = FakeConsole.ReadOutputString();
|
var stdOut = FakeConsole.ReadOutputString();
|
||||||
stdOut.Should().ConsistOfLines(
|
stdOut.Should().ConsistOfLines("one", "two", "three");
|
||||||
"one",
|
|
||||||
"two",
|
|
||||||
"three"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -422,12 +383,7 @@ public class OptionBindingSpecs : SpecsBase
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
var exitCode = await application.RunAsync(
|
var exitCode = await application.RunAsync(
|
||||||
new[]
|
new[] { "-f", "one", "-f", "two", "-f", "three" },
|
||||||
{
|
|
||||||
"-f", "one",
|
|
||||||
"-f", "two",
|
|
||||||
"-f", "three"
|
|
||||||
},
|
|
||||||
new Dictionary<string, string>()
|
new Dictionary<string, string>()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -435,11 +391,7 @@ public class OptionBindingSpecs : SpecsBase
|
|||||||
exitCode.Should().Be(0);
|
exitCode.Should().Be(0);
|
||||||
|
|
||||||
var stdOut = FakeConsole.ReadOutputString();
|
var stdOut = FakeConsole.ReadOutputString();
|
||||||
stdOut.Should().ConsistOfLines(
|
stdOut.Should().ConsistOfLines("one", "two", "three");
|
||||||
"one",
|
|
||||||
"two",
|
|
||||||
"three"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -473,12 +425,7 @@ public class OptionBindingSpecs : SpecsBase
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
var exitCode = await application.RunAsync(
|
var exitCode = await application.RunAsync(
|
||||||
new[]
|
new[] { "--foo", "one", "-f", "two", "--foo", "three" },
|
||||||
{
|
|
||||||
"--foo", "one",
|
|
||||||
"-f", "two",
|
|
||||||
"--foo", "three"
|
|
||||||
},
|
|
||||||
new Dictionary<string, string>()
|
new Dictionary<string, string>()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -486,11 +433,7 @@ public class OptionBindingSpecs : SpecsBase
|
|||||||
exitCode.Should().Be(0);
|
exitCode.Should().Be(0);
|
||||||
|
|
||||||
var stdOut = FakeConsole.ReadOutputString();
|
var stdOut = FakeConsole.ReadOutputString();
|
||||||
stdOut.Should().ConsistOfLines(
|
stdOut.Should().ConsistOfLines("one", "two", "three");
|
||||||
"one",
|
|
||||||
"two",
|
|
||||||
"three"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -527,7 +470,7 @@ public class OptionBindingSpecs : SpecsBase
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
var exitCode = await application.RunAsync(
|
var exitCode = await application.RunAsync(
|
||||||
new[] {"--foo", "one"},
|
new[] { "--foo", "one" },
|
||||||
new Dictionary<string, string>()
|
new Dictionary<string, string>()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -535,10 +478,7 @@ public class OptionBindingSpecs : SpecsBase
|
|||||||
exitCode.Should().Be(0);
|
exitCode.Should().Be(0);
|
||||||
|
|
||||||
var stdOut = FakeConsole.ReadOutputString();
|
var stdOut = FakeConsole.ReadOutputString();
|
||||||
stdOut.Should().ConsistOfLines(
|
stdOut.Should().ConsistOfLines("Foo = one", "Bar = hello");
|
||||||
"Foo = one",
|
|
||||||
"Bar = hello"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -604,24 +544,13 @@ public class OptionBindingSpecs : SpecsBase
|
|||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var exitCode = await application.RunAsync(
|
var exitCode = await application.RunAsync(new[] { "--foo", "42", "--bar", "--baz", "xyz" });
|
||||||
new[]
|
|
||||||
{
|
|
||||||
"--foo", "42",
|
|
||||||
"--bar",
|
|
||||||
"--baz", "xyz"
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
exitCode.Should().Be(0);
|
exitCode.Should().Be(0);
|
||||||
|
|
||||||
var stdOut = FakeConsole.ReadOutputString();
|
var stdOut = FakeConsole.ReadOutputString();
|
||||||
stdOut.Should().ConsistOfLines(
|
stdOut.Should().ConsistOfLines("Foo = 42", "Bar = True", "Baz = xyz");
|
||||||
"Foo = 42",
|
|
||||||
"Bar = True",
|
|
||||||
"Baz = xyz"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -653,7 +582,7 @@ public class OptionBindingSpecs : SpecsBase
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
var exitCode = await application.RunAsync(
|
var exitCode = await application.RunAsync(
|
||||||
new[] {"--foo", "-13"},
|
new[] { "--foo", "-13" },
|
||||||
new Dictionary<string, string>()
|
new Dictionary<string, string>()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -725,7 +654,7 @@ public class OptionBindingSpecs : SpecsBase
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
var exitCode = await application.RunAsync(
|
var exitCode = await application.RunAsync(
|
||||||
new[] {"--foo"},
|
new[] { "--foo" },
|
||||||
new Dictionary<string, string>()
|
new Dictionary<string, string>()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -761,7 +690,7 @@ public class OptionBindingSpecs : SpecsBase
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
var exitCode = await application.RunAsync(
|
var exitCode = await application.RunAsync(
|
||||||
new[] {"--foo"},
|
new[] { "--foo" },
|
||||||
new Dictionary<string, string>()
|
new Dictionary<string, string>()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -797,11 +726,7 @@ public class OptionBindingSpecs : SpecsBase
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
var exitCode = await application.RunAsync(
|
var exitCode = await application.RunAsync(
|
||||||
new[]
|
new[] { "--foo", "one", "--bar", "two" },
|
||||||
{
|
|
||||||
"--foo", "one",
|
|
||||||
"--bar", "two"
|
|
||||||
},
|
|
||||||
new Dictionary<string, string>()
|
new Dictionary<string, string>()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -837,7 +762,7 @@ public class OptionBindingSpecs : SpecsBase
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
var exitCode = await application.RunAsync(
|
var exitCode = await application.RunAsync(
|
||||||
new[] {"--foo", "one", "two", "three"},
|
new[] { "--foo", "one", "two", "three" },
|
||||||
new Dictionary<string, string>()
|
new Dictionary<string, string>()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -847,4 +772,4 @@ public class OptionBindingSpecs : SpecsBase
|
|||||||
var stdErr = FakeConsole.ReadErrorString();
|
var stdErr = FakeConsole.ReadErrorString();
|
||||||
stdErr.Should().Contain("expects a single argument, but provided with multiple");
|
stdErr.Should().Contain("expects a single argument, but provided with multiple");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,9 +11,7 @@ namespace CliFx.Tests;
|
|||||||
public class ParameterBindingSpecs : SpecsBase
|
public class ParameterBindingSpecs : SpecsBase
|
||||||
{
|
{
|
||||||
public ParameterBindingSpecs(ITestOutputHelper testOutput)
|
public ParameterBindingSpecs(ITestOutputHelper testOutput)
|
||||||
: base(testOutput)
|
: base(testOutput) { }
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task I_can_bind_a_parameter_to_a_property_and_get_the_value_from_the_corresponding_argument()
|
public async Task I_can_bind_a_parameter_to_a_property_and_get_the_value_from_the_corresponding_argument()
|
||||||
@@ -49,7 +47,7 @@ public class ParameterBindingSpecs : SpecsBase
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
var exitCode = await application.RunAsync(
|
var exitCode = await application.RunAsync(
|
||||||
new[] {"one", "two"},
|
new[] { "one", "two" },
|
||||||
new Dictionary<string, string>()
|
new Dictionary<string, string>()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -57,10 +55,7 @@ public class ParameterBindingSpecs : SpecsBase
|
|||||||
exitCode.Should().Be(0);
|
exitCode.Should().Be(0);
|
||||||
|
|
||||||
var stdOut = FakeConsole.ReadOutputString();
|
var stdOut = FakeConsole.ReadOutputString();
|
||||||
stdOut.Should().ConsistOfLines(
|
stdOut.Should().ConsistOfLines("Foo = one", "Bar = two");
|
||||||
"Foo = one",
|
|
||||||
"Bar = two"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -106,7 +101,7 @@ public class ParameterBindingSpecs : SpecsBase
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
var exitCode = await application.RunAsync(
|
var exitCode = await application.RunAsync(
|
||||||
new[] {"one", "two", "three", "four", "five", "--boo", "xxx"},
|
new[] { "one", "two", "three", "four", "five", "--boo", "xxx" },
|
||||||
new Dictionary<string, string>()
|
new Dictionary<string, string>()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -114,13 +109,9 @@ public class ParameterBindingSpecs : SpecsBase
|
|||||||
exitCode.Should().Be(0);
|
exitCode.Should().Be(0);
|
||||||
|
|
||||||
var stdOut = FakeConsole.ReadOutputString();
|
var stdOut = FakeConsole.ReadOutputString();
|
||||||
stdOut.Should().ConsistOfLines(
|
stdOut
|
||||||
"Foo = one",
|
.Should()
|
||||||
"Bar = two",
|
.ConsistOfLines("Foo = one", "Bar = two", "Baz = three", "Baz = four", "Baz = five");
|
||||||
"Baz = three",
|
|
||||||
"Baz = four",
|
|
||||||
"Baz = five"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -151,7 +142,7 @@ public class ParameterBindingSpecs : SpecsBase
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
var exitCode = await application.RunAsync(
|
var exitCode = await application.RunAsync(
|
||||||
new[] {"one"},
|
new[] { "one" },
|
||||||
new Dictionary<string, string>()
|
new Dictionary<string, string>()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -190,7 +181,7 @@ public class ParameterBindingSpecs : SpecsBase
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
var exitCode = await application.RunAsync(
|
var exitCode = await application.RunAsync(
|
||||||
new[] {"one"},
|
new[] { "one" },
|
||||||
new Dictionary<string, string>()
|
new Dictionary<string, string>()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -235,7 +226,7 @@ public class ParameterBindingSpecs : SpecsBase
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
var exitCode = await application.RunAsync(
|
var exitCode = await application.RunAsync(
|
||||||
new[] {"abc"},
|
new[] { "abc" },
|
||||||
new Dictionary<string, string>()
|
new Dictionary<string, string>()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -243,10 +234,7 @@ public class ParameterBindingSpecs : SpecsBase
|
|||||||
exitCode.Should().Be(0);
|
exitCode.Should().Be(0);
|
||||||
|
|
||||||
var stdOut = FakeConsole.ReadOutputString();
|
var stdOut = FakeConsole.ReadOutputString();
|
||||||
stdOut.Should().ConsistOfLines(
|
stdOut.Should().ConsistOfLines("Foo = abc", "Bar = xyz");
|
||||||
"Foo = abc",
|
|
||||||
"Bar = xyz"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -277,7 +265,7 @@ public class ParameterBindingSpecs : SpecsBase
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
var exitCode = await application.RunAsync(
|
var exitCode = await application.RunAsync(
|
||||||
new[] {"one", "two", "three"},
|
new[] { "one", "two", "three" },
|
||||||
new Dictionary<string, string>()
|
new Dictionary<string, string>()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -287,4 +275,4 @@ public class ParameterBindingSpecs : SpecsBase
|
|||||||
var stdErr = FakeConsole.ReadErrorString();
|
var stdErr = FakeConsole.ReadErrorString();
|
||||||
stdErr.Should().Contain("Unexpected parameter(s)");
|
stdErr.Should().Contain("Unexpected parameter(s)");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,9 +11,7 @@ namespace CliFx.Tests;
|
|||||||
public class RoutingSpecs : SpecsBase
|
public class RoutingSpecs : SpecsBase
|
||||||
{
|
{
|
||||||
public RoutingSpecs(ITestOutputHelper testOutput)
|
public RoutingSpecs(ITestOutputHelper testOutput)
|
||||||
: base(testOutput)
|
: base(testOutput) { }
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task I_can_configure_a_command_to_be_executed_by_default_when_the_user_does_not_specify_a_command_name()
|
public async Task I_can_configure_a_command_to_be_executed_by_default_when_the_user_does_not_specify_a_command_name()
|
||||||
@@ -118,7 +116,7 @@ public class RoutingSpecs : SpecsBase
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
var exitCode = await application.RunAsync(
|
var exitCode = await application.RunAsync(
|
||||||
new[] {"cmd"},
|
new[] { "cmd" },
|
||||||
new Dictionary<string, string>()
|
new Dictionary<string, string>()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -175,7 +173,7 @@ public class RoutingSpecs : SpecsBase
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
var exitCode = await application.RunAsync(
|
var exitCode = await application.RunAsync(
|
||||||
new[] {"cmd", "child"},
|
new[] { "cmd", "child" },
|
||||||
new Dictionary<string, string>()
|
new Dictionary<string, string>()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -185,4 +183,4 @@ public class RoutingSpecs : SpecsBase
|
|||||||
var stdOut = FakeConsole.ReadOutputString();
|
var stdOut = FakeConsole.ReadOutputString();
|
||||||
stdOut.Trim().Should().Be("cmd child");
|
stdOut.Trim().Should().Be("cmd child");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,12 +11,11 @@ public abstract class SpecsBase : IDisposable
|
|||||||
|
|
||||||
public FakeInMemoryConsole FakeConsole { get; } = new();
|
public FakeInMemoryConsole FakeConsole { get; } = new();
|
||||||
|
|
||||||
protected SpecsBase(ITestOutputHelper testOutput) =>
|
protected SpecsBase(ITestOutputHelper testOutput) => TestOutput = testOutput;
|
||||||
TestOutput = testOutput;
|
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
FakeConsole.DumpToTestOutput(TestOutput);
|
FakeConsole.DumpToTestOutput(TestOutput);
|
||||||
FakeConsole.Dispose();
|
FakeConsole.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,9 +13,7 @@ namespace CliFx.Tests;
|
|||||||
public class TypeActivationSpecs : SpecsBase
|
public class TypeActivationSpecs : SpecsBase
|
||||||
{
|
{
|
||||||
public TypeActivationSpecs(ITestOutputHelper testOutput)
|
public TypeActivationSpecs(ITestOutputHelper testOutput)
|
||||||
: base(testOutput)
|
: base(testOutput) { }
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task I_can_configure_the_application_to_use_the_default_type_activator_to_initialize_types_through_parameterless_constructors()
|
public async Task I_can_configure_the_application_to_use_the_default_type_activator_to_initialize_types_through_parameterless_constructors()
|
||||||
@@ -225,4 +223,4 @@ public class TypeActivationSpecs : SpecsBase
|
|||||||
var stdErr = FakeConsole.ReadErrorString();
|
var stdErr = FakeConsole.ReadErrorString();
|
||||||
stdErr.Should().Contain("Failed to create an instance of type");
|
stdErr.Should().Contain("Failed to create an instance of type");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,8 +31,7 @@ internal static class DynamicCommandBuilder
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Get default CliFx namespaces
|
// Get default CliFx namespaces
|
||||||
var defaultCliFxNamespaces = typeof(ICommand)
|
var defaultCliFxNamespaces = typeof(ICommand).Assembly
|
||||||
.Assembly
|
|
||||||
.GetTypes()
|
.GetTypes()
|
||||||
.Where(t => t.IsPublic)
|
.Where(t => t.IsPublic)
|
||||||
.Select(t => t.Namespace)
|
.Select(t => t.Namespace)
|
||||||
@@ -41,10 +40,10 @@ internal static class DynamicCommandBuilder
|
|||||||
|
|
||||||
// Append default imports to the source code
|
// Append default imports to the source code
|
||||||
var sourceCodeWithUsings =
|
var sourceCodeWithUsings =
|
||||||
string.Join(Environment.NewLine, defaultSystemNamespaces.Select(n => $"using {n};")) +
|
string.Join(Environment.NewLine, defaultSystemNamespaces.Select(n => $"using {n};"))
|
||||||
string.Join(Environment.NewLine, defaultCliFxNamespaces.Select(n => $"using {n};")) +
|
+ string.Join(Environment.NewLine, defaultCliFxNamespaces.Select(n => $"using {n};"))
|
||||||
Environment.NewLine +
|
+ Environment.NewLine
|
||||||
sourceCode;
|
+ sourceCode;
|
||||||
|
|
||||||
// Parse the source code
|
// Parse the source code
|
||||||
var ast = SyntaxFactory.ParseSyntaxTree(
|
var ast = SyntaxFactory.ParseSyntaxTree(
|
||||||
@@ -55,10 +54,14 @@ internal static class DynamicCommandBuilder
|
|||||||
// Compile the code to IL
|
// Compile the code to IL
|
||||||
var compilation = CSharpCompilation.Create(
|
var compilation = CSharpCompilation.Create(
|
||||||
"CliFxTests_DynamicAssembly_" + Guid.NewGuid(),
|
"CliFxTests_DynamicAssembly_" + Guid.NewGuid(),
|
||||||
new[] {ast},
|
new[] { ast },
|
||||||
Net70.References.All
|
Net70.References.All
|
||||||
.Append(MetadataReference.CreateFromFile(typeof(ICommand).Assembly.Location))
|
.Append(MetadataReference.CreateFromFile(typeof(ICommand).Assembly.Location))
|
||||||
.Append(MetadataReference.CreateFromFile(typeof(DynamicCommandBuilder).Assembly.Location)),
|
.Append(
|
||||||
|
MetadataReference.CreateFromFile(
|
||||||
|
typeof(DynamicCommandBuilder).Assembly.Location
|
||||||
|
)
|
||||||
|
),
|
||||||
// DLL to avoid having to define the Main() method
|
// DLL to avoid having to define the Main() method
|
||||||
new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)
|
new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)
|
||||||
);
|
);
|
||||||
@@ -82,8 +85,7 @@ internal static class DynamicCommandBuilder
|
|||||||
using var buffer = new MemoryStream();
|
using var buffer = new MemoryStream();
|
||||||
var emit = compilation.Emit(buffer);
|
var emit = compilation.Emit(buffer);
|
||||||
|
|
||||||
var emitErrors = emit
|
var emitErrors = emit.Diagnostics
|
||||||
.Diagnostics
|
|
||||||
.Where(d => d.Severity >= DiagnosticSeverity.Error)
|
.Where(d => d.Severity >= DiagnosticSeverity.Error)
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
@@ -128,4 +130,4 @@ internal static class DynamicCommandBuilder
|
|||||||
|
|
||||||
return commandTypes.Single();
|
return commandTypes.Single();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,22 +8,22 @@ namespace CliFx.Tests.Utils.Extensions;
|
|||||||
|
|
||||||
internal static class AssertionExtensions
|
internal static class AssertionExtensions
|
||||||
{
|
{
|
||||||
public static void ConsistOfLines(
|
public static void ConsistOfLines(this StringAssertions assertions, IEnumerable<string> lines)
|
||||||
this StringAssertions assertions,
|
|
||||||
IEnumerable<string> lines)
|
|
||||||
{
|
{
|
||||||
var actualLines = assertions.Subject.Split(new[] {'\n', '\r'}, StringSplitOptions.RemoveEmptyEntries);
|
var actualLines = assertions.Subject.Split(
|
||||||
|
new[] { '\n', '\r' },
|
||||||
|
StringSplitOptions.RemoveEmptyEntries
|
||||||
|
);
|
||||||
actualLines.Should().Equal(lines);
|
actualLines.Should().Equal(lines);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void ConsistOfLines(
|
public static void ConsistOfLines(this StringAssertions assertions, params string[] lines) =>
|
||||||
this StringAssertions assertions,
|
assertions.ConsistOfLines((IEnumerable<string>)lines);
|
||||||
params string[] lines) =>
|
|
||||||
assertions.ConsistOfLines((IEnumerable<string>) lines);
|
|
||||||
|
|
||||||
public static AndConstraint<StringAssertions> ContainAllInOrder(
|
public static AndConstraint<StringAssertions> ContainAllInOrder(
|
||||||
this StringAssertions assertions,
|
this StringAssertions assertions,
|
||||||
IEnumerable<string> values)
|
IEnumerable<string> values
|
||||||
|
)
|
||||||
{
|
{
|
||||||
var lastIndex = 0;
|
var lastIndex = 0;
|
||||||
|
|
||||||
@@ -46,6 +46,6 @@ internal static class AssertionExtensions
|
|||||||
|
|
||||||
public static AndConstraint<StringAssertions> ContainAllInOrder(
|
public static AndConstraint<StringAssertions> ContainAllInOrder(
|
||||||
this StringAssertions assertions,
|
this StringAssertions assertions,
|
||||||
params string[] values) =>
|
params string[] values
|
||||||
assertions.ContainAllInOrder((IEnumerable<string>) values);
|
) => assertions.ContainAllInOrder((IEnumerable<string>)values);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,10 @@ namespace CliFx.Tests.Utils.Extensions;
|
|||||||
|
|
||||||
internal static class ConsoleExtensions
|
internal static class ConsoleExtensions
|
||||||
{
|
{
|
||||||
public static void DumpToTestOutput(this FakeInMemoryConsole console, ITestOutputHelper testOutputHelper)
|
public static void DumpToTestOutput(
|
||||||
|
this FakeInMemoryConsole console,
|
||||||
|
ITestOutputHelper testOutputHelper
|
||||||
|
)
|
||||||
{
|
{
|
||||||
testOutputHelper.WriteLine("[*] Captured standard output:");
|
testOutputHelper.WriteLine("[*] Captured standard output:");
|
||||||
testOutputHelper.WriteLine(console.ReadOutputString());
|
testOutputHelper.WriteLine(console.ReadOutputString());
|
||||||
@@ -13,4 +16,4 @@ internal static class ConsoleExtensions
|
|||||||
testOutputHelper.WriteLine("[*] Captured standard error:");
|
testOutputHelper.WriteLine("[*] Captured standard error:");
|
||||||
testOutputHelper.WriteLine(console.ReadErrorString());
|
testOutputHelper.WriteLine(console.ReadErrorString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,4 +8,4 @@ namespace CliFx.Tests.Utils;
|
|||||||
internal class NoOpCommand : ICommand
|
internal class NoOpCommand : ICommand
|
||||||
{
|
{
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="CSharpier.MsBuild" Version="0.25.0" PrivateAssets="all" />
|
||||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="all" />
|
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="all" />
|
||||||
<PackageReference Include="PolyShim" Version="1.7.0" PrivateAssets="all" />
|
<PackageReference Include="PolyShim" Version="1.7.0" PrivateAssets="all" />
|
||||||
<PackageReference Include="System.Threading.Tasks.Extensions" Version="4.5.4" Condition="'$(TargetFramework)' == 'netstandard2.0'" />
|
<PackageReference Include="System.Threading.Tasks.Extensions" Version="4.5.4" Condition="'$(TargetFramework)' == 'netstandard2.0'" />
|
||||||
|
|||||||
Reference in New Issue
Block a user