This commit is contained in:
Tyrrrz
2021-12-08 23:43:35 +02:00
parent 9990387cfa
commit 2feeb21270
132 changed files with 8021 additions and 8154 deletions

View File

@@ -2,71 +2,70 @@
using Microsoft.CodeAnalysis.Diagnostics;
using Xunit;
namespace CliFx.Analyzers.Tests
{
public class CommandMustBeAnnotatedAnalyzerSpecs
{
private static DiagnosticAnalyzer Analyzer { get; } = new CommandMustBeAnnotatedAnalyzer();
namespace CliFx.Analyzers.Tests;
[Fact]
public void Analyzer_reports_an_error_if_a_command_is_not_annotated_with_the_command_attribute()
{
// Arrange
// language=cs
const string code = @"
public class CommandMustBeAnnotatedAnalyzerSpecs
{
private static DiagnosticAnalyzer Analyzer { get; } = new CommandMustBeAnnotatedAnalyzer();
[Fact]
public void Analyzer_reports_an_error_if_a_command_is_not_annotated_with_the_command_attribute()
{
// Arrange
// language=cs
const string code = @"
public class MyCommand : ICommand
{
public ValueTask ExecuteAsync(IConsole console) => default;
}";
// Act & assert
Analyzer.Should().ProduceDiagnostics(code);
}
// Act & assert
Analyzer.Should().ProduceDiagnostics(code);
}
[Fact]
public void Analyzer_does_not_report_an_error_if_a_command_is_annotated_with_the_command_attribute()
{
// Arrange
// language=cs
const string code = @"
[Fact]
public void Analyzer_does_not_report_an_error_if_a_command_is_annotated_with_the_command_attribute()
{
// Arrange
// language=cs
const string code = @"
[Command]
public abstract class MyCommand : ICommand
{
public ValueTask ExecuteAsync(IConsole console) => default;
}";
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
[Fact]
public void Analyzer_does_not_report_an_error_if_a_command_is_implemented_as_an_abstract_class()
{
// Arrange
// language=cs
const string code = @"
[Fact]
public void Analyzer_does_not_report_an_error_if_a_command_is_implemented_as_an_abstract_class()
{
// Arrange
// language=cs
const string code = @"
public abstract class MyCommand : ICommand
{
public ValueTask ExecuteAsync(IConsole console) => default;
}";
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
[Fact]
public void Analyzer_does_not_report_an_error_on_a_class_that_is_not_a_command()
{
// Arrange
// language=cs
const string code = @"
[Fact]
public void Analyzer_does_not_report_an_error_on_a_class_that_is_not_a_command()
{
// Arrange
// language=cs
const string code = @"
public class Foo
{
public int Bar { get; set; } = 5;
}";
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
}

View File

@@ -2,57 +2,56 @@
using Microsoft.CodeAnalysis.Diagnostics;
using Xunit;
namespace CliFx.Analyzers.Tests
{
public class CommandMustImplementInterfaceAnalyzerSpecs
{
private static DiagnosticAnalyzer Analyzer { get; } = new CommandMustImplementInterfaceAnalyzer();
namespace CliFx.Analyzers.Tests;
[Fact]
public void Analyzer_reports_an_error_if_a_command_does_not_implement_ICommand_interface()
{
// Arrange
// language=cs
const string code = @"
public class CommandMustImplementInterfaceAnalyzerSpecs
{
private static DiagnosticAnalyzer Analyzer { get; } = new CommandMustImplementInterfaceAnalyzer();
[Fact]
public void Analyzer_reports_an_error_if_a_command_does_not_implement_ICommand_interface()
{
// Arrange
// language=cs
const string code = @"
[Command]
public class MyCommand
{
public ValueTask ExecuteAsync(IConsole console) => default;
}";
// Act & assert
Analyzer.Should().ProduceDiagnostics(code);
}
// Act & assert
Analyzer.Should().ProduceDiagnostics(code);
}
[Fact]
public void Analyzer_does_not_report_an_error_if_a_command_implements_ICommand_interface()
{
// Arrange
// language=cs
const string code = @"
[Fact]
public void Analyzer_does_not_report_an_error_if_a_command_implements_ICommand_interface()
{
// Arrange
// language=cs
const string code = @"
[Command]
public class MyCommand : ICommand
{
public ValueTask ExecuteAsync(IConsole console) => default;
}";
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
[Fact]
public void Analyzer_does_not_report_an_error_on_a_class_that_is_not_a_command()
{
// Arrange
// language=cs
const string code = @"
[Fact]
public void Analyzer_does_not_report_an_error_on_a_class_that_is_not_a_command()
{
// Arrange
// language=cs
const string code = @"
public class Foo
{
public int Bar { get; set; } = 5;
}";
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
}

View File

@@ -4,28 +4,27 @@ using FluentAssertions;
using Microsoft.CodeAnalysis.Diagnostics;
using Xunit;
namespace CliFx.Analyzers.Tests
namespace CliFx.Analyzers.Tests;
public class GeneralSpecs
{
public class GeneralSpecs
[Fact]
public void All_analyzers_have_unique_diagnostic_IDs()
{
[Fact]
public void All_analyzers_have_unique_diagnostic_IDs()
{
// Arrange
var analyzers = typeof(AnalyzerBase)
.Assembly
.GetTypes()
.Where(t => !t.IsAbstract && t.IsAssignableTo(typeof(DiagnosticAnalyzer)))
.Select(t => (DiagnosticAnalyzer) Activator.CreateInstance(t)!)
.ToArray();
// Arrange
var analyzers = typeof(AnalyzerBase)
.Assembly
.GetTypes()
.Where(t => !t.IsAbstract && t.IsAssignableTo(typeof(DiagnosticAnalyzer)))
.Select(t => (DiagnosticAnalyzer) Activator.CreateInstance(t)!)
.ToArray();
// Act
var diagnosticIds = analyzers
.SelectMany(a => a.SupportedDiagnostics.Select(d => d.Id))
.ToArray();
// Act
var diagnosticIds = analyzers
.SelectMany(a => a.SupportedDiagnostics.Select(d => d.Id))
.ToArray();
// Assert
diagnosticIds.Should().OnlyHaveUniqueItems();
}
// Assert
diagnosticIds.Should().OnlyHaveUniqueItems();
}
}

View File

@@ -2,34 +2,34 @@
using Microsoft.CodeAnalysis.Diagnostics;
using Xunit;
namespace CliFx.Analyzers.Tests
{
public class OptionMustBeInsideCommandAnalyzerSpecs
{
private static DiagnosticAnalyzer Analyzer { get; } = new OptionMustBeInsideCommandAnalyzer();
namespace CliFx.Analyzers.Tests;
[Fact]
public void Analyzer_reports_an_error_if_an_option_is_inside_a_class_that_is_not_a_command()
{
// Arrange
// language=cs
const string code = @"
public class OptionMustBeInsideCommandAnalyzerSpecs
{
private static DiagnosticAnalyzer Analyzer { get; } = new OptionMustBeInsideCommandAnalyzer();
[Fact]
public void Analyzer_reports_an_error_if_an_option_is_inside_a_class_that_is_not_a_command()
{
// Arrange
// language=cs
const string code = @"
public class MyClass
{
[CommandOption(""foo"")]
public string Foo { get; set; }
}";
// Act & assert
Analyzer.Should().ProduceDiagnostics(code);
}
// Act & assert
Analyzer.Should().ProduceDiagnostics(code);
}
[Fact]
public void Analyzer_does_not_report_an_error_if_an_option_is_inside_a_command()
{
// Arrange
// language=cs
const string code = @"
[Fact]
public void Analyzer_does_not_report_an_error_if_an_option_is_inside_a_command()
{
// Arrange
// language=cs
const string code = @"
[Command]
public class MyCommand : ICommand
{
@@ -39,32 +39,32 @@ public class MyCommand : ICommand
public ValueTask ExecuteAsync(IConsole console) => default;
}";
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
[Fact]
public void Analyzer_does_not_report_an_error_if_an_option_is_inside_an_abstract_class()
{
// Arrange
// language=cs
const string code = @"
[Fact]
public void Analyzer_does_not_report_an_error_if_an_option_is_inside_an_abstract_class()
{
// Arrange
// language=cs
const string code = @"
public abstract class MyCommand
{
[CommandOption(""foo"")]
public string Foo { get; set; }
}";
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
[Fact]
public void Analyzer_does_not_report_an_error_on_a_property_that_is_not_an_option()
{
// Arrange
// language=cs
const string code = @"
[Fact]
public void Analyzer_does_not_report_an_error_on_a_property_that_is_not_an_option()
{
// Arrange
// language=cs
const string code = @"
[Command]
public class MyCommand : ICommand
{
@@ -73,8 +73,7 @@ public class MyCommand : ICommand
public ValueTask ExecuteAsync(IConsole console) => default;
}";
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
}

View File

@@ -2,18 +2,18 @@
using Microsoft.CodeAnalysis.Diagnostics;
using Xunit;
namespace CliFx.Analyzers.Tests
{
public class OptionMustHaveNameOrShortNameAnalyzerSpecs
{
private static DiagnosticAnalyzer Analyzer { get; } = new OptionMustHaveNameOrShortNameAnalyzer();
namespace CliFx.Analyzers.Tests;
[Fact]
public void Analyzer_reports_an_error_if_an_option_does_not_have_a_name_or_short_name()
{
// Arrange
// language=cs
const string code = @"
public class OptionMustHaveNameOrShortNameAnalyzerSpecs
{
private static DiagnosticAnalyzer Analyzer { get; } = new OptionMustHaveNameOrShortNameAnalyzer();
[Fact]
public void Analyzer_reports_an_error_if_an_option_does_not_have_a_name_or_short_name()
{
// Arrange
// language=cs
const string code = @"
[Command]
public class MyCommand : ICommand
{
@@ -23,16 +23,16 @@ public class MyCommand : ICommand
public ValueTask ExecuteAsync(IConsole console) => default;
}";
// Act & assert
Analyzer.Should().ProduceDiagnostics(code);
}
// Act & assert
Analyzer.Should().ProduceDiagnostics(code);
}
[Fact]
public void Analyzer_does_not_report_an_error_if_an_option_has_a_name()
{
// Arrange
// language=cs
const string code = @"
[Fact]
public void Analyzer_does_not_report_an_error_if_an_option_has_a_name()
{
// Arrange
// language=cs
const string code = @"
[Command]
public class MyCommand : ICommand
{
@@ -42,16 +42,16 @@ public class MyCommand : ICommand
public ValueTask ExecuteAsync(IConsole console) => default;
}";
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
[Fact]
public void Analyzer_does_not_report_an_error_if_an_option_has_a_short_name()
{
// Arrange
// language=cs
const string code = @"
[Fact]
public void Analyzer_does_not_report_an_error_if_an_option_has_a_short_name()
{
// Arrange
// language=cs
const string code = @"
[Command]
public class MyCommand : ICommand
{
@@ -61,16 +61,16 @@ public class MyCommand : ICommand
public ValueTask ExecuteAsync(IConsole console) => default;
}";
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
[Fact]
public void Analyzer_does_not_report_an_error_on_a_property_that_is_not_an_option()
{
// Arrange
// language=cs
const string code = @"
[Fact]
public void Analyzer_does_not_report_an_error_on_a_property_that_is_not_an_option()
{
// Arrange
// language=cs
const string code = @"
[Command]
public class MyCommand : ICommand
{
@@ -79,8 +79,7 @@ public class MyCommand : ICommand
public ValueTask ExecuteAsync(IConsole console) => default;
}";
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
}

View File

@@ -2,18 +2,18 @@
using Microsoft.CodeAnalysis.Diagnostics;
using Xunit;
namespace CliFx.Analyzers.Tests
{
public class OptionMustHaveUniqueNameAnalyzerSpecs
{
private static DiagnosticAnalyzer Analyzer { get; } = new OptionMustHaveUniqueNameAnalyzer();
namespace CliFx.Analyzers.Tests;
[Fact]
public void Analyzer_reports_an_error_if_an_option_has_the_same_name_as_another_option()
{
// Arrange
// language=cs
const string code = @"
public class OptionMustHaveUniqueNameAnalyzerSpecs
{
private static DiagnosticAnalyzer Analyzer { get; } = new OptionMustHaveUniqueNameAnalyzer();
[Fact]
public void Analyzer_reports_an_error_if_an_option_has_the_same_name_as_another_option()
{
// Arrange
// language=cs
const string code = @"
[Command]
public class MyCommand : ICommand
{
@@ -26,16 +26,16 @@ public class MyCommand : ICommand
public ValueTask ExecuteAsync(IConsole console) => default;
}";
// Act & assert
Analyzer.Should().ProduceDiagnostics(code);
}
// Act & assert
Analyzer.Should().ProduceDiagnostics(code);
}
[Fact]
public void Analyzer_does_not_report_an_error_if_an_option_has_a_unique_name()
{
// Arrange
// language=cs
const string code = @"
[Fact]
public void Analyzer_does_not_report_an_error_if_an_option_has_a_unique_name()
{
// Arrange
// language=cs
const string code = @"
[Command]
public class MyCommand : ICommand
{
@@ -48,16 +48,16 @@ public class MyCommand : ICommand
public ValueTask ExecuteAsync(IConsole console) => default;
}";
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
[Fact]
public void Analyzer_does_not_report_an_error_if_an_option_does_not_have_a_name()
{
// Arrange
// language=cs
const string code = @"
[Fact]
public void Analyzer_does_not_report_an_error_if_an_option_does_not_have_a_name()
{
// Arrange
// language=cs
const string code = @"
[Command]
public class MyCommand : ICommand
{
@@ -67,16 +67,16 @@ public class MyCommand : ICommand
public ValueTask ExecuteAsync(IConsole console) => default;
}";
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
[Fact]
public void Analyzer_does_not_report_an_error_on_a_property_that_is_not_an_option()
{
// Arrange
// language=cs
const string code = @"
[Fact]
public void Analyzer_does_not_report_an_error_on_a_property_that_is_not_an_option()
{
// Arrange
// language=cs
const string code = @"
[Command]
public class MyCommand : ICommand
{
@@ -85,8 +85,7 @@ public class MyCommand : ICommand
public ValueTask ExecuteAsync(IConsole console) => default;
}";
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
}

View File

@@ -2,18 +2,18 @@
using Microsoft.CodeAnalysis.Diagnostics;
using Xunit;
namespace CliFx.Analyzers.Tests
{
public class OptionMustHaveUniqueShortNameAnalyzerSpecs
{
private static DiagnosticAnalyzer Analyzer { get; } = new OptionMustHaveUniqueShortNameAnalyzer();
namespace CliFx.Analyzers.Tests;
[Fact]
public void Analyzer_reports_an_error_if_an_option_has_the_same_short_name_as_another_option()
{
// Arrange
// language=cs
const string code = @"
public class OptionMustHaveUniqueShortNameAnalyzerSpecs
{
private static DiagnosticAnalyzer Analyzer { get; } = new OptionMustHaveUniqueShortNameAnalyzer();
[Fact]
public void Analyzer_reports_an_error_if_an_option_has_the_same_short_name_as_another_option()
{
// Arrange
// language=cs
const string code = @"
[Command]
public class MyCommand : ICommand
{
@@ -26,16 +26,16 @@ public class MyCommand : ICommand
public ValueTask ExecuteAsync(IConsole console) => default;
}";
// Act & assert
Analyzer.Should().ProduceDiagnostics(code);
}
// Act & assert
Analyzer.Should().ProduceDiagnostics(code);
}
[Fact]
public void Analyzer_does_not_report_an_error_if_an_option_has_a_unique_short_name()
{
// Arrange
// language=cs
const string code = @"
[Fact]
public void Analyzer_does_not_report_an_error_if_an_option_has_a_unique_short_name()
{
// Arrange
// language=cs
const string code = @"
[Command]
public class MyCommand : ICommand
{
@@ -48,16 +48,16 @@ public class MyCommand : ICommand
public ValueTask ExecuteAsync(IConsole console) => default;
}";
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
[Fact]
public void Analyzer_does_not_report_an_error_if_an_option_has_a_short_name_which_is_unique_only_in_casing()
{
// Arrange
// language=cs
const string code = @"
[Fact]
public void Analyzer_does_not_report_an_error_if_an_option_has_a_short_name_which_is_unique_only_in_casing()
{
// Arrange
// language=cs
const string code = @"
[Command]
public class MyCommand : ICommand
{
@@ -70,16 +70,16 @@ public class MyCommand : ICommand
public ValueTask ExecuteAsync(IConsole console) => default;
}";
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
[Fact]
public void Analyzer_does_not_report_an_error_if_an_option_does_not_have_a_short_name()
{
// Arrange
// language=cs
const string code = @"
[Fact]
public void Analyzer_does_not_report_an_error_if_an_option_does_not_have_a_short_name()
{
// Arrange
// language=cs
const string code = @"
[Command]
public class MyCommand : ICommand
{
@@ -89,16 +89,16 @@ public class MyCommand : ICommand
public ValueTask ExecuteAsync(IConsole console) => default;
}";
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
[Fact]
public void Analyzer_does_not_report_an_error_on_a_property_that_is_not_an_option()
{
// Arrange
// language=cs
const string code = @"
[Fact]
public void Analyzer_does_not_report_an_error_on_a_property_that_is_not_an_option()
{
// Arrange
// language=cs
const string code = @"
[Command]
public class MyCommand : ICommand
{
@@ -107,8 +107,7 @@ public class MyCommand : ICommand
public ValueTask ExecuteAsync(IConsole console) => default;
}";
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
}

View File

@@ -2,18 +2,18 @@
using Microsoft.CodeAnalysis.Diagnostics;
using Xunit;
namespace CliFx.Analyzers.Tests
{
public class OptionMustHaveValidConverterAnalyzerSpecs
{
private static DiagnosticAnalyzer Analyzer { get; } = new OptionMustHaveValidConverterAnalyzer();
namespace CliFx.Analyzers.Tests;
[Fact]
public void Analyzer_reports_an_error_if_the_specified_option_converter_does_not_derive_from_BindingConverter()
{
// Arrange
// language=cs
const string code = @"
public class OptionMustHaveValidConverterAnalyzerSpecs
{
private static DiagnosticAnalyzer Analyzer { get; } = new OptionMustHaveValidConverterAnalyzer();
[Fact]
public void Analyzer_reports_an_error_if_the_specified_option_converter_does_not_derive_from_BindingConverter()
{
// Arrange
// language=cs
const string code = @"
public class MyConverter
{
public string Convert(string rawValue) => rawValue;
@@ -28,16 +28,16 @@ public class MyCommand : ICommand
public ValueTask ExecuteAsync(IConsole console) => default;
}";
// Act & assert
Analyzer.Should().ProduceDiagnostics(code);
}
// Act & assert
Analyzer.Should().ProduceDiagnostics(code);
}
[Fact]
public void Analyzer_does_not_report_an_error_if_the_specified_option_converter_derives_from_BindingConverter()
{
// Arrange
// language=cs
const string code = @"
[Fact]
public void Analyzer_does_not_report_an_error_if_the_specified_option_converter_derives_from_BindingConverter()
{
// Arrange
// language=cs
const string code = @"
public class MyConverter : BindingConverter<string>
{
public override string Convert(string rawValue) => rawValue;
@@ -52,16 +52,16 @@ public class MyCommand : ICommand
public ValueTask ExecuteAsync(IConsole console) => default;
}";
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
[Fact]
public void Analyzer_does_not_report_an_error_if_an_option_does_not_have_a_converter()
{
// Arrange
// language=cs
const string code = @"
[Fact]
public void Analyzer_does_not_report_an_error_if_an_option_does_not_have_a_converter()
{
// Arrange
// language=cs
const string code = @"
[Command]
public class MyCommand : ICommand
{
@@ -71,16 +71,16 @@ public class MyCommand : ICommand
public ValueTask ExecuteAsync(IConsole console) => default;
}";
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
[Fact]
public void Analyzer_does_not_report_an_error_on_a_property_that_is_not_an_option()
{
// Arrange
// language=cs
const string code = @"
[Fact]
public void Analyzer_does_not_report_an_error_on_a_property_that_is_not_an_option()
{
// Arrange
// language=cs
const string code = @"
[Command]
public class MyCommand : ICommand
{
@@ -89,8 +89,7 @@ public class MyCommand : ICommand
public ValueTask ExecuteAsync(IConsole console) => default;
}";
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
}

View File

@@ -2,18 +2,18 @@
using Microsoft.CodeAnalysis.Diagnostics;
using Xunit;
namespace CliFx.Analyzers.Tests
{
public class OptionMustHaveValidNameAnalyzerSpecs
{
private static DiagnosticAnalyzer Analyzer { get; } = new OptionMustHaveValidNameAnalyzer();
namespace CliFx.Analyzers.Tests;
[Fact]
public void Analyzer_reports_an_error_if_an_option_has_a_name_which_is_too_short()
{
// Arrange
// language=cs
const string code = @"
public class OptionMustHaveValidNameAnalyzerSpecs
{
private static DiagnosticAnalyzer Analyzer { get; } = new OptionMustHaveValidNameAnalyzer();
[Fact]
public void Analyzer_reports_an_error_if_an_option_has_a_name_which_is_too_short()
{
// Arrange
// language=cs
const string code = @"
[Command]
public class MyCommand : ICommand
{
@@ -23,16 +23,16 @@ public class MyCommand : ICommand
public ValueTask ExecuteAsync(IConsole console) => default;
}";
// Act & assert
Analyzer.Should().ProduceDiagnostics(code);
}
// Act & assert
Analyzer.Should().ProduceDiagnostics(code);
}
[Fact]
public void Analyzer_reports_an_error_if_an_option_has_a_name_that_starts_with_a_non_letter_character()
{
// Arrange
// language=cs
const string code = @"
[Fact]
public void Analyzer_reports_an_error_if_an_option_has_a_name_that_starts_with_a_non_letter_character()
{
// Arrange
// language=cs
const string code = @"
[Command]
public class MyCommand : ICommand
{
@@ -42,16 +42,16 @@ public class MyCommand : ICommand
public ValueTask ExecuteAsync(IConsole console) => default;
}";
// Act & assert
Analyzer.Should().ProduceDiagnostics(code);
}
// Act & assert
Analyzer.Should().ProduceDiagnostics(code);
}
[Fact]
public void Analyzer_does_not_report_an_error_if_an_option_has_a_valid_name()
{
// Arrange
// language=cs
const string code = @"
[Fact]
public void Analyzer_does_not_report_an_error_if_an_option_has_a_valid_name()
{
// Arrange
// language=cs
const string code = @"
[Command]
public class MyCommand : ICommand
{
@@ -61,16 +61,16 @@ public class MyCommand : ICommand
public ValueTask ExecuteAsync(IConsole console) => default;
}";
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
[Fact]
public void Analyzer_does_not_report_an_error_if_an_option_does_not_have_a_name()
{
// Arrange
// language=cs
const string code = @"
[Fact]
public void Analyzer_does_not_report_an_error_if_an_option_does_not_have_a_name()
{
// Arrange
// language=cs
const string code = @"
[Command]
public class MyCommand : ICommand
{
@@ -80,16 +80,16 @@ public class MyCommand : ICommand
public ValueTask ExecuteAsync(IConsole console) => default;
}";
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
[Fact]
public void Analyzer_does_not_report_an_error_on_a_property_that_is_not_an_option()
{
// Arrange
// language=cs
const string code = @"
[Fact]
public void Analyzer_does_not_report_an_error_on_a_property_that_is_not_an_option()
{
// Arrange
// language=cs
const string code = @"
[Command]
public class MyCommand : ICommand
{
@@ -98,8 +98,7 @@ public class MyCommand : ICommand
public ValueTask ExecuteAsync(IConsole console) => default;
}";
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
}

View File

@@ -2,18 +2,18 @@
using Microsoft.CodeAnalysis.Diagnostics;
using Xunit;
namespace CliFx.Analyzers.Tests
{
public class OptionMustHaveValidShortNameAnalyzerSpecs
{
private static DiagnosticAnalyzer Analyzer { get; } = new OptionMustHaveValidShortNameAnalyzer();
namespace CliFx.Analyzers.Tests;
[Fact]
public void Analyzer_reports_an_error_if_an_option_has_a_short_name_which_is_not_a_letter_character()
{
// Arrange
// language=cs
const string code = @"
public class OptionMustHaveValidShortNameAnalyzerSpecs
{
private static DiagnosticAnalyzer Analyzer { get; } = new OptionMustHaveValidShortNameAnalyzer();
[Fact]
public void Analyzer_reports_an_error_if_an_option_has_a_short_name_which_is_not_a_letter_character()
{
// Arrange
// language=cs
const string code = @"
[Command]
public class MyCommand : ICommand
{
@@ -23,16 +23,16 @@ public class MyCommand : ICommand
public ValueTask ExecuteAsync(IConsole console) => default;
}";
// Act & assert
Analyzer.Should().ProduceDiagnostics(code);
}
// Act & assert
Analyzer.Should().ProduceDiagnostics(code);
}
[Fact]
public void Analyzer_does_not_report_an_error_if_an_option_has_a_valid_short_name()
{
// Arrange
// language=cs
const string code = @"
[Fact]
public void Analyzer_does_not_report_an_error_if_an_option_has_a_valid_short_name()
{
// Arrange
// language=cs
const string code = @"
[Command]
public class MyCommand : ICommand
{
@@ -42,16 +42,16 @@ public class MyCommand : ICommand
public ValueTask ExecuteAsync(IConsole console) => default;
}";
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
[Fact]
public void Analyzer_does_not_report_an_error_if_an_option_does_not_have_a_short_name()
{
// Arrange
// language=cs
const string code = @"
[Fact]
public void Analyzer_does_not_report_an_error_if_an_option_does_not_have_a_short_name()
{
// Arrange
// language=cs
const string code = @"
[Command]
public class MyCommand : ICommand
{
@@ -61,16 +61,16 @@ public class MyCommand : ICommand
public ValueTask ExecuteAsync(IConsole console) => default;
}";
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
[Fact]
public void Analyzer_does_not_report_an_error_on_a_property_that_is_not_an_option()
{
// Arrange
// language=cs
const string code = @"
[Fact]
public void Analyzer_does_not_report_an_error_on_a_property_that_is_not_an_option()
{
// Arrange
// language=cs
const string code = @"
[Command]
public class MyCommand : ICommand
{
@@ -79,8 +79,7 @@ public class MyCommand : ICommand
public ValueTask ExecuteAsync(IConsole console) => default;
}";
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
}

View File

@@ -2,18 +2,18 @@
using Microsoft.CodeAnalysis.Diagnostics;
using Xunit;
namespace CliFx.Analyzers.Tests
{
public class OptionMustHaveValidValidatorsAnalyzerSpecs
{
private static DiagnosticAnalyzer Analyzer { get; } = new OptionMustHaveValidValidatorsAnalyzer();
namespace CliFx.Analyzers.Tests;
[Fact]
public void Analyzer_reports_an_error_if_one_of_the_specified_option_validators_does_not_derive_from_BindingValidator()
{
// Arrange
// language=cs
const string code = @"
public class OptionMustHaveValidValidatorsAnalyzerSpecs
{
private static DiagnosticAnalyzer Analyzer { get; } = new OptionMustHaveValidValidatorsAnalyzer();
[Fact]
public void Analyzer_reports_an_error_if_one_of_the_specified_option_validators_does_not_derive_from_BindingValidator()
{
// Arrange
// language=cs
const string code = @"
public class MyValidator
{
public void Validate(string value) {}
@@ -28,16 +28,16 @@ public class MyCommand : ICommand
public ValueTask ExecuteAsync(IConsole console) => default;
}";
// Act & assert
Analyzer.Should().ProduceDiagnostics(code);
}
// Act & assert
Analyzer.Should().ProduceDiagnostics(code);
}
[Fact]
public void Analyzer_does_not_report_an_error_if_all_specified_option_validators_derive_from_BindingValidator()
{
// Arrange
// language=cs
const string code = @"
[Fact]
public void Analyzer_does_not_report_an_error_if_all_specified_option_validators_derive_from_BindingValidator()
{
// Arrange
// language=cs
const string code = @"
public class MyValidator : BindingValidator<string>
{
public override BindingValidationError Validate(string value) => Ok();
@@ -52,16 +52,16 @@ public class MyCommand : ICommand
public ValueTask ExecuteAsync(IConsole console) => default;
}";
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
[Fact]
public void Analyzer_does_not_report_an_error_if_an_option_does_not_have_validators()
{
// Arrange
// language=cs
const string code = @"
[Fact]
public void Analyzer_does_not_report_an_error_if_an_option_does_not_have_validators()
{
// Arrange
// language=cs
const string code = @"
[Command]
public class MyCommand : ICommand
{
@@ -71,16 +71,16 @@ public class MyCommand : ICommand
public ValueTask ExecuteAsync(IConsole console) => default;
}";
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
[Fact]
public void Analyzer_does_not_report_an_error_on_a_property_that_is_not_an_option()
{
// Arrange
// language=cs
const string code = @"
[Fact]
public void Analyzer_does_not_report_an_error_on_a_property_that_is_not_an_option()
{
// Arrange
// language=cs
const string code = @"
[Command]
public class MyCommand : ICommand
{
@@ -89,8 +89,7 @@ public class MyCommand : ICommand
public ValueTask ExecuteAsync(IConsole console) => default;
}";
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
}

View File

@@ -2,34 +2,34 @@
using Microsoft.CodeAnalysis.Diagnostics;
using Xunit;
namespace CliFx.Analyzers.Tests
{
public class ParameterMustBeInsideCommandAnalyzerSpecs
{
private static DiagnosticAnalyzer Analyzer { get; } = new ParameterMustBeInsideCommandAnalyzer();
namespace CliFx.Analyzers.Tests;
[Fact]
public void Analyzer_reports_an_error_if_a_parameter_is_inside_a_class_that_is_not_a_command()
{
// Arrange
// language=cs
const string code = @"
public class ParameterMustBeInsideCommandAnalyzerSpecs
{
private static DiagnosticAnalyzer Analyzer { get; } = new ParameterMustBeInsideCommandAnalyzer();
[Fact]
public void Analyzer_reports_an_error_if_a_parameter_is_inside_a_class_that_is_not_a_command()
{
// Arrange
// language=cs
const string code = @"
public class MyClass
{
[CommandParameter(0)]
public string Foo { get; set; }
}";
// Act & assert
Analyzer.Should().ProduceDiagnostics(code);
}
// Act & assert
Analyzer.Should().ProduceDiagnostics(code);
}
[Fact]
public void Analyzer_does_not_report_an_error_if_a_parameter_is_inside_a_command()
{
// Arrange
// language=cs
const string code = @"
[Fact]
public void Analyzer_does_not_report_an_error_if_a_parameter_is_inside_a_command()
{
// Arrange
// language=cs
const string code = @"
[Command]
public class MyCommand : ICommand
{
@@ -39,32 +39,32 @@ public class MyCommand : ICommand
public ValueTask ExecuteAsync(IConsole console) => default;
}";
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
[Fact]
public void Analyzer_does_not_report_an_error_if_a_parameter_is_inside_an_abstract_class()
{
// Arrange
// language=cs
const string code = @"
[Fact]
public void Analyzer_does_not_report_an_error_if_a_parameter_is_inside_an_abstract_class()
{
// Arrange
// language=cs
const string code = @"
public abstract class MyCommand
{
[CommandParameter(0)]
public string Foo { get; set; }
}";
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
[Fact]
public void Analyzer_does_not_report_an_error_on_a_property_that_is_not_a_parameter()
{
// Arrange
// language=cs
const string code = @"
[Fact]
public void Analyzer_does_not_report_an_error_on_a_property_that_is_not_a_parameter()
{
// Arrange
// language=cs
const string code = @"
[Command]
public class MyCommand : ICommand
{
@@ -73,8 +73,7 @@ public class MyCommand : ICommand
public ValueTask ExecuteAsync(IConsole console) => default;
}";
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
}

View File

@@ -2,18 +2,18 @@
using Microsoft.CodeAnalysis.Diagnostics;
using Xunit;
namespace CliFx.Analyzers.Tests
{
public class ParameterMustBeLastIfNonScalarAnalyzerSpecs
{
private static DiagnosticAnalyzer Analyzer { get; } = new ParameterMustBeLastIfNonScalarAnalyzer();
namespace CliFx.Analyzers.Tests;
[Fact]
public void Analyzer_reports_an_error_if_a_non_scalar_parameter_is_not_last_in_order()
{
// Arrange
// language=cs
const string code = @"
public class ParameterMustBeLastIfNonScalarAnalyzerSpecs
{
private static DiagnosticAnalyzer Analyzer { get; } = new ParameterMustBeLastIfNonScalarAnalyzer();
[Fact]
public void Analyzer_reports_an_error_if_a_non_scalar_parameter_is_not_last_in_order()
{
// Arrange
// language=cs
const string code = @"
[Command]
public class MyCommand : ICommand
{
@@ -26,16 +26,16 @@ public class MyCommand : ICommand
public ValueTask ExecuteAsync(IConsole console) => default;
}";
// Act & assert
Analyzer.Should().ProduceDiagnostics(code);
}
// Act & assert
Analyzer.Should().ProduceDiagnostics(code);
}
[Fact]
public void Analyzer_does_not_report_an_error_if_a_non_scalar_parameter_is_last_in_order()
{
// Arrange
// language=cs
const string code = @"
[Fact]
public void Analyzer_does_not_report_an_error_if_a_non_scalar_parameter_is_last_in_order()
{
// Arrange
// language=cs
const string code = @"
[Command]
public class MyCommand : ICommand
{
@@ -48,16 +48,16 @@ public class MyCommand : ICommand
public ValueTask ExecuteAsync(IConsole console) => default;
}";
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
[Fact]
public void Analyzer_does_not_report_an_error_if_no_non_scalar_parameters_are_defined()
{
// Arrange
// language=cs
const string code = @"
[Fact]
public void Analyzer_does_not_report_an_error_if_no_non_scalar_parameters_are_defined()
{
// Arrange
// language=cs
const string code = @"
[Command]
public class MyCommand : ICommand
{
@@ -70,16 +70,16 @@ public class MyCommand : ICommand
public ValueTask ExecuteAsync(IConsole console) => default;
}";
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
[Fact]
public void Analyzer_does_not_report_an_error_on_a_property_that_is_not_a_parameter()
{
// Arrange
// language=cs
const string code = @"
[Fact]
public void Analyzer_does_not_report_an_error_on_a_property_that_is_not_a_parameter()
{
// Arrange
// language=cs
const string code = @"
[Command]
public class MyCommand : ICommand
{
@@ -88,8 +88,7 @@ public class MyCommand : ICommand
public ValueTask ExecuteAsync(IConsole console) => default;
}";
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
}

View File

@@ -2,18 +2,18 @@
using Microsoft.CodeAnalysis.Diagnostics;
using Xunit;
namespace CliFx.Analyzers.Tests
{
public class ParameterMustBeSingleIfNonScalarAnalyzerSpecs
{
private static DiagnosticAnalyzer Analyzer { get; } = new ParameterMustBeSingleIfNonScalarAnalyzer();
namespace CliFx.Analyzers.Tests;
[Fact]
public void Analyzer_reports_an_error_if_more_than_one_non_scalar_parameters_are_defined()
{
// Arrange
// language=cs
const string code = @"
public class ParameterMustBeSingleIfNonScalarAnalyzerSpecs
{
private static DiagnosticAnalyzer Analyzer { get; } = new ParameterMustBeSingleIfNonScalarAnalyzer();
[Fact]
public void Analyzer_reports_an_error_if_more_than_one_non_scalar_parameters_are_defined()
{
// Arrange
// language=cs
const string code = @"
[Command]
public class MyCommand : ICommand
{
@@ -26,16 +26,16 @@ public class MyCommand : ICommand
public ValueTask ExecuteAsync(IConsole console) => default;
}";
// Act & assert
Analyzer.Should().ProduceDiagnostics(code);
}
// Act & assert
Analyzer.Should().ProduceDiagnostics(code);
}
[Fact]
public void Analyzer_does_not_report_an_error_if_only_one_non_scalar_parameter_is_defined()
{
// Arrange
// language=cs
const string code = @"
[Fact]
public void Analyzer_does_not_report_an_error_if_only_one_non_scalar_parameter_is_defined()
{
// Arrange
// language=cs
const string code = @"
[Command]
public class MyCommand : ICommand
{
@@ -48,16 +48,16 @@ public class MyCommand : ICommand
public ValueTask ExecuteAsync(IConsole console) => default;
}";
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
[Fact]
public void Analyzer_does_not_report_an_error_if_no_non_scalar_parameters_are_defined()
{
// Arrange
// language=cs
const string code = @"
[Fact]
public void Analyzer_does_not_report_an_error_if_no_non_scalar_parameters_are_defined()
{
// Arrange
// language=cs
const string code = @"
[Command]
public class MyCommand : ICommand
{
@@ -70,16 +70,16 @@ public class MyCommand : ICommand
public ValueTask ExecuteAsync(IConsole console) => default;
}";
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
[Fact]
public void Analyzer_does_not_report_an_error_on_a_property_that_is_not_a_parameter()
{
// Arrange
// language=cs
const string code = @"
[Fact]
public void Analyzer_does_not_report_an_error_on_a_property_that_is_not_a_parameter()
{
// Arrange
// language=cs
const string code = @"
[Command]
public class MyCommand : ICommand
{
@@ -88,8 +88,7 @@ public class MyCommand : ICommand
public ValueTask ExecuteAsync(IConsole console) => default;
}";
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
}

View File

@@ -2,18 +2,18 @@
using Microsoft.CodeAnalysis.Diagnostics;
using Xunit;
namespace CliFx.Analyzers.Tests
{
public class ParameterMustHaveUniqueNameAnalyzerSpecs
{
private static DiagnosticAnalyzer Analyzer { get; } = new ParameterMustHaveUniqueNameAnalyzer();
namespace CliFx.Analyzers.Tests;
[Fact]
public void Analyzer_reports_an_error_if_a_parameter_has_the_same_name_as_another_parameter()
{
// Arrange
// language=cs
const string code = @"
public class ParameterMustHaveUniqueNameAnalyzerSpecs
{
private static DiagnosticAnalyzer Analyzer { get; } = new ParameterMustHaveUniqueNameAnalyzer();
[Fact]
public void Analyzer_reports_an_error_if_a_parameter_has_the_same_name_as_another_parameter()
{
// Arrange
// language=cs
const string code = @"
[Command]
public class MyCommand : ICommand
{
@@ -26,16 +26,16 @@ public class MyCommand : ICommand
public ValueTask ExecuteAsync(IConsole console) => default;
}";
// Act & assert
Analyzer.Should().ProduceDiagnostics(code);
}
// Act & assert
Analyzer.Should().ProduceDiagnostics(code);
}
[Fact]
public void Analyzer_does_not_report_an_error_if_a_parameter_has_unique_name()
{
// Arrange
// language=cs
const string code = @"
[Fact]
public void Analyzer_does_not_report_an_error_if_a_parameter_has_unique_name()
{
// Arrange
// language=cs
const string code = @"
[Command]
public class MyCommand : ICommand
{
@@ -48,16 +48,16 @@ public class MyCommand : ICommand
public ValueTask ExecuteAsync(IConsole console) => default;
}";
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
[Fact]
public void Analyzer_does_not_report_an_error_on_a_property_that_is_not_a_parameter()
{
// Arrange
// language=cs
const string code = @"
[Fact]
public void Analyzer_does_not_report_an_error_on_a_property_that_is_not_a_parameter()
{
// Arrange
// language=cs
const string code = @"
[Command]
public class MyCommand : ICommand
{
@@ -66,8 +66,7 @@ public class MyCommand : ICommand
public ValueTask ExecuteAsync(IConsole console) => default;
}";
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
}

View File

@@ -2,18 +2,18 @@
using Microsoft.CodeAnalysis.Diagnostics;
using Xunit;
namespace CliFx.Analyzers.Tests
{
public class ParameterMustHaveUniqueOrderAnalyzerSpecs
{
private static DiagnosticAnalyzer Analyzer { get; } = new ParameterMustHaveUniqueOrderAnalyzer();
namespace CliFx.Analyzers.Tests;
[Fact]
public void Analyzer_reports_an_error_if_a_parameter_has_the_same_order_as_another_parameter()
{
// Arrange
// language=cs
const string code = @"
public class ParameterMustHaveUniqueOrderAnalyzerSpecs
{
private static DiagnosticAnalyzer Analyzer { get; } = new ParameterMustHaveUniqueOrderAnalyzer();
[Fact]
public void Analyzer_reports_an_error_if_a_parameter_has_the_same_order_as_another_parameter()
{
// Arrange
// language=cs
const string code = @"
[Command]
public class MyCommand : ICommand
{
@@ -26,16 +26,16 @@ public class MyCommand : ICommand
public ValueTask ExecuteAsync(IConsole console) => default;
}";
// Act & assert
Analyzer.Should().ProduceDiagnostics(code);
}
// Act & assert
Analyzer.Should().ProduceDiagnostics(code);
}
[Fact]
public void Analyzer_does_not_report_an_error_if_a_parameter_has_unique_order()
{
// Arrange
// language=cs
const string code = @"
[Fact]
public void Analyzer_does_not_report_an_error_if_a_parameter_has_unique_order()
{
// Arrange
// language=cs
const string code = @"
[Command]
public class MyCommand : ICommand
{
@@ -48,16 +48,16 @@ public class MyCommand : ICommand
public ValueTask ExecuteAsync(IConsole console) => default;
}";
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
[Fact]
public void Analyzer_does_not_report_an_error_on_a_property_that_is_not_a_parameter()
{
// Arrange
// language=cs
const string code = @"
[Fact]
public void Analyzer_does_not_report_an_error_on_a_property_that_is_not_a_parameter()
{
// Arrange
// language=cs
const string code = @"
[Command]
public class MyCommand : ICommand
{
@@ -66,8 +66,7 @@ public class MyCommand : ICommand
public ValueTask ExecuteAsync(IConsole console) => default;
}";
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
}

View File

@@ -2,18 +2,18 @@
using Microsoft.CodeAnalysis.Diagnostics;
using Xunit;
namespace CliFx.Analyzers.Tests
{
public class ParameterMustHaveValidConverterAnalyzerSpecs
{
private static DiagnosticAnalyzer Analyzer { get; } = new ParameterMustHaveValidConverterAnalyzer();
namespace CliFx.Analyzers.Tests;
[Fact]
public void Analyzer_reports_an_error_if_the_specified_parameter_converter_does_not_derive_from_BindingConverter()
{
// Arrange
// language=cs
const string code = @"
public class ParameterMustHaveValidConverterAnalyzerSpecs
{
private static DiagnosticAnalyzer Analyzer { get; } = new ParameterMustHaveValidConverterAnalyzer();
[Fact]
public void Analyzer_reports_an_error_if_the_specified_parameter_converter_does_not_derive_from_BindingConverter()
{
// Arrange
// language=cs
const string code = @"
public class MyConverter
{
public string Convert(string rawValue) => rawValue;
@@ -28,16 +28,16 @@ public class MyCommand : ICommand
public ValueTask ExecuteAsync(IConsole console) => default;
}";
// Act & assert
Analyzer.Should().ProduceDiagnostics(code);
}
// Act & assert
Analyzer.Should().ProduceDiagnostics(code);
}
[Fact]
public void Analyzer_does_not_report_an_error_if_the_specified_parameter_converter_derives_from_BindingConverter()
{
// Arrange
// language=cs
const string code = @"
[Fact]
public void Analyzer_does_not_report_an_error_if_the_specified_parameter_converter_derives_from_BindingConverter()
{
// Arrange
// language=cs
const string code = @"
public class MyConverter : BindingConverter<string>
{
public override string Convert(string rawValue) => rawValue;
@@ -52,16 +52,16 @@ public class MyCommand : ICommand
public ValueTask ExecuteAsync(IConsole console) => default;
}";
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
[Fact]
public void Analyzer_does_not_report_an_error_if_a_parameter_does_not_have_a_converter()
{
// Arrange
// language=cs
const string code = @"
[Fact]
public void Analyzer_does_not_report_an_error_if_a_parameter_does_not_have_a_converter()
{
// Arrange
// language=cs
const string code = @"
[Command]
public class MyCommand : ICommand
{
@@ -71,16 +71,16 @@ public class MyCommand : ICommand
public ValueTask ExecuteAsync(IConsole console) => default;
}";
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
[Fact]
public void Analyzer_does_not_report_an_error_on_a_property_that_is_not_a_parameter()
{
// Arrange
// language=cs
const string code = @"
[Fact]
public void Analyzer_does_not_report_an_error_on_a_property_that_is_not_a_parameter()
{
// Arrange
// language=cs
const string code = @"
[Command]
public class MyCommand : ICommand
{
@@ -89,8 +89,7 @@ public class MyCommand : ICommand
public ValueTask ExecuteAsync(IConsole console) => default;
}";
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
}

View File

@@ -2,18 +2,18 @@
using Microsoft.CodeAnalysis.Diagnostics;
using Xunit;
namespace CliFx.Analyzers.Tests
{
public class ParameterMustHaveValidValidatorsAnalyzerSpecs
{
private static DiagnosticAnalyzer Analyzer { get; } = new ParameterMustHaveValidValidatorsAnalyzer();
namespace CliFx.Analyzers.Tests;
[Fact]
public void Analyzer_reports_an_error_if_one_of_the_specified_parameter_validators_does_not_derive_from_BindingValidator()
{
// Arrange
// language=cs
const string code = @"
public class ParameterMustHaveValidValidatorsAnalyzerSpecs
{
private static DiagnosticAnalyzer Analyzer { get; } = new ParameterMustHaveValidValidatorsAnalyzer();
[Fact]
public void Analyzer_reports_an_error_if_one_of_the_specified_parameter_validators_does_not_derive_from_BindingValidator()
{
// Arrange
// language=cs
const string code = @"
public class MyValidator
{
public void Validate(string value) {}
@@ -28,16 +28,16 @@ public class MyCommand : ICommand
public ValueTask ExecuteAsync(IConsole console) => default;
}";
// Act & assert
Analyzer.Should().ProduceDiagnostics(code);
}
// Act & assert
Analyzer.Should().ProduceDiagnostics(code);
}
[Fact]
public void Analyzer_does_not_report_an_error_if_all_specified_parameter_validators_derive_from_BindingValidator()
{
// Arrange
// language=cs
const string code = @"
[Fact]
public void Analyzer_does_not_report_an_error_if_all_specified_parameter_validators_derive_from_BindingValidator()
{
// Arrange
// language=cs
const string code = @"
public class MyValidator : BindingValidator<string>
{
public override BindingValidationError Validate(string value) => Ok();
@@ -52,16 +52,16 @@ public class MyCommand : ICommand
public ValueTask ExecuteAsync(IConsole console) => default;
}";
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
[Fact]
public void Analyzer_does_not_report_an_error_if_a_parameter_does_not_have_validators()
{
// Arrange
// language=cs
const string code = @"
[Fact]
public void Analyzer_does_not_report_an_error_if_a_parameter_does_not_have_validators()
{
// Arrange
// language=cs
const string code = @"
[Command]
public class MyCommand : ICommand
{
@@ -71,16 +71,16 @@ public class MyCommand : ICommand
public ValueTask ExecuteAsync(IConsole console) => default;
}";
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
[Fact]
public void Analyzer_does_not_report_an_error_on_a_property_that_is_not_a_parameter()
{
// Arrange
// language=cs
const string code = @"
[Fact]
public void Analyzer_does_not_report_an_error_on_a_property_that_is_not_a_parameter()
{
// Arrange
// language=cs
const string code = @"
[Command]
public class MyCommand : ICommand
{
@@ -89,8 +89,7 @@ public class MyCommand : ICommand
public ValueTask ExecuteAsync(IConsole console) => default;
}";
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
}

View File

@@ -2,18 +2,18 @@
using Microsoft.CodeAnalysis.Diagnostics;
using Xunit;
namespace CliFx.Analyzers.Tests
{
public class SystemConsoleShouldBeAvoidedAnalyzerSpecs
{
private static DiagnosticAnalyzer Analyzer { get; } = new SystemConsoleShouldBeAvoidedAnalyzer();
namespace CliFx.Analyzers.Tests;
[Fact]
public void Analyzer_reports_an_error_if_a_command_calls_a_method_on_SystemConsole()
{
// Arrange
// language=cs
const string code = @"
public class SystemConsoleShouldBeAvoidedAnalyzerSpecs
{
private static DiagnosticAnalyzer Analyzer { get; } = new SystemConsoleShouldBeAvoidedAnalyzer();
[Fact]
public void Analyzer_reports_an_error_if_a_command_calls_a_method_on_SystemConsole()
{
// Arrange
// language=cs
const string code = @"
[Command]
public class MyCommand : ICommand
{
@@ -24,16 +24,16 @@ public class MyCommand : ICommand
}
}";
// Act & assert
Analyzer.Should().ProduceDiagnostics(code);
}
// Act & assert
Analyzer.Should().ProduceDiagnostics(code);
}
[Fact]
public void Analyzer_reports_an_error_if_a_command_accesses_a_property_on_SystemConsole()
{
// Arrange
// language=cs
const string code = @"
[Fact]
public void Analyzer_reports_an_error_if_a_command_accesses_a_property_on_SystemConsole()
{
// Arrange
// language=cs
const string code = @"
[Command]
public class MyCommand : ICommand
{
@@ -43,16 +43,16 @@ public class MyCommand : ICommand
return default;
}
}";
// Act & assert
Analyzer.Should().ProduceDiagnostics(code);
}
// Act & assert
Analyzer.Should().ProduceDiagnostics(code);
}
[Fact]
public void Analyzer_reports_an_error_if_a_command_calls_a_method_on_a_property_of_SystemConsole()
{
// Arrange
// language=cs
const string code = @"
[Fact]
public void Analyzer_reports_an_error_if_a_command_calls_a_method_on_a_property_of_SystemConsole()
{
// Arrange
// language=cs
const string code = @"
[Command]
public class MyCommand : ICommand
{
@@ -63,16 +63,16 @@ public class MyCommand : ICommand
}
}";
// Act & assert
Analyzer.Should().ProduceDiagnostics(code);
}
// Act & assert
Analyzer.Should().ProduceDiagnostics(code);
}
[Fact]
public void Analyzer_does_not_report_an_error_if_a_command_interacts_with_the_console_through_IConsole()
{
// Arrange
// language=cs
const string code = @"
[Fact]
public void Analyzer_does_not_report_an_error_if_a_command_interacts_with_the_console_through_IConsole()
{
// Arrange
// language=cs
const string code = @"
[Command]
public class MyCommand : ICommand
{
@@ -83,16 +83,16 @@ public class MyCommand : ICommand
}
}";
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
[Fact]
public void Analyzer_does_not_report_an_error_if_IConsole_is_not_available_in_the_current_method()
{
// Arrange
// language=cs
const string code = @"
[Fact]
public void Analyzer_does_not_report_an_error_if_IConsole_is_not_available_in_the_current_method()
{
// Arrange
// language=cs
const string code = @"
[Command]
public class MyCommand : ICommand
{
@@ -101,16 +101,16 @@ public class MyCommand : ICommand
public ValueTask ExecuteAsync(IConsole console) => default;
}";
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
[Fact]
public void Analyzer_does_not_report_an_error_if_a_command_does_not_access_SystemConsole()
{
// Arrange
// language=cs
const string code = @"
[Fact]
public void Analyzer_does_not_report_an_error_if_a_command_does_not_access_SystemConsole()
{
// Arrange
// language=cs
const string code = @"
[Command]
public class MyCommand : ICommand
{
@@ -120,8 +120,7 @@ public class MyCommand : ICommand
}
}";
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
// Act & assert
Analyzer.Should().NotProduceDiagnostics(code);
}
}

View File

@@ -11,158 +11,157 @@ using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Text;
namespace CliFx.Analyzers.Tests.Utils
{
internal class AnalyzerAssertions : ReferenceTypeAssertions<DiagnosticAnalyzer, AnalyzerAssertions>
{
protected override string Identifier { get; } = "analyzer";
namespace CliFx.Analyzers.Tests.Utils;
public AnalyzerAssertions(DiagnosticAnalyzer analyzer)
: base(analyzer)
internal class AnalyzerAssertions : ReferenceTypeAssertions<DiagnosticAnalyzer, AnalyzerAssertions>
{
protected override string Identifier { get; } = "analyzer";
public AnalyzerAssertions(DiagnosticAnalyzer analyzer)
: base(analyzer)
{
}
private Compilation Compile(string sourceCode)
{
// Get default system namespaces
var defaultSystemNamespaces = new[]
{
"System",
"System.Collections.Generic",
"System.Threading.Tasks"
};
// Get default CliFx namespaces
var defaultCliFxNamespaces = typeof(ICommand)
.Assembly
.GetTypes()
.Where(t => t.IsPublic)
.Select(t => t.Namespace)
.Distinct()
.ToArray();
// Append default imports to the source code
var sourceCodeWithUsings =
string.Join(Environment.NewLine, defaultSystemNamespaces.Select(n => $"using {n};")) +
string.Join(Environment.NewLine, defaultCliFxNamespaces.Select(n => $"using {n};")) +
Environment.NewLine +
sourceCode;
// Parse the source code
var ast = SyntaxFactory.ParseSyntaxTree(
SourceText.From(sourceCodeWithUsings),
CSharpParseOptions.Default
);
// Compile the code to IL
var compilation = CSharpCompilation.Create(
"CliFxTests_DynamicAssembly_" + Guid.NewGuid(),
new[] {ast},
ReferenceAssemblies.Net50
.Append(MetadataReference.CreateFromFile(typeof(ICommand).Assembly.Location)),
// DLL to avoid having to define the Main() method
new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)
);
var compilationErrors = compilation
.GetDiagnostics()
.Where(d => d.Severity >= DiagnosticSeverity.Error)
.ToArray();
if (compilationErrors.Any())
{
throw new InvalidOperationException(
"Failed to compile code." +
Environment.NewLine +
string.Join(Environment.NewLine, compilationErrors.Select(e => e.ToString()))
);
}
private Compilation Compile(string sourceCode)
return compilation;
}
private IReadOnlyList<Diagnostic> GetProducedDiagnostics(string sourceCode)
{
var analyzers = ImmutableArray.Create(Subject);
var compilation = Compile(sourceCode);
return compilation
.WithAnalyzers(analyzers)
.GetAnalyzerDiagnosticsAsync(analyzers, default)
.GetAwaiter()
.GetResult();
}
public void ProduceDiagnostics(string sourceCode)
{
var expectedDiagnostics = Subject.SupportedDiagnostics;
var producedDiagnostics = GetProducedDiagnostics(sourceCode);
var expectedDiagnosticIds = expectedDiagnostics.Select(d => d.Id).Distinct().ToArray();
var producedDiagnosticIds = producedDiagnostics.Select(d => d.Id).Distinct().ToArray();
var result =
expectedDiagnosticIds.Intersect(producedDiagnosticIds).Count() ==
expectedDiagnosticIds.Length;
Execute.Assertion.ForCondition(result).FailWith(() =>
{
// Get default system namespaces
var defaultSystemNamespaces = new[]
var buffer = new StringBuilder();
buffer.AppendLine("Expected and produced diagnostics do not match.");
buffer.AppendLine();
buffer.AppendLine("Expected diagnostics:");
foreach (var expectedDiagnostic in expectedDiagnostics)
{
"System",
"System.Collections.Generic",
"System.Threading.Tasks"
};
// Get default CliFx namespaces
var defaultCliFxNamespaces = typeof(ICommand)
.Assembly
.GetTypes()
.Where(t => t.IsPublic)
.Select(t => t.Namespace)
.Distinct()
.ToArray();
// Append default imports to the source code
var sourceCodeWithUsings =
string.Join(Environment.NewLine, defaultSystemNamespaces.Select(n => $"using {n};")) +
string.Join(Environment.NewLine, defaultCliFxNamespaces.Select(n => $"using {n};")) +
Environment.NewLine +
sourceCode;
// Parse the source code
var ast = SyntaxFactory.ParseSyntaxTree(
SourceText.From(sourceCodeWithUsings),
CSharpParseOptions.Default
);
// Compile the code to IL
var compilation = CSharpCompilation.Create(
"CliFxTests_DynamicAssembly_" + Guid.NewGuid(),
new[] {ast},
ReferenceAssemblies.Net50
.Append(MetadataReference.CreateFromFile(typeof(ICommand).Assembly.Location)),
// DLL to avoid having to define the Main() method
new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)
);
var compilationErrors = compilation
.GetDiagnostics()
.Where(d => d.Severity >= DiagnosticSeverity.Error)
.ToArray();
if (compilationErrors.Any())
{
throw new InvalidOperationException(
"Failed to compile code." +
Environment.NewLine +
string.Join(Environment.NewLine, compilationErrors.Select(e => e.ToString()))
);
buffer.Append(" - ");
buffer.Append(expectedDiagnostic.Id);
buffer.AppendLine();
}
return compilation;
}
buffer.AppendLine();
private IReadOnlyList<Diagnostic> GetProducedDiagnostics(string sourceCode)
{
var analyzers = ImmutableArray.Create(Subject);
var compilation = Compile(sourceCode);
buffer.AppendLine("Produced diagnostics:");
return compilation
.WithAnalyzers(analyzers)
.GetAnalyzerDiagnosticsAsync(analyzers, default)
.GetAwaiter()
.GetResult();
}
public void ProduceDiagnostics(string sourceCode)
{
var expectedDiagnostics = Subject.SupportedDiagnostics;
var producedDiagnostics = GetProducedDiagnostics(sourceCode);
var expectedDiagnosticIds = expectedDiagnostics.Select(d => d.Id).Distinct().ToArray();
var producedDiagnosticIds = producedDiagnostics.Select(d => d.Id).Distinct().ToArray();
var result =
expectedDiagnosticIds.Intersect(producedDiagnosticIds).Count() ==
expectedDiagnosticIds.Length;
Execute.Assertion.ForCondition(result).FailWith(() =>
foreach (var producedDiagnostic in producedDiagnostics)
{
var buffer = new StringBuilder();
buffer.Append(" - ");
buffer.Append(producedDiagnostic);
}
buffer.AppendLine("Expected and produced diagnostics do not match.");
buffer.AppendLine();
buffer.AppendLine("Expected diagnostics:");
foreach (var expectedDiagnostic in expectedDiagnostics)
{
buffer.Append(" - ");
buffer.Append(expectedDiagnostic.Id);
buffer.AppendLine();
}
buffer.AppendLine();
buffer.AppendLine("Produced diagnostics:");
foreach (var producedDiagnostic in producedDiagnostics)
{
buffer.Append(" - ");
buffer.Append(producedDiagnostic);
}
return new FailReason(buffer.ToString());
});
}
public void NotProduceDiagnostics(string sourceCode)
{
var producedDiagnostics = GetProducedDiagnostics(sourceCode);
var result = !producedDiagnostics.Any();
Execute.Assertion.ForCondition(result).FailWith(() =>
{
var buffer = new StringBuilder();
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());
});
}
return new FailReason(buffer.ToString());
});
}
internal static class AnalyzerAssertionsExtensions
public void NotProduceDiagnostics(string sourceCode)
{
public static AnalyzerAssertions Should(this DiagnosticAnalyzer analyzer) => new(analyzer);
var producedDiagnostics = GetProducedDiagnostics(sourceCode);
var result = !producedDiagnostics.Any();
Execute.Assertion.ForCondition(result).FailWith(() =>
{
var buffer = new StringBuilder();
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
{
public static AnalyzerAssertions Should(this DiagnosticAnalyzer analyzer) => new(analyzer);
}