diff --git a/Directory.Build.props b/Directory.Build.props index c275881..fa3b16f 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -11,4 +11,8 @@ Meziantou.Analyzer + + + 2025 + diff --git a/Directory.Packages.props b/Directory.Packages.props index 46bad5c..53c9ab8 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -9,7 +9,8 @@ - + + diff --git a/src/NetEvolve.Arguments.Analyser/SyntaxHelpers.cs b/src/NetEvolve.Arguments.Analyser/SyntaxHelpers.cs index ef35504..5ca20cd 100644 --- a/src/NetEvolve.Arguments.Analyser/SyntaxHelpers.cs +++ b/src/NetEvolve.Arguments.Analyser/SyntaxHelpers.cs @@ -1,4 +1,4 @@ -namespace NetEvolve.Arguments.Analyser; +namespace NetEvolve.Arguments.Analyser; using System; using System.Globalization; @@ -39,8 +39,8 @@ public static ExpressionSyntax Unwrap(ExpressionSyntax expression) return expression; } - /// Gets the single throw statement a statement consists of, whether written directly or as the sole statement of a block. - /// The statement to inspect, typically the body of an if statement. + /// Gets the single statement a statement consists of, whether written directly or as the sole statement of a block. + /// The statement to inspect, typically the body of an statement. /// The if is a throw statement, or a block containing exactly one; otherwise, . public static ThrowStatementSyntax? GetSingleThrowStatement(StatementSyntax statement) { @@ -62,7 +62,7 @@ public static ExpressionSyntax Unwrap(ExpressionSyntax expression) /// Determines whether an object-creation expression constructs exactly the given exception type. /// The semantic model used to resolve the created type. - /// The new expression to inspect. + /// The expression to inspect. /// The fully-qualified metadata name of the expected exception type, e.g. System.ArgumentException. /// The token used to cancel semantic-model lookups. /// if constructs exactly the named type; otherwise, . @@ -73,6 +73,8 @@ public static bool IsExceptionType( CancellationToken cancellationToken ) { + cancellationToken.ThrowIfCancellationRequested(); + var typeInfo = semanticModel.GetTypeInfo(objectCreation, cancellationToken); var exceptionType = semanticModel.Compilation.GetTypeByMetadataName(fullyQualifiedMetadataName); @@ -80,15 +82,15 @@ CancellationToken cancellationToken } /// - /// Recognizes the common shape every rule in this package requires of the if statement's body: no else - /// clause, a single throw statement, and an object-creation expression of exactly the given exception type. + /// Recognizes the common shape every rule in this package requires of the statement's body: no + /// clause, a single statement, and an object-creation expression of exactly the given exception type. /// - /// The if statement to inspect. + /// The statement to inspect. /// The semantic model used to resolve the thrown exception's type. /// The fully-qualified metadata name of the expected exception type. /// The token used to cancel semantic-model lookups. - /// When this method returns , the matched new expression; otherwise, . - /// if the if statement matches the shape; otherwise, . + /// When this method returns , the matched expression; otherwise, . + /// if the statement matches the shape; otherwise, . public static bool TryGetThrownException( IfStatementSyntax ifStatement, SemanticModel semanticModel, @@ -97,6 +99,8 @@ public static bool TryGetThrownException( out ObjectCreationExpressionSyntax? objectCreation ) { + cancellationToken.ThrowIfCancellationRequested(); + objectCreation = null; if (ifStatement.Else is not null) @@ -121,10 +125,10 @@ out ObjectCreationExpressionSyntax? objectCreation } /// - /// Recognizes an if condition that is true precisely when an expression is — covering + /// Recognizes an condition that is true precisely when an expression is — covering /// is null/is not null, ==/!=, ReferenceEquals, and any number of enclosing ! negations. /// - /// The if statement's condition expression. + /// The statement's condition expression. /// When this method returns , the expression being null-checked; otherwise, . /// if is a recognized "argument is null" shape; otherwise, . public static bool TryGetNullCheckedExpression(ExpressionSyntax condition, out ExpressionSyntax? argument) @@ -264,6 +268,8 @@ public static bool TryGetCoalesceNullCheck( out ExpressionSyntax? argument ) { + cancellationToken.ThrowIfCancellationRequested(); + argument = null; if (!binary.IsKind(SyntaxKind.CoalesceExpression)) @@ -324,12 +330,12 @@ public static bool IsZeroLiteral(ExpressionSyntax expression) } var text = literal.Token.ValueText; - return double.TryParse(text, NumberStyles.Any, CultureInfo.InvariantCulture, out var value) && value == 0; + return double.TryParse(text, NumberStyles.Any, CultureInfo.InvariantCulture, out var value) && value == 0D; } - /// Determines whether an expression is the default literal or an explicitly-typed default(T) expression. + /// Determines whether an expression is the literal or an explicitly-typed default(T) expression. /// The expression to test. - /// if is default or default(T); otherwise, . + /// if is or default(T); otherwise, . public static bool IsDefaultLiteral(ExpressionSyntax expression) => Unwrap(expression) switch { diff --git a/src/NetEvolve.Arguments.Analyser/ThrowIfContainsWhiteSpaceAnalyzer.cs b/src/NetEvolve.Arguments.Analyser/ThrowIfContainsWhiteSpaceAnalyzer.cs index 5be76e6..21c3190 100644 --- a/src/NetEvolve.Arguments.Analyser/ThrowIfContainsWhiteSpaceAnalyzer.cs +++ b/src/NetEvolve.Arguments.Analyser/ThrowIfContainsWhiteSpaceAnalyzer.cs @@ -1,4 +1,4 @@ -namespace NetEvolve.Arguments.Analyser; +namespace NetEvolve.Arguments.Analyser; using System; using System.Collections.Immutable; @@ -32,8 +32,8 @@ public override void Initialize(AnalysisContext context) context.RegisterSyntaxNodeAction(Analyze, SyntaxKind.IfStatement); } - /// Analyzes an if statement and reports NEA0008 when it is a white-space-check-then-throw of . - /// The syntax-node analysis context for the if statement being visited. + /// Analyzes an statement and reports NEA0008 when it is a white-space-check-then-throw of . + /// The syntax-node analysis context for the statement being visited. private static void Analyze(SyntaxNodeAnalysisContext context) { var ifStatement = (IfStatementSyntax)context.Node; @@ -106,7 +106,7 @@ out var objectCreation /// arg.Where(char.IsWhiteSpace).Any(). /// /// - /// The if statement's condition expression. + /// The statement's condition expression. /// When this method returns , the string argument being checked; otherwise, . /// /// When this method returns , the invocation(s) that must still be confirmed (via the @@ -377,7 +377,7 @@ CancellationToken cancellationToken && method.Name == expectedMethodName && containingType.ToDisplayString() == "System.Linq.Enumerable"; - /// Determines whether an expression is a char.IsWhiteSpace member access, either via the char keyword or the Char identifier. + /// Determines whether an expression is a char.IsWhiteSpace member access, either via the keyword or the Char identifier. /// The expression to test. /// if is char.IsWhiteSpace or Char.IsWhiteSpace; otherwise, . private static bool IsCharIsWhiteSpaceMemberAccess(ExpressionSyntax expression) diff --git a/src/NetEvolve.Arguments.Analyser/ThrowIfContainsWhiteSpaceCodeFixProvider.cs b/src/NetEvolve.Arguments.Analyser/ThrowIfContainsWhiteSpaceCodeFixProvider.cs index 2b738d9..ae3fbae 100644 --- a/src/NetEvolve.Arguments.Analyser/ThrowIfContainsWhiteSpaceCodeFixProvider.cs +++ b/src/NetEvolve.Arguments.Analyser/ThrowIfContainsWhiteSpaceCodeFixProvider.cs @@ -54,9 +54,9 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context) ); } - /// Rewrites the matched if statement into a single ArgumentException.ThrowIfContainsWhiteSpace call. + /// Rewrites the matched statement into a single ArgumentException.ThrowIfContainsWhiteSpace call. /// The document containing the diagnostic. - /// The if statement to replace. + /// The statement to replace. /// The token used to cancel the fix. /// The updated document, or the original document if the pattern can no longer be matched. private static async Task ApplyFixAsync( @@ -65,6 +65,8 @@ private static async Task ApplyFixAsync( CancellationToken cancellationToken ) { + cancellationToken.ThrowIfCancellationRequested(); + var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); if ( diff --git a/src/NetEvolve.Arguments.Analyser/ThrowIfCountAnalyzer.cs b/src/NetEvolve.Arguments.Analyser/ThrowIfCountAnalyzer.cs index dbda8b1..a3b752b 100644 --- a/src/NetEvolve.Arguments.Analyser/ThrowIfCountAnalyzer.cs +++ b/src/NetEvolve.Arguments.Analyser/ThrowIfCountAnalyzer.cs @@ -39,8 +39,8 @@ public override void Initialize(AnalysisContext context) context.RegisterSyntaxNodeAction(Analyze, SyntaxKind.IfStatement); } - /// Analyzes an if statement and reports NEA0007 when it is a collection-count-comparison-then-throw of . - /// The syntax-node analysis context for the if statement being visited. + /// Analyzes an statement and reports NEA0007 when it is a collection-count-comparison-then-throw of . + /// The syntax-node analysis context for the statement being visited. private static void Analyze(SyntaxNodeAnalysisContext context) { var ifStatement = (IfStatementSyntax)context.Node; @@ -90,7 +90,7 @@ out var objectCreation } /// Recognizes arg.Count > max, arg.Count < min, and the combined range arg.Count < min || arg.Count > max (both the .Count property and the .Count() LINQ extension method). - /// The if statement's condition expression. + /// The statement's condition expression. /// When this method returns , the recognized comparison; otherwise, . /// if is a recognized collection-count comparison shape; otherwise, . internal static bool TryGetCountComparison(ExpressionSyntax condition, out ComparisonResult? comparison) @@ -184,6 +184,8 @@ private static bool IsSupportedCountAccess( CancellationToken cancellationToken ) { + cancellationToken.ThrowIfCancellationRequested(); + if (!IsSupportedReceiverType(target, semanticModel, cancellationToken)) { return false; @@ -222,6 +224,8 @@ private static bool IsSupportedReceiverType( CancellationToken cancellationToken ) { + cancellationToken.ThrowIfCancellationRequested(); + var type = semanticModel.GetTypeInfo(target, cancellationToken).Type; if (type is null or IErrorTypeSymbol) diff --git a/src/NetEvolve.Arguments.Analyser/ThrowIfCountCodeFixProvider.cs b/src/NetEvolve.Arguments.Analyser/ThrowIfCountCodeFixProvider.cs index 24dafcc..1df1ffa 100644 --- a/src/NetEvolve.Arguments.Analyser/ThrowIfCountCodeFixProvider.cs +++ b/src/NetEvolve.Arguments.Analyser/ThrowIfCountCodeFixProvider.cs @@ -58,9 +58,9 @@ ifStatement is null ); } - /// Rewrites the matched if statement into a single call to the given collection-count throw-helper. + /// Rewrites the matched statement into a single call to the given collection-count throw-helper. /// The document containing the diagnostic. - /// The if statement to replace. + /// The statement to replace. /// The token used to cancel the fix. /// The updated document, or the original document if the pattern can no longer be matched. private static async Task ApplyFixAsync( @@ -69,6 +69,8 @@ private static async Task ApplyFixAsync( CancellationToken cancellationToken ) { + cancellationToken.ThrowIfCancellationRequested(); + var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); if ( diff --git a/src/NetEvolve.Arguments.Analyser/ThrowIfDefaultAnalyzer.cs b/src/NetEvolve.Arguments.Analyser/ThrowIfDefaultAnalyzer.cs index 508f1fe..7711b6c 100644 --- a/src/NetEvolve.Arguments.Analyser/ThrowIfDefaultAnalyzer.cs +++ b/src/NetEvolve.Arguments.Analyser/ThrowIfDefaultAnalyzer.cs @@ -2,7 +2,6 @@ namespace NetEvolve.Arguments.Analyser; using System; using System.Collections.Immutable; -using System.Linq; using System.Threading; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; @@ -33,8 +32,8 @@ public override void Initialize(AnalysisContext context) context.RegisterSyntaxNodeAction(Analyze, SyntaxKind.IfStatement); } - /// Analyzes an if statement and reports NEA0004 when it is a default-value-check-then-throw of . - /// The syntax-node analysis context for the if statement being visited. + /// Analyzes an statement and reports NEA0004 when it is a default-value-check-then-throw of . + /// The syntax-node analysis context for the statement being visited. private static void Analyze(SyntaxNodeAnalysisContext context) { var ifStatement = (IfStatementSyntax)context.Node; @@ -86,6 +85,8 @@ private static bool SatisfiesThrowIfDefaultConstraint( CancellationToken cancellationToken ) { + cancellationToken.ThrowIfCancellationRequested(); + var type = semanticModel.GetTypeInfo(argument, cancellationToken).Type; if (type is null || !type.IsValueType) @@ -111,7 +112,7 @@ CancellationToken cancellationToken } /// Recognizes arg.Equals(default)/arg.Equals(default(T)) and arg == default/default == arg (and the default(T) variants). - /// The if statement's condition expression. + /// The statement's condition expression. /// When this method returns , the expression being checked; otherwise, . /// if is a recognized default-value-check shape; otherwise, . internal static bool TryGetDefaultCheckedExpression(ExpressionSyntax condition, out ExpressionSyntax? argument) diff --git a/src/NetEvolve.Arguments.Analyser/ThrowIfDefaultCodeFixProvider.cs b/src/NetEvolve.Arguments.Analyser/ThrowIfDefaultCodeFixProvider.cs index 05e8724..1f7bdef 100644 --- a/src/NetEvolve.Arguments.Analyser/ThrowIfDefaultCodeFixProvider.cs +++ b/src/NetEvolve.Arguments.Analyser/ThrowIfDefaultCodeFixProvider.cs @@ -54,9 +54,9 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context) ); } - /// Rewrites the matched if statement into a single call to ArgumentException.ThrowIfDefault. + /// Rewrites the matched statement into a single call to ArgumentException.ThrowIfDefault. /// The document containing the diagnostic. - /// The if statement to replace. + /// The statement to replace. /// The token used to cancel the fix. /// The updated document, or the original document if the pattern can no longer be matched. private static async Task ApplyFixAsync( @@ -65,6 +65,8 @@ private static async Task ApplyFixAsync( CancellationToken cancellationToken ) { + cancellationToken.ThrowIfCancellationRequested(); + var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); if ( diff --git a/src/NetEvolve.Arguments.Analyser/ThrowIfDisposedAnalyzer.cs b/src/NetEvolve.Arguments.Analyser/ThrowIfDisposedAnalyzer.cs index 0ffd4fe..659b33b 100644 --- a/src/NetEvolve.Arguments.Analyser/ThrowIfDisposedAnalyzer.cs +++ b/src/NetEvolve.Arguments.Analyser/ThrowIfDisposedAnalyzer.cs @@ -46,10 +46,10 @@ private static void OnCompilationStart(CompilationStartAnalysisContext context) } /// - /// Analyzes an if statement and reports NEA0005 when it is a disposed-check-then-throw of - /// inside an instance member (the fix requires this). + /// Analyzes an statement and reports NEA0005 when it is a disposed-check-then-throw of + /// inside an instance member (the fix requires ). /// - /// The syntax-node analysis context for the if statement being visited. + /// The syntax-node analysis context for the statement being visited. private static void Analyze(SyntaxNodeAnalysisContext context) { var ifStatement = (IfStatementSyntax)context.Node; diff --git a/src/NetEvolve.Arguments.Analyser/ThrowIfDisposedCodeFixProvider.cs b/src/NetEvolve.Arguments.Analyser/ThrowIfDisposedCodeFixProvider.cs index 542b912..42046bb 100644 --- a/src/NetEvolve.Arguments.Analyser/ThrowIfDisposedCodeFixProvider.cs +++ b/src/NetEvolve.Arguments.Analyser/ThrowIfDisposedCodeFixProvider.cs @@ -54,9 +54,9 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context) ); } - /// Rewrites the matched if statement into a single ObjectDisposedException.ThrowIf(condition, this); call. + /// Rewrites the matched statement into a single ObjectDisposedException.ThrowIf(condition, this); call. /// The document containing the diagnostic. - /// The if statement to replace. + /// The statement to replace. /// The token used to cancel the fix. /// The updated document, or the original document if the syntax tree can no longer be retrieved. private static async Task ApplyFixAsync( @@ -65,6 +65,8 @@ private static async Task ApplyFixAsync( CancellationToken cancellationToken ) { + cancellationToken.ThrowIfCancellationRequested(); + var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); if (root is null) diff --git a/src/NetEvolve.Arguments.Analyser/ThrowIfEmptyGuidAnalyzer.cs b/src/NetEvolve.Arguments.Analyser/ThrowIfEmptyGuidAnalyzer.cs index 24686bb..1d8dbe2 100644 --- a/src/NetEvolve.Arguments.Analyser/ThrowIfEmptyGuidAnalyzer.cs +++ b/src/NetEvolve.Arguments.Analyser/ThrowIfEmptyGuidAnalyzer.cs @@ -35,8 +35,8 @@ public override void Initialize(AnalysisContext context) context.RegisterSyntaxNodeAction(Analyze, SyntaxKind.IfStatement); } - /// Analyzes an if statement and reports NEA0009 when it is a Guid.Empty-check-then-throw of . - /// The syntax-node analysis context for the if statement being visited. + /// Analyzes an statement and reports NEA0009 when it is a Guid.Empty-check-then-throw of . + /// The syntax-node analysis context for the statement being visited. private static void Analyze(SyntaxNodeAnalysisContext context) { var ifStatement = (IfStatementSyntax)context.Node; @@ -85,7 +85,7 @@ out var objectCreation } /// Recognizes arg.Equals(Guid.Empty) and arg == Guid.Empty/Guid.Empty == arg. - /// The if statement's condition expression. + /// The statement's condition expression. /// The semantic model used to resolve Guid.Empty. /// The token used to cancel semantic-model lookups. /// When this method returns , the expression being checked; otherwise, . @@ -97,6 +97,8 @@ internal static bool TryGetEmptyGuidCheckedExpression( out ExpressionSyntax? argument ) { + cancellationToken.ThrowIfCancellationRequested(); + condition = SyntaxHelpers.Unwrap(condition); argument = null; @@ -141,6 +143,8 @@ private static bool IsGuidEmpty( CancellationToken cancellationToken ) { + cancellationToken.ThrowIfCancellationRequested(); + if ( SyntaxHelpers.Unwrap(expression) is not MemberAccessExpressionSyntax { Name.Identifier.Text: "Empty" } memberAccess diff --git a/src/NetEvolve.Arguments.Analyser/ThrowIfEmptyGuidCodeFixProvider.cs b/src/NetEvolve.Arguments.Analyser/ThrowIfEmptyGuidCodeFixProvider.cs index d90b1fb..670767e 100644 --- a/src/NetEvolve.Arguments.Analyser/ThrowIfEmptyGuidCodeFixProvider.cs +++ b/src/NetEvolve.Arguments.Analyser/ThrowIfEmptyGuidCodeFixProvider.cs @@ -54,9 +54,9 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context) ); } - /// Rewrites the matched if statement into a single ArgumentException.ThrowIfEmptyGuid call. + /// Rewrites the matched statement into a single ArgumentException.ThrowIfEmptyGuid call. /// The document containing the diagnostic. - /// The if statement to replace. + /// The statement to replace. /// The token used to cancel the fix. /// The updated document, or the original document if the pattern can no longer be matched. private static async Task ApplyFixAsync( @@ -65,6 +65,8 @@ private static async Task ApplyFixAsync( CancellationToken cancellationToken ) { + cancellationToken.ThrowIfCancellationRequested(); + var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); diff --git a/src/NetEvolve.Arguments.Analyser/ThrowIfLengthAnalyzer.cs b/src/NetEvolve.Arguments.Analyser/ThrowIfLengthAnalyzer.cs index ba805f7..87376aa 100644 --- a/src/NetEvolve.Arguments.Analyser/ThrowIfLengthAnalyzer.cs +++ b/src/NetEvolve.Arguments.Analyser/ThrowIfLengthAnalyzer.cs @@ -31,8 +31,8 @@ public override void Initialize(AnalysisContext context) context.RegisterSyntaxNodeAction(Analyze, SyntaxKind.IfStatement); } - /// Analyzes an if statement and reports NEA0006 when it is a string-length-comparison-then-throw of . - /// The syntax-node analysis context for the if statement being visited. + /// Analyzes an statement and reports NEA0006 when it is a string-length-comparison-then-throw of . + /// The syntax-node analysis context for the statement being visited. private static void Analyze(SyntaxNodeAnalysisContext context) { var ifStatement = (IfStatementSyntax)context.Node; @@ -86,7 +86,7 @@ out var objectCreation } /// Recognizes arg.Length > max, arg.Length < min, and the combined range arg.Length < min || arg.Length > max. - /// The if statement's condition expression. + /// The statement's condition expression. /// When this method returns , the recognized comparison; otherwise, . /// if is a recognized string-length comparison shape; otherwise, . internal static bool TryGetLengthComparison(ExpressionSyntax condition, out ComparisonResult? comparison) diff --git a/src/NetEvolve.Arguments.Analyser/ThrowIfLengthCodeFixProvider.cs b/src/NetEvolve.Arguments.Analyser/ThrowIfLengthCodeFixProvider.cs index 5aa0f5e..bdb0a4e 100644 --- a/src/NetEvolve.Arguments.Analyser/ThrowIfLengthCodeFixProvider.cs +++ b/src/NetEvolve.Arguments.Analyser/ThrowIfLengthCodeFixProvider.cs @@ -58,9 +58,9 @@ ifStatement is null ); } - /// Rewrites the matched if statement into a single call to the given string-length throw-helper. + /// Rewrites the matched statement into a single call to the given string-length throw-helper. /// The document containing the diagnostic. - /// The if statement to replace. + /// The statement to replace. /// The token used to cancel the fix. /// The updated document, or the original document if the pattern can no longer be matched. private static async Task ApplyFixAsync( @@ -69,6 +69,8 @@ private static async Task ApplyFixAsync( CancellationToken cancellationToken ) { + cancellationToken.ThrowIfCancellationRequested(); + var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); if ( diff --git a/src/NetEvolve.Arguments.Analyser/ThrowIfNullAnalyzer.cs b/src/NetEvolve.Arguments.Analyser/ThrowIfNullAnalyzer.cs index 1b30d68..59b4843 100644 --- a/src/NetEvolve.Arguments.Analyser/ThrowIfNullAnalyzer.cs +++ b/src/NetEvolve.Arguments.Analyser/ThrowIfNullAnalyzer.cs @@ -123,8 +123,8 @@ private static bool IsConditionallyEvaluatedRelativeToContainingStatement(Binary return false; } - /// Analyzes an if statement and reports NEA0001 when it is a null-check-then-throw of . - /// The syntax-node analysis context for the if statement being visited. + /// Analyzes an statement and reports NEA0001 when it is a null-check-then-throw of . + /// The syntax-node analysis context for the statement being visited. private static void Analyze(SyntaxNodeAnalysisContext context) { var ifStatement = (IfStatementSyntax)context.Node; diff --git a/src/NetEvolve.Arguments.Analyser/ThrowIfNullCodeFixProvider.cs b/src/NetEvolve.Arguments.Analyser/ThrowIfNullCodeFixProvider.cs index 5797aad..48ff8e7 100644 --- a/src/NetEvolve.Arguments.Analyser/ThrowIfNullCodeFixProvider.cs +++ b/src/NetEvolve.Arguments.Analyser/ThrowIfNullCodeFixProvider.cs @@ -68,7 +68,7 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context) /// Rewrites an if (arg is null) throw ...; statement into a single ArgumentNullException.ThrowIfNull(arg); call. /// The document containing the diagnostic. - /// The if statement to replace. + /// The statement to replace. /// The token used to cancel the fix. /// The updated document, or the original document if the pattern can no longer be matched. private static async Task ApplyIfStatementFixAsync( @@ -77,6 +77,8 @@ private static async Task ApplyIfStatementFixAsync( CancellationToken cancellationToken ) { + cancellationToken.ThrowIfCancellationRequested(); + var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); if ( @@ -119,6 +121,8 @@ private static async Task ApplyCoalesceFixAsync( CancellationToken cancellationToken ) { + cancellationToken.ThrowIfCancellationRequested(); + var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); var containingStatement = coalesce.FirstAncestorOrSelf(); diff --git a/src/NetEvolve.Arguments.Analyser/ThrowIfNullOrEmptyAnalyzer.cs b/src/NetEvolve.Arguments.Analyser/ThrowIfNullOrEmptyAnalyzer.cs index 06eec68..3ee55ce 100644 --- a/src/NetEvolve.Arguments.Analyser/ThrowIfNullOrEmptyAnalyzer.cs +++ b/src/NetEvolve.Arguments.Analyser/ThrowIfNullOrEmptyAnalyzer.cs @@ -1,4 +1,4 @@ -namespace NetEvolve.Arguments.Analyser; +namespace NetEvolve.Arguments.Analyser; using System; using System.Collections.Immutable; @@ -74,8 +74,8 @@ private static void OnCompilationStart(CompilationStartAnalysisContext context) ); } - /// Analyzes an if statement and reports NEA0002 when it is a string.IsNullOrEmpty/IsNullOrWhiteSpace-then-throw of . - /// The syntax-node analysis context for the if statement being visited. + /// Analyzes an statement and reports NEA0002 when it is a string.IsNullOrEmpty/IsNullOrWhiteSpace-then-throw of . + /// The syntax-node analysis context for the statement being visited. /// Whether the compilation's BCL already exposes ArgumentException.ThrowIfNullOrEmpty. /// Whether the compilation's BCL already exposes ArgumentException.ThrowIfNullOrWhiteSpace. private static void Analyze( @@ -142,7 +142,7 @@ out objectCreation } /// Recognizes string.IsNullOrEmpty(arg)/IsNullOrWhiteSpace(arg) and reports the matching throw-helper member name and the checked argument. - /// The if statement's condition expression. + /// The statement's condition expression. /// When this method returns , the string argument being checked; otherwise, . /// When this method returns , the matching throw-helper member name; otherwise, . /// if is a recognized shape; otherwise, . @@ -191,7 +191,7 @@ is not InvocationExpressionSyntax return true; } - /// Determines whether an expression refers to the type, either via the string keyword or the String identifier. + /// Determines whether an expression refers to the type, either via the keyword or the String identifier. /// The invocation target's qualifier expression to test. /// if refers to ; otherwise, . private static bool IsStringTypeReference(ExpressionSyntax expression) => diff --git a/src/NetEvolve.Arguments.Analyser/ThrowIfNullOrEmptyCodeFixProvider.cs b/src/NetEvolve.Arguments.Analyser/ThrowIfNullOrEmptyCodeFixProvider.cs index 6115516..4518e94 100644 --- a/src/NetEvolve.Arguments.Analyser/ThrowIfNullOrEmptyCodeFixProvider.cs +++ b/src/NetEvolve.Arguments.Analyser/ThrowIfNullOrEmptyCodeFixProvider.cs @@ -57,9 +57,9 @@ ifStatement is null ); } - /// Rewrites the matched if statement into a single call to the given throw-helper. + /// Rewrites the matched statement into a single call to the given throw-helper. /// The document containing the diagnostic. - /// The if statement to replace. + /// The statement to replace. /// The throw-helper member name to invoke, e.g. ThrowIfNullOrEmpty. /// The token used to cancel the fix. /// The updated document, or the original document if the pattern can no longer be matched. @@ -70,6 +70,8 @@ private static async Task ApplyFixAsync( CancellationToken cancellationToken ) { + cancellationToken.ThrowIfCancellationRequested(); + var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); if ( diff --git a/src/NetEvolve.Arguments.Analyser/ThrowIfOutOfRangeAnalyzer.cs b/src/NetEvolve.Arguments.Analyser/ThrowIfOutOfRangeAnalyzer.cs index b64069d..c34c702 100644 --- a/src/NetEvolve.Arguments.Analyser/ThrowIfOutOfRangeAnalyzer.cs +++ b/src/NetEvolve.Arguments.Analyser/ThrowIfOutOfRangeAnalyzer.cs @@ -76,8 +76,8 @@ private static void OnCompilationStart(CompilationStartAnalysisContext context) context.RegisterSyntaxNodeAction(Analyze, SyntaxKind.IfStatement); } - /// Analyzes an if statement and reports NEA0003 when it is a comparison-then-throw of . - /// The syntax-node analysis context for the if statement being visited. + /// Analyzes an statement and reports NEA0003 when it is a comparison-then-throw of . + /// The syntax-node analysis context for the statement being visited. private static void Analyze(SyntaxNodeAnalysisContext context) { var ifStatement = (IfStatementSyntax)context.Node; @@ -164,6 +164,8 @@ private static bool IsSupportedOperandType( CancellationToken cancellationToken ) { + cancellationToken.ThrowIfCancellationRequested(); + var operandType = semanticModel.GetTypeInfo(comparison.ValueExpression, cancellationToken).Type; if (operandType is null || operandType.TypeKind == TypeKind.Error) @@ -206,6 +208,8 @@ private static bool IsIeeeFloatingPointOperand( CancellationToken cancellationToken ) { + cancellationToken.ThrowIfCancellationRequested(); + var type = semanticModel.GetTypeInfo(operand, cancellationToken).Type; if (type is null) @@ -228,7 +232,7 @@ CancellationToken cancellationToken /// Recognizes a comparison against zero, another expression, or a combined range (value < min || value > max) /// and maps it to the matching throw-helper member and arguments. /// - /// The if statement's condition expression. + /// The statement's condition expression. /// When this method returns , the recognized comparison; otherwise, . /// if is a recognized comparison shape; otherwise, . internal static bool TryGetComparison(ExpressionSyntax condition, out ComparisonResult? comparison) @@ -319,7 +323,7 @@ out ComparisonResult? comparison /// /// /// This is a conservative, purely syntactic allow-list: a bare identifier (a parameter or local), or a chain of - /// member accesses rooted in one. Invocations, indexers, object creation, await, and assignment or + /// member accesses rooted in one. Invocations, indexers, object creation, , and assignment or /// increment/decrement expressions are all rejected. Note that a member access is not strictly guaranteed to be /// side-effect-free either, since a property getter can run arbitrary code; however, rejecting all member access /// would gut the rule's main use case (e.g. arg.Length), so accepting member-access chains while diff --git a/src/NetEvolve.Arguments.Analyser/ThrowIfOutOfRangeCodeFixProvider.cs b/src/NetEvolve.Arguments.Analyser/ThrowIfOutOfRangeCodeFixProvider.cs index 27be24d..140c732 100644 --- a/src/NetEvolve.Arguments.Analyser/ThrowIfOutOfRangeCodeFixProvider.cs +++ b/src/NetEvolve.Arguments.Analyser/ThrowIfOutOfRangeCodeFixProvider.cs @@ -58,9 +58,9 @@ ifStatement is null ); } - /// Rewrites the matched if statement into a single call to the given throw-helper. + /// Rewrites the matched statement into a single call to the given throw-helper. /// The document containing the diagnostic. - /// The if statement to replace. + /// The statement to replace. /// The token used to cancel the fix. /// The updated document, or the original document if the pattern can no longer be matched. private static async Task ApplyFixAsync( @@ -69,6 +69,8 @@ private static async Task ApplyFixAsync( CancellationToken cancellationToken ) { + cancellationToken.ThrowIfCancellationRequested(); + var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); if ( diff --git a/src/NetEvolve.Arguments.Analyser/TriviaHelpers.cs b/src/NetEvolve.Arguments.Analyser/TriviaHelpers.cs index 841174d..6ad3f1f 100644 --- a/src/NetEvolve.Arguments.Analyser/TriviaHelpers.cs +++ b/src/NetEvolve.Arguments.Analyser/TriviaHelpers.cs @@ -6,20 +6,20 @@ namespace NetEvolve.Arguments.Analyser; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; -/// Shared trivia-preservation helpers used by the code fix providers that replace an if statement. +/// Shared trivia-preservation helpers used by the code fix providers that replace an statement. internal static class TriviaHelpers { /// /// Copies the leading and trailing trivia of onto , /// exactly like the WithTriviaFrom extension method, and additionally re-inserts any comment trivia attached - /// to tokens INSIDE the if statement's subtree (for example, a comment on its own line right before the - /// throw statement inside the block) that WithTriviaFrom alone would silently discard, since it - /// only carries the leading trivia of the if keyword and the trailing trivia after the closing brace. + /// to tokens INSIDE the statement's subtree (for example, a comment on its own line right before the + /// statement inside the block) that WithTriviaFrom alone would silently discard, since it + /// only carries the leading trivia of the keyword and the trailing trivia after the closing brace. /// /// The type of the replacement syntax node. /// The node that is replacing . - /// The if statement being replaced. - /// with the if statement's trivia and any interior comments preserved. + /// The statement being replaced. + /// with the statement's trivia and any interior comments preserved. public static TNode WithTriviaFromPreservingComments(this TNode replacement, IfStatementSyntax ifStatement) where TNode : SyntaxNode { @@ -34,9 +34,9 @@ public static TNode WithTriviaFromPreservingComments(this TNode replaceme var interiorComments = ifStatement .DescendantTrivia() .Where(trivia => - trivia.IsKind(SyntaxKind.SingleLineCommentTrivia) || trivia.IsKind(SyntaxKind.MultiLineCommentTrivia) + (trivia.IsKind(SyntaxKind.SingleLineCommentTrivia) || trivia.IsKind(SyntaxKind.MultiLineCommentTrivia)) + && !alreadyCarried.Contains(trivia) ) - .Where(trivia => !alreadyCarried.Contains(trivia)) .ToList(); if (interiorComments.Count == 0) diff --git a/src/NetEvolve.Arguments.Analyser/UsingDirectiveInserter.cs b/src/NetEvolve.Arguments.Analyser/UsingDirectiveInserter.cs index 5e09b48..0190146 100644 --- a/src/NetEvolve.Arguments.Analyser/UsingDirectiveInserter.cs +++ b/src/NetEvolve.Arguments.Analyser/UsingDirectiveInserter.cs @@ -12,7 +12,7 @@ namespace NetEvolve.Arguments.Analyser; /// call binds to the polyfilled extension members in NetEvolve.Arguments, the extension block /// lives in namespace System, so the containing namespace must be imported for the call to /// resolve, even though the diagnostic itself can fire on a fully-qualified throw expression that -/// required no such using directive. +/// required no such directive. /// internal static class UsingDirectiveInserter { diff --git a/src/NetEvolve.Arguments/ArgumentExceptionPolyfill.cs b/src/NetEvolve.Arguments/ArgumentExceptionPolyfills.cs similarity index 99% rename from src/NetEvolve.Arguments/ArgumentExceptionPolyfill.cs rename to src/NetEvolve.Arguments/ArgumentExceptionPolyfills.cs index 3ccb12d..cc59fb7 100644 --- a/src/NetEvolve.Arguments/ArgumentExceptionPolyfill.cs +++ b/src/NetEvolve.Arguments/ArgumentExceptionPolyfills.cs @@ -1,7 +1,7 @@ -#pragma warning disable IDE0130 // Namespace does not match folder structure +#pragma warning disable IDE0130, NE0002 // Namespace does not match folder structure namespace System; -#pragma warning restore IDE0130 // Namespace does not match folder structure +#pragma warning restore IDE0130, NE0002 // Namespace does not match folder structure using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; diff --git a/src/NetEvolve.Arguments/ArgumentNullExceptionPolyfills.cs b/src/NetEvolve.Arguments/ArgumentNullExceptionPolyfills.cs index da82d55..9979a5d 100644 --- a/src/NetEvolve.Arguments/ArgumentNullExceptionPolyfills.cs +++ b/src/NetEvolve.Arguments/ArgumentNullExceptionPolyfills.cs @@ -1,9 +1,9 @@ #if !NET9_0_OR_GREATER -#pragma warning disable IDE0130 // Namespace does not match folder structure +#pragma warning disable IDE0130, NE0002 // Namespace does not match folder structure namespace System; -#pragma warning restore IDE0130 // Namespace does not match folder structure +#pragma warning restore IDE0130, NE0002 // Namespace does not match folder structure using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; diff --git a/src/NetEvolve.Arguments/ArgumentOutOfRangeExceptionPolyfills.cs b/src/NetEvolve.Arguments/ArgumentOutOfRangeExceptionPolyfills.cs index a07cf5c..e93d735 100644 --- a/src/NetEvolve.Arguments/ArgumentOutOfRangeExceptionPolyfills.cs +++ b/src/NetEvolve.Arguments/ArgumentOutOfRangeExceptionPolyfills.cs @@ -1,7 +1,7 @@ -#pragma warning disable IDE0130 // Namespace does not match folder structure +#pragma warning disable IDE0130, NE0002 // Namespace does not match folder structure namespace System; -#pragma warning restore IDE0130 // Namespace does not match folder structure +#pragma warning restore IDE0130, NE0002 // Namespace does not match folder structure using System.Diagnostics.CodeAnalysis; diff --git a/src/NetEvolve.Arguments/Argument_ThrowIfEqual.cs b/src/NetEvolve.Arguments/Argument_ThrowIfEqual.cs index 18324ed..6558d2f 100644 --- a/src/NetEvolve.Arguments/Argument_ThrowIfEqual.cs +++ b/src/NetEvolve.Arguments/Argument_ThrowIfEqual.cs @@ -2,8 +2,14 @@ using System; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; +[SuppressMessage( + "Maintainability", + "NE0001:Declare one type per file with a matching file name", + Justification = "Obsolete" +)] public static partial class Argument { /// Throws an if is equal to . diff --git a/src/NetEvolve.Arguments/Argument_ThrowIfGreaterThan.cs b/src/NetEvolve.Arguments/Argument_ThrowIfGreaterThan.cs index 9e4fb0e..59dabdb 100644 --- a/src/NetEvolve.Arguments/Argument_ThrowIfGreaterThan.cs +++ b/src/NetEvolve.Arguments/Argument_ThrowIfGreaterThan.cs @@ -2,8 +2,14 @@ using System; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; +[SuppressMessage( + "Maintainability", + "NE0001:Declare one type per file with a matching file name", + Justification = "Obsolete" +)] public static partial class Argument { /// Throws an if is greater than . diff --git a/src/NetEvolve.Arguments/Argument_ThrowIfGreaterThanOrEqual.cs b/src/NetEvolve.Arguments/Argument_ThrowIfGreaterThanOrEqual.cs index 4357800..34f6808 100644 --- a/src/NetEvolve.Arguments/Argument_ThrowIfGreaterThanOrEqual.cs +++ b/src/NetEvolve.Arguments/Argument_ThrowIfGreaterThanOrEqual.cs @@ -2,8 +2,14 @@ using System; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; +[SuppressMessage( + "Maintainability", + "NE0001:Declare one type per file with a matching file name", + Justification = "Obsolete" +)] public static partial class Argument { /// Throws an if is greater than or equal . diff --git a/src/NetEvolve.Arguments/Argument_ThrowIfLessThan.cs b/src/NetEvolve.Arguments/Argument_ThrowIfLessThan.cs index cd0bf57..a933517 100644 --- a/src/NetEvolve.Arguments/Argument_ThrowIfLessThan.cs +++ b/src/NetEvolve.Arguments/Argument_ThrowIfLessThan.cs @@ -2,8 +2,14 @@ using System; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; +[SuppressMessage( + "Maintainability", + "NE0001:Declare one type per file with a matching file name", + Justification = "Obsolete" +)] public static partial class Argument { /// Throws an if is less than . diff --git a/src/NetEvolve.Arguments/Argument_ThrowIfLessThanOrEqual.cs b/src/NetEvolve.Arguments/Argument_ThrowIfLessThanOrEqual.cs index adc0c08..1142ec5 100644 --- a/src/NetEvolve.Arguments/Argument_ThrowIfLessThanOrEqual.cs +++ b/src/NetEvolve.Arguments/Argument_ThrowIfLessThanOrEqual.cs @@ -2,8 +2,14 @@ using System; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; +[SuppressMessage( + "Maintainability", + "NE0001:Declare one type per file with a matching file name", + Justification = "Obsolete" +)] public static partial class Argument { /// Throws an if is less than or equal . diff --git a/src/NetEvolve.Arguments/Argument_ThrowIfNotEqual.cs b/src/NetEvolve.Arguments/Argument_ThrowIfNotEqual.cs index d9e995a..9ce0ea0 100644 --- a/src/NetEvolve.Arguments/Argument_ThrowIfNotEqual.cs +++ b/src/NetEvolve.Arguments/Argument_ThrowIfNotEqual.cs @@ -1,10 +1,15 @@ namespace NetEvolve.Arguments; using System; -using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; +[SuppressMessage( + "Maintainability", + "NE0001:Declare one type per file with a matching file name", + Justification = "Obsolete" +)] public static partial class Argument { /// Throws an if is not equal to . diff --git a/src/NetEvolve.Arguments/Argument_ThrowIfNull.cs b/src/NetEvolve.Arguments/Argument_ThrowIfNull.cs index f1a5e63..0ca0140 100644 --- a/src/NetEvolve.Arguments/Argument_ThrowIfNull.cs +++ b/src/NetEvolve.Arguments/Argument_ThrowIfNull.cs @@ -5,6 +5,11 @@ using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; +[SuppressMessage( + "Maintainability", + "NE0001:Declare one type per file with a matching file name", + Justification = "Obsolete" +)] public static partial class Argument { /// Throws an if is null. diff --git a/src/NetEvolve.Arguments/Argument_ThrowIfNullOrEmpty.cs b/src/NetEvolve.Arguments/Argument_ThrowIfNullOrEmpty.cs index d1a58d5..94c91e2 100644 --- a/src/NetEvolve.Arguments/Argument_ThrowIfNullOrEmpty.cs +++ b/src/NetEvolve.Arguments/Argument_ThrowIfNullOrEmpty.cs @@ -4,9 +4,13 @@ using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; -using System.Linq; using System.Runtime.CompilerServices; +[SuppressMessage( + "Maintainability", + "NE0001:Declare one type per file with a matching file name", + Justification = "Obsolete" +)] public static partial class Argument { /// Throws an exception if is null or empty. diff --git a/src/NetEvolve.Arguments/Argument_ThrowIfNullOrWhiteSpace.cs b/src/NetEvolve.Arguments/Argument_ThrowIfNullOrWhiteSpace.cs index 783ea1a..6325f3d 100644 --- a/src/NetEvolve.Arguments/Argument_ThrowIfNullOrWhiteSpace.cs +++ b/src/NetEvolve.Arguments/Argument_ThrowIfNullOrWhiteSpace.cs @@ -5,6 +5,11 @@ using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; +[SuppressMessage( + "Maintainability", + "NE0001:Declare one type per file with a matching file name", + Justification = "Obsolete" +)] public static partial class Argument { /// Throws an exception if is null, empty, or consists only of white-space characters. diff --git a/src/NetEvolve.Arguments/NetEvolve.Arguments.csproj b/src/NetEvolve.Arguments/NetEvolve.Arguments.csproj index a29ae2a..a1324d5 100644 --- a/src/NetEvolve.Arguments/NetEvolve.Arguments.csproj +++ b/src/NetEvolve.Arguments/NetEvolve.Arguments.csproj @@ -1,4 +1,4 @@ - + $(_ProjectTargetFrameworks) A universal polyfill library that provides modern ArgumentNullException.ThrowIf* and ArgumentException.ThrowIf* helper methods across all .NET runtimes (.NET Standard 2.0+, .NET Framework 4.6.2+, .NET 6.0+), enabling consistent argument validation patterns regardless of target framework version. diff --git a/src/NetEvolve.Arguments/ObjectDisposedExceptionPolyfills.cs b/src/NetEvolve.Arguments/ObjectDisposedExceptionPolyfills.cs index bb012ab..d53cde4 100644 --- a/src/NetEvolve.Arguments/ObjectDisposedExceptionPolyfills.cs +++ b/src/NetEvolve.Arguments/ObjectDisposedExceptionPolyfills.cs @@ -1,9 +1,9 @@ -#if !NET7_0_OR_GREATER +#if !NET7_0_OR_GREATER -#pragma warning disable IDE0130 // Namespace does not match folder structure +#pragma warning disable IDE0130, NE0002 // Namespace does not match folder structure namespace System; -#pragma warning restore IDE0130 // Namespace does not match folder structure +#pragma warning restore IDE0130, NE0002 // Namespace does not match folder structure using System.Diagnostics.CodeAnalysis; diff --git a/src/NetEvolve.Arguments/Polyfills/CallerArgumentExpressionAttribute.cs b/src/NetEvolve.Arguments/Polyfills/CallerArgumentExpressionAttribute.cs index 57c1e6e..8923c8c 100644 --- a/src/NetEvolve.Arguments/Polyfills/CallerArgumentExpressionAttribute.cs +++ b/src/NetEvolve.Arguments/Polyfills/CallerArgumentExpressionAttribute.cs @@ -1,9 +1,9 @@ #if !NETCOREAPP3_0_OR_GREATER -#pragma warning disable IDE0130 // Namespace does not match folder structure +#pragma warning disable IDE0130, NE0002 // Namespace does not match folder structure namespace System.Runtime.CompilerServices; -#pragma warning restore IDE0130 // Namespace does not match folder structure +#pragma warning restore IDE0130, NE0002 // Namespace does not match folder structure using Diagnostics; using Diagnostics.CodeAnalysis; diff --git a/src/NetEvolve.Arguments/Polyfills/DoesNotReturnAttribute.cs b/src/NetEvolve.Arguments/Polyfills/DoesNotReturnAttribute.cs index 6faf68a..e2ecdcf 100644 --- a/src/NetEvolve.Arguments/Polyfills/DoesNotReturnAttribute.cs +++ b/src/NetEvolve.Arguments/Polyfills/DoesNotReturnAttribute.cs @@ -1,9 +1,9 @@ #if !NETCOREAPP3_0_OR_GREATER && !NETSTANDARD2_1_OR_GREATER -#pragma warning disable IDE0130 // Namespace does not match folder structure +#pragma warning disable IDE0130, NE0002 // Namespace does not match folder structure namespace System.Diagnostics.CodeAnalysis; -#pragma warning restore IDE0130 // Namespace does not match folder structure +#pragma warning restore IDE0130, NE0002 // Namespace does not match folder structure /// /// Specifies that a method that will never return under any circumstance. diff --git a/src/NetEvolve.Arguments/Polyfills/DoesNotReturnIfAttribute.cs b/src/NetEvolve.Arguments/Polyfills/DoesNotReturnIfAttribute.cs index 453cdae..c738b9a 100644 --- a/src/NetEvolve.Arguments/Polyfills/DoesNotReturnIfAttribute.cs +++ b/src/NetEvolve.Arguments/Polyfills/DoesNotReturnIfAttribute.cs @@ -1,9 +1,9 @@ #if !NETCOREAPP3_0_OR_GREATER && !NETSTANDARD2_1_OR_GREATER -#pragma warning disable IDE0130 // Namespace does not match folder structure +#pragma warning disable IDE0130, NE0002 // Namespace does not match folder structure namespace System.Diagnostics.CodeAnalysis; -#pragma warning restore IDE0130 // Namespace does not match folder structure +#pragma warning restore IDE0130, NE0002 // Namespace does not match folder structure /// /// Specifies that the method will not return if the associated diff --git a/src/NetEvolve.Arguments/Polyfills/IEnumerable_TryGetNonEnumeratedCount.cs b/src/NetEvolve.Arguments/Polyfills/IEnumerableExtensions.cs similarity index 92% rename from src/NetEvolve.Arguments/Polyfills/IEnumerable_TryGetNonEnumeratedCount.cs rename to src/NetEvolve.Arguments/Polyfills/IEnumerableExtensions.cs index 847f5e6..6493bd4 100644 --- a/src/NetEvolve.Arguments/Polyfills/IEnumerable_TryGetNonEnumeratedCount.cs +++ b/src/NetEvolve.Arguments/Polyfills/IEnumerableExtensions.cs @@ -1,9 +1,9 @@ #if !NET6_0_OR_GREATER -#pragma warning disable IDE0130 // Namespace does not match folder structure +#pragma warning disable IDE0130, NE0002 // Namespace does not match folder structure namespace System.Linq; -#pragma warning restore IDE0130 // Namespace does not match folder structure +#pragma warning restore IDE0130, NE0002 // Namespace does not match folder structure using System.Collections; using System.Collections.Generic; diff --git a/src/NetEvolve.Arguments/Polyfills/ModuleInitializerAttribute.cs b/src/NetEvolve.Arguments/Polyfills/ModuleInitializerAttribute.cs index e15e4ef..ca31b3c 100644 --- a/src/NetEvolve.Arguments/Polyfills/ModuleInitializerAttribute.cs +++ b/src/NetEvolve.Arguments/Polyfills/ModuleInitializerAttribute.cs @@ -1,9 +1,9 @@ #if !NET5_0_OR_GREATER -#pragma warning disable IDE0130 // Namespace does not match folder structure +#pragma warning disable IDE0130, NE0002 // Namespace does not match folder structure namespace System.Runtime.CompilerServices; -#pragma warning restore IDE0130 // Namespace does not match folder structure +#pragma warning restore IDE0130, NE0002 // Namespace does not match folder structure using System.Diagnostics; using System.Diagnostics.CodeAnalysis; diff --git a/src/NetEvolve.Arguments/Polyfills/NotNullAttribute.cs b/src/NetEvolve.Arguments/Polyfills/NotNullAttribute.cs index 43ea81f..4b05f0e 100644 --- a/src/NetEvolve.Arguments/Polyfills/NotNullAttribute.cs +++ b/src/NetEvolve.Arguments/Polyfills/NotNullAttribute.cs @@ -1,9 +1,9 @@ #if !NETCOREAPP3_0_OR_GREATER && !NETSTANDARD2_1_OR_GREATER -#pragma warning disable IDE0130 // Namespace does not match folder structure +#pragma warning disable IDE0130, NE0002 // Namespace does not match folder structure namespace System.Diagnostics.CodeAnalysis; -#pragma warning restore IDE0130 // Namespace does not match folder structure +#pragma warning restore IDE0130, NE0002 // Namespace does not match folder structure using static AttributeTargets; diff --git a/src/NetEvolve.Arguments/Polyfills/StackTraceHiddenAttribute.cs b/src/NetEvolve.Arguments/Polyfills/StackTraceHiddenAttribute.cs index 9ffdcbc..d6f3741 100644 --- a/src/NetEvolve.Arguments/Polyfills/StackTraceHiddenAttribute.cs +++ b/src/NetEvolve.Arguments/Polyfills/StackTraceHiddenAttribute.cs @@ -1,8 +1,8 @@ #if !NET6_0_OR_GREATER -#pragma warning disable IDE0130 // Namespace does not match folder structure +#pragma warning disable IDE0130, NE0002 // Namespace does not match folder structure namespace System.Diagnostics; -#pragma warning restore IDE0130 // Namespace does not match folder structure +#pragma warning restore IDE0130, NE0002 // Namespace does not match folder structure using System.Diagnostics.CodeAnalysis; using static AttributeTargets; diff --git a/tests/NetEvolve.Arguments.Analyser.Tests.Unit/AnalyzerVerifier.cs b/tests/NetEvolve.Arguments.Analyser.Tests.Unit/AnalyzerVerifier.cs index 36cc020..4a39a43 100644 --- a/tests/NetEvolve.Arguments.Analyser.Tests.Unit/AnalyzerVerifier.cs +++ b/tests/NetEvolve.Arguments.Analyser.Tests.Unit/AnalyzerVerifier.cs @@ -27,16 +27,18 @@ internal static class AnalyzerVerifier public static Task> GetDiagnosticsAsync( DiagnosticAnalyzer analyzer, string source, - bool useLegacyReferences = true - ) => GetDiagnosticsCoreAsync(analyzer, source, useLegacyReferences); + bool useLegacyReferences = true, + CancellationToken cancellationToken = default + ) => GetDiagnosticsCoreAsync(analyzer, source, useLegacyReferences, cancellationToken: cancellationToken); public static Task ApplyFixAsync( DiagnosticAnalyzer analyzer, CodeFixProvider codeFix, string source, bool useLegacyReferences = true, - int expectedDiagnosticCount = 1 - ) => ApplyFixCoreAsync(analyzer, codeFix, source, useLegacyReferences, expectedDiagnosticCount); + int expectedDiagnosticCount = 1, + CancellationToken cancellationToken = default + ) => ApplyFixCoreAsync(analyzer, codeFix, source, useLegacyReferences, expectedDiagnosticCount, cancellationToken); /// /// Applies the code fix's (e.g. WellKnownFixAllProviders.BatchFixer) @@ -46,19 +48,23 @@ public static Task ApplyFixAllAsync( DiagnosticAnalyzer analyzer, CodeFixProvider codeFix, string source, - bool useLegacyReferences = true - ) => ApplyFixAllCoreAsync(analyzer, codeFix, source, useLegacyReferences); + bool useLegacyReferences = true, + CancellationToken cancellationToken = default + ) => ApplyFixAllCoreAsync(analyzer, codeFix, source, useLegacyReferences, cancellationToken: cancellationToken); private static async Task> GetDiagnosticsCoreAsync( DiagnosticAnalyzer analyzer, string source, - bool useLegacyReferences + bool useLegacyReferences, + CancellationToken cancellationToken = default ) { + cancellationToken.ThrowIfCancellationRequested(); + var compilation = CreateCompilation(source, useLegacyReferences); var compilationWithAnalyzers = compilation.WithAnalyzers(ImmutableArray.Create(analyzer)); - return await compilationWithAnalyzers.GetAnalyzerDiagnosticsAsync(CancellationToken.None).ConfigureAwait(false); + return await compilationWithAnalyzers.GetAnalyzerDiagnosticsAsync(cancellationToken).ConfigureAwait(false); } private static async Task ApplyFixCoreAsync( @@ -66,9 +72,12 @@ private static async Task ApplyFixCoreAsync( CodeFixProvider codeFix, string source, bool useLegacyReferences, - int expectedDiagnosticCount + int expectedDiagnosticCount, + CancellationToken cancellationToken = default ) { + cancellationToken.ThrowIfCancellationRequested(); + using var workspace = new AdhocWorkspace(); var initialProject = workspace.AddProject("TestProject", LanguageNames.CSharp); @@ -83,7 +92,8 @@ int expectedDiagnosticCount var document = workspace.AddDocument(configuredProject.Id, "Test.cs", SourceText.From(source)); - var compilation = (CSharpCompilation)(await document.Project.GetCompilationAsync().ConfigureAwait(false))!; + var compilation = (CSharpCompilation) + (await document.Project.GetCompilationAsync(cancellationToken: cancellationToken).ConfigureAwait(false))!; var compilationWithAnalyzers = compilation.WithAnalyzers(ImmutableArray.Create(analyzer)); var diagnostics = await compilationWithAnalyzers .GetAnalyzerDiagnosticsAsync(CancellationToken.None) @@ -119,7 +129,7 @@ int expectedDiagnosticCount var operations = await registeredAction.GetOperationsAsync(CancellationToken.None).ConfigureAwait(false); var applyChanges = operations.OfType().Single(); var newDocument = applyChanges.ChangedSolution.GetDocument(document.Id)!; - var newRoot = await newDocument.GetSyntaxRootAsync().ConfigureAwait(false); + var newRoot = await newDocument.GetSyntaxRootAsync(cancellationToken: cancellationToken).ConfigureAwait(false); return newRoot!.ToFullString(); } @@ -128,9 +138,12 @@ private static async Task ApplyFixAllCoreAsync( DiagnosticAnalyzer analyzer, CodeFixProvider codeFix, string source, - bool useLegacyReferences + bool useLegacyReferences, + CancellationToken cancellationToken = default ) { + cancellationToken.ThrowIfCancellationRequested(); + using var workspace = new AdhocWorkspace(); var initialProject = workspace.AddProject("TestProject", LanguageNames.CSharp); @@ -155,7 +168,8 @@ bool useLegacyReferences ); } - var equivalenceKey = await GetEquivalenceKeyAsync(document, codeFix, diagnostics[0]).ConfigureAwait(false); + var equivalenceKey = await GetEquivalenceKeyAsync(document, codeFix, diagnostics[0], cancellationToken) + .ConfigureAwait(false); var fixAllProvider = codeFix.GetFixAllProvider() @@ -178,7 +192,7 @@ await fixAllProvider.GetFixAsync(fixAllContext).ConfigureAwait(false) var operations = await fixAllAction.GetOperationsAsync(CancellationToken.None).ConfigureAwait(false); var applyChanges = operations.OfType().Single(); var newDocument = applyChanges.ChangedSolution.GetDocument(document.Id)!; - var newRoot = await newDocument.GetSyntaxRootAsync().ConfigureAwait(false); + var newRoot = await newDocument.GetSyntaxRootAsync(cancellationToken: cancellationToken).ConfigureAwait(false); return newRoot!.ToFullString(); } @@ -186,9 +200,12 @@ await fixAllProvider.GetFixAsync(fixAllContext).ConfigureAwait(false) private static async Task GetEquivalenceKeyAsync( Document document, CodeFixProvider codeFix, - Diagnostic diagnostic + Diagnostic diagnostic, + CancellationToken cancellationToken = default ) { + cancellationToken.ThrowIfCancellationRequested(); + CodeAction? registeredAction = null; var fixContext = new CodeFixContext( document, @@ -208,6 +225,8 @@ private static async Task> GetAnalyzerDiagnosticsAsyn CancellationToken cancellationToken ) { + cancellationToken.ThrowIfCancellationRequested(); + var compilation = (CSharpCompilation) (await document.Project.GetCompilationAsync(cancellationToken).ConfigureAwait(false))!; var compilationWithAnalyzers = compilation.WithAnalyzers(ImmutableArray.Create(analyzer)); @@ -224,6 +243,8 @@ public override async Task> GetAllDiagnosticsAsync( CancellationToken cancellationToken ) { + cancellationToken.ThrowIfCancellationRequested(); + var diagnostics = ImmutableArray.Empty; foreach (var document in project.Documents) diff --git a/tests/NetEvolve.Arguments.Analyser.Tests.Unit/ThrowIfContainsWhiteSpaceAnalyzerTests.cs b/tests/NetEvolve.Arguments.Analyser.Tests.Unit/ThrowIfContainsWhiteSpaceAnalyzerTests.cs index 10c25c8..fc82280 100644 --- a/tests/NetEvolve.Arguments.Analyser.Tests.Unit/ThrowIfContainsWhiteSpaceAnalyzerTests.cs +++ b/tests/NetEvolve.Arguments.Analyser.Tests.Unit/ThrowIfContainsWhiteSpaceAnalyzerTests.cs @@ -1,5 +1,7 @@ namespace NetEvolve.Arguments.Analyser.Tests.Unit; +using System.Threading; + public sealed class ThrowIfContainsWhiteSpaceAnalyzerTests { [Test] @@ -16,8 +18,13 @@ public sealed class ThrowIfContainsWhiteSpaceAnalyzerTests [Arguments("0 != argument.Count(char.IsWhiteSpace)")] [Arguments("argument.Where(c => char.IsWhiteSpace(c)).Any()")] [Arguments("argument.Where(char.IsWhiteSpace).Any()")] - public async Task Analyze_WhenWhiteSpaceCheckThrowsArgumentException_ReportsDiagnosticAndFixes(string condition) + public async Task Analyze_WhenWhiteSpaceCheckThrowsArgumentException_ReportsDiagnosticAndFixes( + string condition, + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + var source = $$""" using System; using System.Linq; @@ -31,7 +38,11 @@ void M(string argument) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfContainsWhiteSpaceAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfContainsWhiteSpaceAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).Count().IsEqualTo(1); _ = await Assert.That(diagnostics[0].Id).IsEqualTo("NEA0008"); @@ -39,7 +50,8 @@ void M(string argument) var fixedSource = await AnalyzerVerifier.ApplyFixAsync( new ThrowIfContainsWhiteSpaceAnalyzer(), new ThrowIfContainsWhiteSpaceCodeFixProvider(), - source + source, + cancellationToken: cancellationToken ); const string expected = """ @@ -59,8 +71,12 @@ void M(string argument) } [Test] - public async Task Analyze_WhenExceptionHasEmptyMessageAndMatchingParamName_ReportsDiagnostic() + public async Task Analyze_WhenExceptionHasEmptyMessageAndMatchingParamName_ReportsDiagnostic( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; using System.Linq; @@ -74,7 +90,11 @@ void M(string argument) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfContainsWhiteSpaceAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfContainsWhiteSpaceAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).Count().IsEqualTo(1); } @@ -115,8 +135,13 @@ void M(string argument) } """ )] - public async Task Analyze_WhenConditionOrExceptionIsNotRecognized_DoesNotReportDiagnostic(string statement) + public async Task Analyze_WhenConditionOrExceptionIsNotRecognized_DoesNotReportDiagnostic( + string statement, + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + var source = $$""" using System; using System.Linq; @@ -130,7 +155,11 @@ void M(string argument, char other) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfContainsWhiteSpaceAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfContainsWhiteSpaceAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).IsEmpty(); } @@ -139,8 +168,13 @@ void M(string argument, char other) [Arguments("char[]")] [Arguments("System.Collections.Generic.List")] [Arguments("System.Collections.Generic.IEnumerable")] - public async Task Analyze_WhenReceiverIsNotString_DoesNotReportDiagnostic(string parameterType) + public async Task Analyze_WhenReceiverIsNotString_DoesNotReportDiagnostic( + string parameterType, + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + var source = $$""" using System; using System.Linq; @@ -154,7 +188,11 @@ void M({{parameterType}} chars) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfContainsWhiteSpaceAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfContainsWhiteSpaceAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).IsEmpty(); } @@ -166,9 +204,12 @@ void M({{parameterType}} chars) [Arguments("System.Collections.Generic.List", "chars.Where(char.IsWhiteSpace).Any()")] public async Task Analyze_WhenReceiverIsNotString_NewShapes_DoesNotReportDiagnostic( string parameterType, - string condition + string condition, + CancellationToken cancellationToken = default ) { + cancellationToken.ThrowIfCancellationRequested(); + var source = $$""" using System; using System.Linq; @@ -182,14 +223,21 @@ void M({{parameterType}} chars) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfContainsWhiteSpaceAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfContainsWhiteSpaceAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).IsEmpty(); } [Test] - public async Task Analyze_WhenReceiverHasNoResolvableType_DoesNotReportDiagnostic() + public async Task Analyze_WhenReceiverHasNoResolvableType_DoesNotReportDiagnostic( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); // "Predicate" refers to the method group C.Predicate(char), which has no type of its own // (SemanticModel.GetTypeInfo(...).Type is null for it), exercising the null-propagation // branch of IsStringReceiver rather than the "resolved but not string" branch already @@ -209,7 +257,11 @@ void M() } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfContainsWhiteSpaceAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfContainsWhiteSpaceAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).IsEmpty(); } @@ -217,8 +269,13 @@ void M() [Test] [Arguments("argument.Count(char.IsWhiteSpace) > 0")] [Arguments("argument.Where(char.IsWhiteSpace).Any()")] - public async Task Analyze_WhenCountOrWhereIsUserDefinedExtension_DoesNotReportDiagnostic(string condition) + public async Task Analyze_WhenCountOrWhereIsUserDefinedExtension_DoesNotReportDiagnostic( + string condition, + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + var source = $$""" using System; @@ -240,14 +297,22 @@ void M(string argument) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfContainsWhiteSpaceAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfContainsWhiteSpaceAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).IsEmpty(); } [Test] - public async Task Analyze_WhenAnyIsUserDefinedExtensionOnWhereResult_DoesNotReportDiagnostic() + public async Task Analyze_WhenAnyIsUserDefinedExtensionOnWhereResult_DoesNotReportDiagnostic( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + var source = """ using System; using System.Linq; @@ -266,14 +331,21 @@ void M(string argument) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfContainsWhiteSpaceAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfContainsWhiteSpaceAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).IsEmpty(); } [Test] - public async Task Analyze_WhenAnyResolutionIsAmbiguous_DoesNotReportDiagnostic() + public async Task Analyze_WhenAnyResolutionIsAmbiguous_DoesNotReportDiagnostic( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); // Two equally applicable extension methods named "Any" make the call ambiguous, so // SemanticModel.GetSymbolInfo(...).Symbol is null (CandidateReason.OverloadResolutionFailure). // This exercises the "Symbol is IMethodSymbol" pattern failing in IsLinqEnumerableMethod, as @@ -302,14 +374,22 @@ void M(string argument) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfContainsWhiteSpaceAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfContainsWhiteSpaceAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).IsEmpty(); } [Test] - public async Task Analyze_WhenAnyIsNotLinqEnumerableAny_DoesNotReportDiagnostic() + public async Task Analyze_WhenAnyIsNotLinqEnumerableAny_DoesNotReportDiagnostic( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + var source = """ using System; using System.Linq; @@ -328,7 +408,11 @@ void M(string argument) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfContainsWhiteSpaceAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfContainsWhiteSpaceAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).IsEmpty(); } diff --git a/tests/NetEvolve.Arguments.Analyser.Tests.Unit/ThrowIfCountAnalyzerTests.cs b/tests/NetEvolve.Arguments.Analyser.Tests.Unit/ThrowIfCountAnalyzerTests.cs index f25f64c..3d94ee3 100644 --- a/tests/NetEvolve.Arguments.Analyser.Tests.Unit/ThrowIfCountAnalyzerTests.cs +++ b/tests/NetEvolve.Arguments.Analyser.Tests.Unit/ThrowIfCountAnalyzerTests.cs @@ -1,5 +1,7 @@ namespace NetEvolve.Arguments.Analyser.Tests.Unit; +using System.Threading; + public sealed class ThrowIfCountAnalyzerTests { [Test] @@ -9,9 +11,12 @@ public sealed class ThrowIfCountAnalyzerTests [Arguments("argument.Count() > 100", "ThrowIfCountGreaterThan(argument, 100);")] public async Task Analyze_WhenCountComparisonThrowsArgumentException_ReportsDiagnosticAndFixes( string condition, - string expectedInvocation + string expectedInvocation, + CancellationToken cancellationToken = default ) { + cancellationToken.ThrowIfCancellationRequested(); + var source = $$""" using System; using System.Collections.Generic; @@ -26,7 +31,11 @@ void M(ICollection argument) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfCountAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfCountAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).Count().IsEqualTo(1); _ = await Assert.That(diagnostics[0].Id).IsEqualTo("NEA0007"); @@ -34,7 +43,8 @@ void M(ICollection argument) var fixedSource = await AnalyzerVerifier.ApplyFixAsync( new ThrowIfCountAnalyzer(), new ThrowIfCountCodeFixProvider(), - source + source, + cancellationToken: cancellationToken ); var expected = $$""" @@ -55,8 +65,12 @@ void M(ICollection argument) } [Test] - public async Task Analyze_WhenExceptionHasEmptyMessageAndMatchingParamName_ReportsDiagnostic() + public async Task Analyze_WhenExceptionHasEmptyMessageAndMatchingParamName_ReportsDiagnostic( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; using System.Collections.Generic; @@ -70,7 +84,11 @@ void M(ICollection argument) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfCountAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfCountAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).Count().IsEqualTo(1); } @@ -92,8 +110,13 @@ void M(ICollection argument) } """ )] - public async Task Analyze_WhenConditionOrExceptionIsNotRecognized_DoesNotReportDiagnostic(string statement) + public async Task Analyze_WhenConditionOrExceptionIsNotRecognized_DoesNotReportDiagnostic( + string statement, + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + var source = $$""" using System; using System.Collections.Generic; @@ -107,14 +130,22 @@ void M(ICollection argument, ICollection other) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfCountAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfCountAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).IsEmpty(); } [Test] - public async Task Analyze_WhenReceiverIsUserDefinedNonCollectionType_DoesNotReportDiagnostic() + public async Task Analyze_WhenReceiverIsUserDefinedNonCollectionType_DoesNotReportDiagnostic( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -132,14 +163,22 @@ void M(Counter argument) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfCountAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfCountAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).IsEmpty(); } [Test] - public async Task Analyze_WhenReceiverIsNonGenericCollection_DoesNotReportDiagnostic() + public async Task Analyze_WhenReceiverIsNonGenericCollection_DoesNotReportDiagnostic( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; using System.Collections; @@ -153,14 +192,22 @@ void M(ArrayList argument) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfCountAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfCountAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).IsEmpty(); } [Test] - public async Task Analyze_WhenCountInvocationIsNotLinqEnumerableCount_DoesNotReportDiagnostic() + public async Task Analyze_WhenCountInvocationIsNotLinqEnumerableCount_DoesNotReportDiagnostic( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; using System.Collections; @@ -184,14 +231,20 @@ void M(Counter argument) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfCountAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfCountAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).IsEmpty(); } [Test] - public async Task Analyze_WhenReceiverIsArray_ReportsDiagnostic() + public async Task Analyze_WhenReceiverIsArray_ReportsDiagnostic(CancellationToken cancellationToken = default) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; using System.Linq; @@ -205,15 +258,23 @@ void M(int[] argument) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfCountAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfCountAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).Count().IsEqualTo(1); _ = await Assert.That(diagnostics[0].Id).IsEqualTo("NEA0007"); } [Test] - public async Task Analyze_WhenReceiverIsPlainIEnumerable_ReportsDiagnostic() + public async Task Analyze_WhenReceiverIsPlainIEnumerable_ReportsDiagnostic( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; using System.Collections.Generic; @@ -228,15 +289,21 @@ void M(IEnumerable argument) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfCountAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfCountAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).Count().IsEqualTo(1); _ = await Assert.That(diagnostics[0].Id).IsEqualTo("NEA0007"); } [Test] - public async Task Analyze_WhenReceiverIsString_ReportsDiagnostic() + public async Task Analyze_WhenReceiverIsString_ReportsDiagnostic(CancellationToken cancellationToken = default) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; using System.Linq; @@ -250,15 +317,23 @@ void M(string argument) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfCountAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfCountAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).Count().IsEqualTo(1); _ = await Assert.That(diagnostics[0].Id).IsEqualTo("NEA0007"); } [Test] - public async Task Analyze_WhenReceiverTypeIsUnresolved_DoesNotReportDiagnostic() + public async Task Analyze_WhenReceiverTypeIsUnresolved_DoesNotReportDiagnostic( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -271,7 +346,11 @@ void M() } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfCountAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfCountAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).IsEmpty(); } diff --git a/tests/NetEvolve.Arguments.Analyser.Tests.Unit/ThrowIfDefaultAnalyzerTests.cs b/tests/NetEvolve.Arguments.Analyser.Tests.Unit/ThrowIfDefaultAnalyzerTests.cs index 6f81e54..566287b 100644 --- a/tests/NetEvolve.Arguments.Analyser.Tests.Unit/ThrowIfDefaultAnalyzerTests.cs +++ b/tests/NetEvolve.Arguments.Analyser.Tests.Unit/ThrowIfDefaultAnalyzerTests.cs @@ -1,6 +1,7 @@ namespace NetEvolve.Arguments.Analyser.Tests.Unit; using System; +using System.Threading; public sealed class ThrowIfDefaultAnalyzerTests { @@ -10,8 +11,13 @@ public sealed class ThrowIfDefaultAnalyzerTests [Arguments("default == argument")] [Arguments("argument.Equals(default(Guid))")] [Arguments("argument == default(Guid)")] - public async Task Analyze_WhenDefaultCheckThrowsArgumentException_ReportsDiagnostic(string condition) + public async Task Analyze_WhenDefaultCheckThrowsArgumentException_ReportsDiagnostic( + string condition, + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + var source = $$""" using System; @@ -24,7 +30,11 @@ void M(Guid argument) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfDefaultAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfDefaultAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).Count().IsEqualTo(1); _ = await Assert.That(diagnostics[0].Id).IsEqualTo("NEA0004"); @@ -45,8 +55,13 @@ void M(Guid argument) } """ )] - public async Task Analyze_WhenConditionOrExceptionIsNotRecognized_DoesNotReportDiagnostic(string statement) + public async Task Analyze_WhenConditionOrExceptionIsNotRecognized_DoesNotReportDiagnostic( + string statement, + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + var source = $$""" using System; @@ -59,14 +74,22 @@ void M(Guid argument) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfDefaultAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfDefaultAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).IsEmpty(); } [Test] - public async Task Analyze_WhenArgumentTypeIsReferenceType_DoesNotReportDiagnostic() + public async Task Analyze_WhenArgumentTypeIsReferenceType_DoesNotReportDiagnostic( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -79,14 +102,22 @@ void M(string argument) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfDefaultAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfDefaultAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).IsEmpty(); } [Test] - public async Task Analyze_WhenArgumentTypeIsNullableValueType_DoesNotReportDiagnostic() + public async Task Analyze_WhenArgumentTypeIsNullableValueType_DoesNotReportDiagnostic( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -99,14 +130,22 @@ void M(Guid? argument) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfDefaultAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfDefaultAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).IsEmpty(); } [Test] - public async Task Analyze_WhenArgumentTypeIsStructWithoutIEquatable_DoesNotReportDiagnostic() + public async Task Analyze_WhenArgumentTypeIsStructWithoutIEquatable_DoesNotReportDiagnostic( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -123,14 +162,22 @@ void M(S argument) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfDefaultAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfDefaultAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).IsEmpty(); } [Test] - public async Task Analyze_WhenParamNameIsStringLiteral_ReportsDiagnostic() + public async Task Analyze_WhenParamNameIsStringLiteral_ReportsDiagnostic( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -143,14 +190,20 @@ void M(Guid argument) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfDefaultAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfDefaultAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).Count().IsEqualTo(1); } [Test] - public async Task CodeFix_WhenApplied_ReplacesWithThrowIfDefaultCall() + public async Task CodeFix_WhenApplied_ReplacesWithThrowIfDefaultCall(CancellationToken cancellationToken = default) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -166,7 +219,8 @@ void M(Guid argument) var fixedSource = await AnalyzerVerifier.ApplyFixAsync( new ThrowIfDefaultAnalyzer(), new ThrowIfDefaultCodeFixProvider(), - source + source, + cancellationToken: cancellationToken ); const string expected = """ @@ -185,8 +239,12 @@ void M(Guid argument) } [Test] - public async Task CodeFix_WhenBlockContainsInteriorComment_PreservesCommentExactlyOnce() + public async Task CodeFix_WhenBlockContainsInteriorComment_PreservesCommentExactlyOnce( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -207,7 +265,8 @@ void M(Guid argument) var fixedSource = await AnalyzerVerifier.ApplyFixAsync( new ThrowIfDefaultAnalyzer(), new ThrowIfDefaultCodeFixProvider(), - source + source, + cancellationToken: cancellationToken ); _ = await Assert.That(fixedSource).Contains("ArgumentException.ThrowIfDefault(argument);"); diff --git a/tests/NetEvolve.Arguments.Analyser.Tests.Unit/ThrowIfDisposedAnalyzerTests.cs b/tests/NetEvolve.Arguments.Analyser.Tests.Unit/ThrowIfDisposedAnalyzerTests.cs index 03c5615..4a0a194 100644 --- a/tests/NetEvolve.Arguments.Analyser.Tests.Unit/ThrowIfDisposedAnalyzerTests.cs +++ b/tests/NetEvolve.Arguments.Analyser.Tests.Unit/ThrowIfDisposedAnalyzerTests.cs @@ -1,10 +1,16 @@ namespace NetEvolve.Arguments.Analyser.Tests.Unit; +using System.Threading; + public sealed class ThrowIfDisposedAnalyzerTests { [Test] - public async Task Analyze_WhenDisposedCheckThrowsObjectDisposedException_ReportsDiagnostic() + public async Task Analyze_WhenDisposedCheckThrowsObjectDisposedException_ReportsDiagnostic( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -19,15 +25,23 @@ void M() } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfDisposedAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfDisposedAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).Count().IsEqualTo(1); _ = await Assert.That(diagnostics[0].Id).IsEqualTo("NEA0005"); } [Test] - public async Task Analyze_WhenExceptionHasAnExplicitMessage_DoesNotReportDiagnostic() + public async Task Analyze_WhenExceptionHasAnExplicitMessage_DoesNotReportDiagnostic( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -42,14 +56,20 @@ void M() } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfDisposedAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfDisposedAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).IsEmpty(); } [Test] - public async Task Analyze_WhenInStaticMethod_DoesNotReportDiagnostic() + public async Task Analyze_WhenInStaticMethod_DoesNotReportDiagnostic(CancellationToken cancellationToken = default) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -64,14 +84,22 @@ static void M() } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfDisposedAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfDisposedAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).IsEmpty(); } [Test] - public async Task Analyze_WhenInLocalFunctionInsideStaticMethod_DoesNotReportDiagnostic() + public async Task Analyze_WhenInLocalFunctionInsideStaticMethod_DoesNotReportDiagnostic( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -91,14 +119,22 @@ void Check() } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfDisposedAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfDisposedAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).IsEmpty(); } [Test] - public async Task Analyze_WhenInLambdaInsideStaticMethod_DoesNotReportDiagnostic() + public async Task Analyze_WhenInLambdaInsideStaticMethod_DoesNotReportDiagnostic( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -118,14 +154,22 @@ static void M() } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfDisposedAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfDisposedAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).IsEmpty(); } [Test] - public async Task Analyze_WhenInLocalFunctionInsideInstanceMethod_ReportsDiagnostic() + public async Task Analyze_WhenInLocalFunctionInsideInstanceMethod_ReportsDiagnostic( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -145,7 +189,11 @@ void Check() } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfDisposedAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfDisposedAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).Count().IsEqualTo(1); _ = await Assert.That(diagnostics[0].Id).IsEqualTo("NEA0005"); @@ -164,8 +212,13 @@ void Check() } """ )] - public async Task Analyze_WhenExceptionTypeOrShapeIsNotRecognized_DoesNotReportDiagnostic(string statement) + public async Task Analyze_WhenExceptionTypeOrShapeIsNotRecognized_DoesNotReportDiagnostic( + string statement, + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + var source = $$""" using System; @@ -180,14 +233,22 @@ void M() } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfDisposedAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfDisposedAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).IsEmpty(); } [Test] - public async Task Analyze_WhenBuiltInThrowIfAvailable_DoesNotReportDiagnostic() + public async Task Analyze_WhenBuiltInThrowIfAvailable_DoesNotReportDiagnostic( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -205,15 +266,18 @@ void M() var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( new ThrowIfDisposedAnalyzer(), source, - useLegacyReferences: false + useLegacyReferences: false, + cancellationToken: cancellationToken ); _ = await Assert.That(diagnostics).IsEmpty(); } [Test] - public async Task CodeFix_WhenApplied_ReplacesWithThrowIfCall() + public async Task CodeFix_WhenApplied_ReplacesWithThrowIfCall(CancellationToken cancellationToken = default) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -231,7 +295,8 @@ void M() var fixedSource = await AnalyzerVerifier.ApplyFixAsync( new ThrowIfDisposedAnalyzer(), new ThrowIfDisposedCodeFixProvider(), - source + source, + cancellationToken: cancellationToken ); const string expected = """ diff --git a/tests/NetEvolve.Arguments.Analyser.Tests.Unit/ThrowIfEmptyGuidAnalyzerTests.cs b/tests/NetEvolve.Arguments.Analyser.Tests.Unit/ThrowIfEmptyGuidAnalyzerTests.cs index ee7cbfd..9ded57d 100644 --- a/tests/NetEvolve.Arguments.Analyser.Tests.Unit/ThrowIfEmptyGuidAnalyzerTests.cs +++ b/tests/NetEvolve.Arguments.Analyser.Tests.Unit/ThrowIfEmptyGuidAnalyzerTests.cs @@ -1,13 +1,20 @@ namespace NetEvolve.Arguments.Analyser.Tests.Unit; +using System.Threading; + public sealed class ThrowIfEmptyGuidAnalyzerTests { [Test] [Arguments("argument == Guid.Empty")] [Arguments("Guid.Empty == argument")] [Arguments("argument.Equals(Guid.Empty)")] - public async Task Analyze_WhenEmptyGuidCheckThrowsArgumentException_ReportsDiagnostic(string condition) + public async Task Analyze_WhenEmptyGuidCheckThrowsArgumentException_ReportsDiagnostic( + string condition, + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + var source = $$""" using System; @@ -20,7 +27,11 @@ void M(Guid argument) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfEmptyGuidAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfEmptyGuidAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).Count().IsEqualTo(1); _ = await Assert.That(diagnostics[0].Id).IsEqualTo("NEA0009"); @@ -41,8 +52,13 @@ void M(Guid argument) } """ )] - public async Task Analyze_WhenConditionOrExceptionIsNotRecognized_DoesNotReportDiagnostic(string statement) + public async Task Analyze_WhenConditionOrExceptionIsNotRecognized_DoesNotReportDiagnostic( + string statement, + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + var source = $$""" using System; @@ -55,14 +71,22 @@ void M(Guid argument) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfEmptyGuidAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfEmptyGuidAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).IsEmpty(); } [Test] - public async Task Analyze_WhenArgumentIsNullableGuid_DoesNotReportDiagnostic() + public async Task Analyze_WhenArgumentIsNullableGuid_DoesNotReportDiagnostic( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -75,14 +99,22 @@ void M(Guid? argument) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfEmptyGuidAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfEmptyGuidAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).IsEmpty(); } [Test] - public async Task Analyze_WhenArgumentIsObject_DoesNotReportDiagnostic() + public async Task Analyze_WhenArgumentIsObject_DoesNotReportDiagnostic( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -95,14 +127,22 @@ void M(object argument) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfEmptyGuidAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfEmptyGuidAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).IsEmpty(); } [Test] - public async Task Analyze_WhenGuidIsUserDefinedType_DoesNotReportDiagnostic() + public async Task Analyze_WhenGuidIsUserDefinedType_DoesNotReportDiagnostic( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; using Guid = Other.Guid; @@ -124,14 +164,22 @@ void M(Guid argument) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfEmptyGuidAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfEmptyGuidAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).IsEmpty(); } [Test] - public async Task CodeFix_WhenApplied_ReplacesWithThrowIfEmptyGuidCall() + public async Task CodeFix_WhenApplied_ReplacesWithThrowIfEmptyGuidCall( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -147,7 +195,8 @@ void M(Guid argument) var fixedSource = await AnalyzerVerifier.ApplyFixAsync( new ThrowIfEmptyGuidAnalyzer(), new ThrowIfEmptyGuidCodeFixProvider(), - source + source, + cancellationToken: cancellationToken ); const string expected = """ diff --git a/tests/NetEvolve.Arguments.Analyser.Tests.Unit/ThrowIfLengthAnalyzerTests.cs b/tests/NetEvolve.Arguments.Analyser.Tests.Unit/ThrowIfLengthAnalyzerTests.cs index 75f07c2..6e922e0 100644 --- a/tests/NetEvolve.Arguments.Analyser.Tests.Unit/ThrowIfLengthAnalyzerTests.cs +++ b/tests/NetEvolve.Arguments.Analyser.Tests.Unit/ThrowIfLengthAnalyzerTests.cs @@ -1,5 +1,7 @@ namespace NetEvolve.Arguments.Analyser.Tests.Unit; +using System.Threading; + public sealed class ThrowIfLengthAnalyzerTests { [Test] @@ -8,9 +10,12 @@ public sealed class ThrowIfLengthAnalyzerTests [Arguments("argument.Length < 5 || argument.Length > 100", "ThrowIfLengthOutOfRange(argument, 5, 100);")] public async Task Analyze_WhenLengthComparisonThrowsArgumentException_ReportsDiagnosticAndFixes( string condition, - string expectedInvocation + string expectedInvocation, + CancellationToken cancellationToken = default ) { + cancellationToken.ThrowIfCancellationRequested(); + var source = $$""" using System; @@ -23,7 +28,11 @@ void M(string argument) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfLengthAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfLengthAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).Count().IsEqualTo(1); _ = await Assert.That(diagnostics[0].Id).IsEqualTo("NEA0006"); @@ -31,7 +40,8 @@ void M(string argument) var fixedSource = await AnalyzerVerifier.ApplyFixAsync( new ThrowIfLengthAnalyzer(), new ThrowIfLengthCodeFixProvider(), - source + source, + cancellationToken: cancellationToken ); var expected = $$""" @@ -50,8 +60,12 @@ void M(string argument) } [Test] - public async Task Analyze_WhenCombinedRangeTargetsHaveInteriorTrivia_ReportsDiagnostic() + public async Task Analyze_WhenCombinedRangeTargetsHaveInteriorTrivia_ReportsDiagnostic( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + var source = """ using System; @@ -70,15 +84,23 @@ void M(Options options) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfLengthAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfLengthAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).Count().IsEqualTo(1); _ = await Assert.That(diagnostics[0].Id).IsEqualTo("NEA0006"); } [Test] - public async Task Analyze_WhenExceptionHasEmptyMessageAndMatchingParamName_ReportsDiagnostic() + public async Task Analyze_WhenExceptionHasEmptyMessageAndMatchingParamName_ReportsDiagnostic( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -91,7 +113,11 @@ void M(string argument) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfLengthAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfLengthAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).Count().IsEqualTo(1); } @@ -114,8 +140,13 @@ void M(string argument) } """ )] - public async Task Analyze_WhenConditionOrExceptionIsNotRecognized_DoesNotReportDiagnostic(string statement) + public async Task Analyze_WhenConditionOrExceptionIsNotRecognized_DoesNotReportDiagnostic( + string statement, + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + var source = $$""" using System; @@ -128,7 +159,11 @@ void M(string argument, string other) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfLengthAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfLengthAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).IsEmpty(); } @@ -136,8 +171,14 @@ void M(string argument, string other) [Test] [Arguments("int[] argument", "argument.Length > 100")] [Arguments("System.Span argument", "argument.Length > 100")] - public async Task Analyze_WhenLengthReceiverIsNotString_DoesNotReportDiagnostic(string parameter, string condition) + public async Task Analyze_WhenLengthReceiverIsNotString_DoesNotReportDiagnostic( + string parameter, + string condition, + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + var source = $$""" using System; @@ -150,14 +191,22 @@ void M({{parameter}}) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfLengthAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfLengthAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).IsEmpty(); } [Test] - public async Task Analyze_WhenLengthReceiverIsUserDefinedTypeWithLengthProperty_DoesNotReportDiagnostic() + public async Task Analyze_WhenLengthReceiverIsUserDefinedTypeWithLengthProperty_DoesNotReportDiagnostic( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + var source = """ using System; @@ -175,7 +224,11 @@ void M(Buffer argument) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfLengthAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfLengthAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).IsEmpty(); } diff --git a/tests/NetEvolve.Arguments.Analyser.Tests.Unit/ThrowIfNullAnalyzerTests.cs b/tests/NetEvolve.Arguments.Analyser.Tests.Unit/ThrowIfNullAnalyzerTests.cs index ba8a457..606eb0c 100644 --- a/tests/NetEvolve.Arguments.Analyser.Tests.Unit/ThrowIfNullAnalyzerTests.cs +++ b/tests/NetEvolve.Arguments.Analyser.Tests.Unit/ThrowIfNullAnalyzerTests.cs @@ -1,12 +1,17 @@ namespace NetEvolve.Arguments.Analyser.Tests.Unit; using System; +using System.Threading; public sealed class ThrowIfNullAnalyzerTests { [Test] - public async Task Analyze_WhenIsNullCheckThrowsArgumentNullException_ReportsDiagnostic() + public async Task Analyze_WhenIsNullCheckThrowsArgumentNullException_ReportsDiagnostic( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -19,7 +24,11 @@ void M(string? argument) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfNullAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfNullAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).Count().IsEqualTo(1); _ = await Assert.That(diagnostics[0].Id).IsEqualTo("NEA0001"); @@ -36,8 +45,13 @@ void M(string? argument) [Arguments("!(null != argument)")] [Arguments("object.ReferenceEquals(argument, null)")] [Arguments("(argument is null)")] - public async Task Analyze_WhenUsingRecognizedNullCheckVariant_ReportsDiagnostic(string condition) + public async Task Analyze_WhenUsingRecognizedNullCheckVariant_ReportsDiagnostic( + string condition, + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + var source = $$""" using System; @@ -50,7 +64,11 @@ void M(string? argument) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfNullAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfNullAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).Count().IsEqualTo(1); } @@ -60,8 +78,13 @@ void M(string? argument) [Arguments("!(argument is null)")] [Arguments("argument != null")] [Arguments("null != argument")] - public async Task Analyze_WhenConditionMeansNonNull_DoesNotReportDiagnostic(string condition) + public async Task Analyze_WhenConditionMeansNonNull_DoesNotReportDiagnostic( + string condition, + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + var source = $$""" using System; @@ -74,14 +97,22 @@ void M(string? argument) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfNullAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfNullAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).IsEmpty(); } [Test] - public async Task Analyze_WhenCoalesceThrowsArgumentNullException_ReportsDiagnostic() + public async Task Analyze_WhenCoalesceThrowsArgumentNullException_ReportsDiagnostic( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -96,15 +127,23 @@ public C(string? argument) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfNullAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfNullAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).Count().IsEqualTo(1); _ = await Assert.That(diagnostics[0].Id).IsEqualTo("NEA0001"); } [Test] - public async Task CodeFix_WhenAppliedToCoalesce_HoistsThrowIfNullAndKeepsAssignment() + public async Task CodeFix_WhenAppliedToCoalesce_HoistsThrowIfNullAndKeepsAssignment( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -122,7 +161,8 @@ public C(string? argument) var fixedSource = await AnalyzerVerifier.ApplyFixAsync( new ThrowIfNullAnalyzer(), new ThrowIfNullCodeFixProvider(), - source + source, + cancellationToken: cancellationToken ); _ = await Assert.That(fixedSource).Contains("ArgumentNullException.ThrowIfNull(argument);"); @@ -131,8 +171,12 @@ public C(string? argument) } [Test] - public async Task CodeFix_WhenAppliedToCoalesceWithRegionTrivia_DoesNotDuplicateLeadingTrivia() + public async Task CodeFix_WhenAppliedToCoalesceWithRegionTrivia_DoesNotDuplicateLeadingTrivia( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -152,7 +196,8 @@ public C(string? argument) var fixedSource = await AnalyzerVerifier.ApplyFixAsync( new ThrowIfNullAnalyzer(), new ThrowIfNullCodeFixProvider(), - source + source, + cancellationToken: cancellationToken ); var regionOccurrences = CountOccurrences(fixedSource, "#region Guards"); @@ -165,8 +210,12 @@ public C(string? argument) } [Test] - public async Task CodeFix_WhenAppliedToCoalesceWithLeadingComment_DoesNotDuplicateComment() + public async Task CodeFix_WhenAppliedToCoalesceWithLeadingComment_DoesNotDuplicateComment( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -185,7 +234,8 @@ public C(string? argument) var fixedSource = await AnalyzerVerifier.ApplyFixAsync( new ThrowIfNullAnalyzer(), new ThrowIfNullCodeFixProvider(), - source + source, + cancellationToken: cancellationToken ); var commentOccurrences = CountOccurrences(fixedSource, "// validate input"); @@ -196,8 +246,12 @@ public C(string? argument) } [Test] - public async Task CodeFix_WhenAppliedToCoalesceInWhileEmbeddedStatement_WrapsInBlock() + public async Task CodeFix_WhenAppliedToCoalesceInWhileEmbeddedStatement_WrapsInBlock( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -216,7 +270,8 @@ void M(string? argument, bool flag) var fixedSource = await AnalyzerVerifier.ApplyFixAsync( new ThrowIfNullAnalyzer(), new ThrowIfNullCodeFixProvider(), - source + source, + cancellationToken: cancellationToken ); var normalized = fixedSource.Replace("\r\n", "\n", StringComparison.Ordinal); @@ -228,8 +283,12 @@ void M(string? argument, bool flag) } [Test] - public async Task CodeFix_WhenAppliedToCoalesceInWhileEmbeddedStatementWithLeadingComment_DoesNotDuplicateComment() + public async Task CodeFix_WhenAppliedToCoalesceInWhileEmbeddedStatementWithLeadingComment_DoesNotDuplicateComment( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -249,7 +308,8 @@ void M(string? argument, bool flag) var fixedSource = await AnalyzerVerifier.ApplyFixAsync( new ThrowIfNullAnalyzer(), new ThrowIfNullCodeFixProvider(), - source + source, + cancellationToken: cancellationToken ); var commentOccurrences = CountOccurrences(fixedSource, "// validate input"); @@ -261,8 +321,12 @@ void M(string? argument, bool flag) } [Test] - public async Task CodeFix_WhenAppliedToCoalesceInLockEmbeddedStatement_WrapsInBlock() + public async Task CodeFix_WhenAppliedToCoalesceInLockEmbeddedStatement_WrapsInBlock( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -282,7 +346,8 @@ void M(string? argument) var fixedSource = await AnalyzerVerifier.ApplyFixAsync( new ThrowIfNullAnalyzer(), new ThrowIfNullCodeFixProvider(), - source + source, + cancellationToken: cancellationToken ); var normalized = fixedSource.Replace("\r\n", "\n", StringComparison.Ordinal); @@ -308,8 +373,12 @@ private static int CountOccurrences(string source, string value) } [Test] - public async Task Analyze_WhenBuiltInThrowIfNullAvailable_DoesNotReportDiagnostic() + public async Task Analyze_WhenBuiltInThrowIfNullAvailable_DoesNotReportDiagnostic( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -325,15 +394,20 @@ void M(string? argument) var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( new ThrowIfNullAnalyzer(), source, - useLegacyReferences: false + useLegacyReferences: false, + cancellationToken: cancellationToken ); _ = await Assert.That(diagnostics).IsEmpty(); } [Test] - public async Task Analyze_WhenExceptionHasNoArguments_ReportsDiagnostic() + public async Task Analyze_WhenExceptionHasNoArguments_ReportsDiagnostic( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -346,14 +420,22 @@ void M(string? argument) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfNullAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfNullAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).Count().IsEqualTo(1); } [Test] - public async Task Analyze_WhenParamNameDoesNotMatchCheckedArgument_DoesNotReportDiagnostic() + public async Task Analyze_WhenParamNameDoesNotMatchCheckedArgument_DoesNotReportDiagnostic( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -366,7 +448,11 @@ void M(string? argument, string other) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfNullAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfNullAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).IsEmpty(); } @@ -374,8 +460,13 @@ void M(string? argument, string other) [Test] [Arguments("_value = argument ?? throw new ArgumentException(nameof(argument));")] [Arguments("_value = argument ?? throw new ArgumentNullException(nameof(argument), \"custom\");")] - public async Task Analyze_WhenCoalesceThrowIsNotRecognized_DoesNotReportDiagnostic(string statement) + public async Task Analyze_WhenCoalesceThrowIsNotRecognized_DoesNotReportDiagnostic( + string statement, + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + var source = $$""" using System; @@ -390,14 +481,22 @@ public C(string? argument) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfNullAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfNullAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).IsEmpty(); } [Test] - public async Task Analyze_WhenExceptionHasCustomMessage_DoesNotReportDiagnostic() + public async Task Analyze_WhenExceptionHasCustomMessage_DoesNotReportDiagnostic( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -410,14 +509,20 @@ void M(string? argument) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfNullAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfNullAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).IsEmpty(); } [Test] - public async Task Analyze_WhenIfHasElseClause_DoesNotReportDiagnostic() + public async Task Analyze_WhenIfHasElseClause_DoesNotReportDiagnostic(CancellationToken cancellationToken = default) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -436,14 +541,22 @@ void M(string? argument) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfNullAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfNullAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).IsEmpty(); } [Test] - public async Task Analyze_WhenCoalesceInSimpleLambdaParameterExpression_DoesNotReportDiagnostic() + public async Task Analyze_WhenCoalesceInSimpleLambdaParameterExpression_DoesNotReportDiagnostic( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -456,14 +569,22 @@ void M() } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfNullAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfNullAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).IsEmpty(); } [Test] - public async Task Analyze_WhenCoalesceInParenthesizedLambdaCapturingOuterVariable_DoesNotReportDiagnostic() + public async Task Analyze_WhenCoalesceInParenthesizedLambdaCapturingOuterVariable_DoesNotReportDiagnostic( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -476,14 +597,22 @@ void M(string? a) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfNullAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfNullAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).IsEmpty(); } [Test] - public async Task Analyze_WhenCoalesceInsideConditionalExpressionBranch_DoesNotReportDiagnostic() + public async Task Analyze_WhenCoalesceInsideConditionalExpressionBranch_DoesNotReportDiagnostic( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -496,14 +625,22 @@ void M(bool flag, string? a) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfNullAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfNullAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).IsEmpty(); } [Test] - public async Task Analyze_WhenCoalesceInStatementBodiedLambda_ReportsDiagnostic() + public async Task Analyze_WhenCoalesceInStatementBodiedLambda_ReportsDiagnostic( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -519,15 +656,23 @@ void M() } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfNullAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfNullAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).Count().IsEqualTo(1); _ = await Assert.That(diagnostics[0].Id).IsEqualTo("NEA0001"); } [Test] - public async Task Analyze_WhenCoalesceInAnonymousMethodStatement_ReportsDiagnostic() + public async Task Analyze_WhenCoalesceInAnonymousMethodStatement_ReportsDiagnostic( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -543,15 +688,23 @@ void M() } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfNullAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfNullAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).Count().IsEqualTo(1); _ = await Assert.That(diagnostics[0].Id).IsEqualTo("NEA0001"); } [Test] - public async Task Analyze_WhenCoalesceInExpressionBodiedProperty_DoesNotReportDiagnostic() + public async Task Analyze_WhenCoalesceInExpressionBodiedProperty_DoesNotReportDiagnostic( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -563,14 +716,22 @@ class C } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfNullAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfNullAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).IsEmpty(); } [Test] - public async Task Analyze_WhenCoalesceInConditionalExpressionWhenFalseBranch_DoesNotReportDiagnostic() + public async Task Analyze_WhenCoalesceInConditionalExpressionWhenFalseBranch_DoesNotReportDiagnostic( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -583,14 +744,22 @@ void M(bool flag, string? a) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfNullAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfNullAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).IsEmpty(); } [Test] - public async Task Analyze_WhenCoalesceIsConditionOfTernary_ReportsDiagnostic() + public async Task Analyze_WhenCoalesceIsConditionOfTernary_ReportsDiagnostic( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -603,15 +772,23 @@ void M(bool? b) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfNullAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfNullAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).Count().IsEqualTo(1); _ = await Assert.That(diagnostics[0].Id).IsEqualTo("NEA0001"); } [Test] - public async Task Analyze_WhenCoalesceIsRightOperandOfEnclosingCoalesce_DoesNotReportDiagnostic() + public async Task Analyze_WhenCoalesceIsRightOperandOfEnclosingCoalesce_DoesNotReportDiagnostic( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -624,14 +801,22 @@ void M(string? a, string? b) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfNullAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfNullAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).IsEmpty(); } [Test] - public async Task Analyze_WhenCoalesceIsRightOperandOfLogicalAnd_DoesNotReportDiagnostic() + public async Task Analyze_WhenCoalesceIsRightOperandOfLogicalAnd_DoesNotReportDiagnostic( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -644,14 +829,22 @@ void M(bool flag, bool? b) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfNullAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfNullAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).IsEmpty(); } [Test] - public async Task Analyze_WhenCoalesceIsRightOperandOfLogicalOr_DoesNotReportDiagnostic() + public async Task Analyze_WhenCoalesceIsRightOperandOfLogicalOr_DoesNotReportDiagnostic( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -664,14 +857,22 @@ void M(bool flag, bool? b) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfNullAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfNullAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).IsEmpty(); } [Test] - public async Task Analyze_WhenCoalesceIsLeftOperandOfLogicalAnd_ReportsDiagnostic() + public async Task Analyze_WhenCoalesceIsLeftOperandOfLogicalAnd_ReportsDiagnostic( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -684,15 +885,23 @@ void M(bool flag, bool? b) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfNullAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfNullAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).Count().IsEqualTo(1); _ = await Assert.That(diagnostics[0].Id).IsEqualTo("NEA0001"); } [Test] - public async Task Analyze_WhenCoalesceIsLeftOperandOfLogicalOr_ReportsDiagnostic() + public async Task Analyze_WhenCoalesceIsLeftOperandOfLogicalOr_ReportsDiagnostic( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -705,15 +914,23 @@ void M(bool flag, bool? b) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfNullAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfNullAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).Count().IsEqualTo(1); _ = await Assert.That(diagnostics[0].Id).IsEqualTo("NEA0001"); } [Test] - public async Task Analyze_WhenCoalesceIsLeftOperandOfEnclosingCoalesce_ReportsDiagnostic() + public async Task Analyze_WhenCoalesceIsLeftOperandOfEnclosingCoalesce_ReportsDiagnostic( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -726,15 +943,23 @@ void M(string? a) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfNullAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfNullAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).Count().IsEqualTo(1); _ = await Assert.That(diagnostics[0].Id).IsEqualTo("NEA0001"); } [Test] - public async Task CodeFix_WhenCoalesceIsNestedInsideIfStatement_HoistsThrowIfNullAndKeepsAssignment() + public async Task CodeFix_WhenCoalesceIsNestedInsideIfStatement_HoistsThrowIfNullAndKeepsAssignment( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -753,7 +978,8 @@ void M(string? target, string? source) var fixedSource = await AnalyzerVerifier.ApplyFixAsync( new ThrowIfNullAnalyzer(), new ThrowIfNullCodeFixProvider(), - source + source, + cancellationToken: cancellationToken ); _ = await Assert.That(fixedSource).Contains("ArgumentNullException.ThrowIfNull(source);"); @@ -762,8 +988,12 @@ void M(string? target, string? source) } [Test] - public async Task CodeFix_WhenCoalesceIsNestedInsideUnrelatedIfStatement_StillAppliesCoalesceFix() + public async Task CodeFix_WhenCoalesceIsNestedInsideUnrelatedIfStatement_StillAppliesCoalesceFix( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -782,7 +1012,8 @@ void M(bool flag, string? source) var fixedSource = await AnalyzerVerifier.ApplyFixAsync( new ThrowIfNullAnalyzer(), new ThrowIfNullCodeFixProvider(), - source + source, + cancellationToken: cancellationToken ); _ = await Assert.That(fixedSource).Contains("ArgumentNullException.ThrowIfNull(source);"); @@ -791,8 +1022,10 @@ void M(bool flag, string? source) } [Test] - public async Task CodeFix_WhenApplied_ReplacesWithThrowIfNullCall() + public async Task CodeFix_WhenApplied_ReplacesWithThrowIfNullCall(CancellationToken cancellationToken = default) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -808,7 +1041,8 @@ void M(string? argument) var fixedSource = await AnalyzerVerifier.ApplyFixAsync( new ThrowIfNullAnalyzer(), new ThrowIfNullCodeFixProvider(), - source + source, + cancellationToken: cancellationToken ); _ = await Assert.That(fixedSource).Contains("ArgumentNullException.ThrowIfNull(argument);"); @@ -816,8 +1050,12 @@ void M(string? argument) } [Test] - public async Task CodeFix_WhenSourceHasNoUsingSystemAndThrowIsFullyQualified_AddsUsingSystemDirective() + public async Task CodeFix_WhenSourceHasNoUsingSystemAndThrowIsFullyQualified_AddsUsingSystemDirective( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ class C { @@ -831,7 +1069,8 @@ void M(string? argument) var fixedSource = await AnalyzerVerifier.ApplyFixAsync( new ThrowIfNullAnalyzer(), new ThrowIfNullCodeFixProvider(), - source + source, + cancellationToken: cancellationToken ); _ = await Assert.That(fixedSource).Contains("using System;"); @@ -840,8 +1079,12 @@ void M(string? argument) } [Test] - public async Task CodeFix_WhenFileScopedNamespaceHasNoUsingSystem_AddsUsingSystemDirective() + public async Task CodeFix_WhenFileScopedNamespaceHasNoUsingSystem_AddsUsingSystemDirective( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ namespace Test; @@ -857,7 +1100,8 @@ void M(string? argument) var fixedSource = await AnalyzerVerifier.ApplyFixAsync( new ThrowIfNullAnalyzer(), new ThrowIfNullCodeFixProvider(), - source + source, + cancellationToken: cancellationToken ); _ = await Assert.That(fixedSource).Contains("using System;"); @@ -866,8 +1110,12 @@ void M(string? argument) } [Test] - public async Task CodeFix_WhenFileScopedNamespaceAlreadyHasUsingSystem_DoesNotDuplicateDirective() + public async Task CodeFix_WhenFileScopedNamespaceAlreadyHasUsingSystem_DoesNotDuplicateDirective( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ namespace Test; @@ -885,7 +1133,8 @@ void M(string? argument) var fixedSource = await AnalyzerVerifier.ApplyFixAsync( new ThrowIfNullAnalyzer(), new ThrowIfNullCodeFixProvider(), - source + source, + cancellationToken: cancellationToken ); _ = await Assert.That(fixedSource).Contains("ArgumentNullException.ThrowIfNull(argument);"); @@ -893,8 +1142,12 @@ void M(string? argument) } [Test] - public async Task CodeFix_WhenBlockScopedNamespaceHasNoUsingSystem_AddsUsingSystemDirective() + public async Task CodeFix_WhenBlockScopedNamespaceHasNoUsingSystem_AddsUsingSystemDirective( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ namespace Test { @@ -911,7 +1164,8 @@ void M(string? argument) var fixedSource = await AnalyzerVerifier.ApplyFixAsync( new ThrowIfNullAnalyzer(), new ThrowIfNullCodeFixProvider(), - source + source, + cancellationToken: cancellationToken ); _ = await Assert.That(fixedSource).Contains("using System;"); @@ -920,8 +1174,12 @@ void M(string? argument) } [Test] - public async Task CodeFix_WhenBlockScopedNamespaceAlreadyHasUsingSystem_DoesNotDuplicateDirective() + public async Task CodeFix_WhenBlockScopedNamespaceAlreadyHasUsingSystem_DoesNotDuplicateDirective( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ namespace Test { @@ -940,7 +1198,8 @@ void M(string? argument) var fixedSource = await AnalyzerVerifier.ApplyFixAsync( new ThrowIfNullAnalyzer(), new ThrowIfNullCodeFixProvider(), - source + source, + cancellationToken: cancellationToken ); _ = await Assert.That(fixedSource).Contains("ArgumentNullException.ThrowIfNull(argument);"); @@ -948,8 +1207,12 @@ void M(string? argument) } [Test] - public async Task CodeFix_WhenSourceHasOnlyAliasedSystemUsing_AddsRealUsingSystemDirective() + public async Task CodeFix_WhenSourceHasOnlyAliasedSystemUsing_AddsRealUsingSystemDirective( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using SysArg = System; @@ -965,7 +1228,8 @@ void M(string? argument) var fixedSource = await AnalyzerVerifier.ApplyFixAsync( new ThrowIfNullAnalyzer(), new ThrowIfNullCodeFixProvider(), - source + source, + cancellationToken: cancellationToken ); _ = await Assert.That(fixedSource).Contains("using SysArg = System;"); @@ -974,8 +1238,12 @@ void M(string? argument) } [Test] - public async Task CodeFix_WhenFixAllAppliedAcrossTwoMatchedSites_ReplacesBothWithThrowIfNullCalls() + public async Task CodeFix_WhenFixAllAppliedAcrossTwoMatchedSites_ReplacesBothWithThrowIfNullCalls( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -989,14 +1257,19 @@ void M(string? first, string? second) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfNullAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfNullAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).Count().IsEqualTo(2); var fixedSource = await AnalyzerVerifier.ApplyFixAllAsync( new ThrowIfNullAnalyzer(), new ThrowIfNullCodeFixProvider(), - source + source, + cancellationToken: cancellationToken ); const string expected = """ diff --git a/tests/NetEvolve.Arguments.Analyser.Tests.Unit/ThrowIfNullOrEmptyAnalyzerTests.cs b/tests/NetEvolve.Arguments.Analyser.Tests.Unit/ThrowIfNullOrEmptyAnalyzerTests.cs index a992471..03cd59b 100644 --- a/tests/NetEvolve.Arguments.Analyser.Tests.Unit/ThrowIfNullOrEmptyAnalyzerTests.cs +++ b/tests/NetEvolve.Arguments.Analyser.Tests.Unit/ThrowIfNullOrEmptyAnalyzerTests.cs @@ -12,8 +12,12 @@ namespace NetEvolve.Arguments.Analyser.Tests.Unit; public sealed class ThrowIfNullOrEmptyAnalyzerTests { [Test] - public async Task Analyze_WhenIsNullOrEmptyCheckThrowsArgumentException_ReportsDiagnostic() + public async Task Analyze_WhenIsNullOrEmptyCheckThrowsArgumentException_ReportsDiagnostic( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -26,15 +30,23 @@ void M(string? argument) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfNullOrEmptyAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfNullOrEmptyAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).Count().IsEqualTo(1); _ = await Assert.That(diagnostics[0].Id).IsEqualTo("NEA0002"); } [Test] - public async Task Analyze_WhenIsNullOrWhiteSpaceCheckThrowsArgumentException_ReportsDiagnostic() + public async Task Analyze_WhenIsNullOrWhiteSpaceCheckThrowsArgumentException_ReportsDiagnostic( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -47,14 +59,22 @@ void M(string? argument) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfNullOrEmptyAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfNullOrEmptyAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).Count().IsEqualTo(1); } [Test] - public async Task Analyze_WhenParamNameArgumentNamesADifferentParameter_DoesNotReportDiagnostic() + public async Task Analyze_WhenParamNameArgumentNamesADifferentParameter_DoesNotReportDiagnostic( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -67,14 +87,22 @@ void M(string? first, string? second) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfNullOrEmptyAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfNullOrEmptyAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).IsEmpty(); } [Test] - public async Task Analyze_WhenExceptionHasNonEmptyMessage_DoesNotReportDiagnostic() + public async Task Analyze_WhenExceptionHasNonEmptyMessage_DoesNotReportDiagnostic( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -87,14 +115,21 @@ void M(string? argument) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfNullOrEmptyAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfNullOrEmptyAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).IsEmpty(); } [Test] - public async Task Analyze_WhenIsNullOrEmptyCheckThrowsArgumentNullException_ReportsDiagnostic() + public async Task Analyze_WhenIsNullOrEmptyCheckThrowsArgumentNullException_ReportsDiagnostic( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); // Throwing ArgumentNullException for an IsNullOrEmpty/IsNullOrWhiteSpace check is itself a bug for the // whitespace-only/empty-but-non-null case; the same throw-helper fix corrects the wrong exception type too. const string source = """ @@ -109,15 +144,23 @@ void M(string? argument) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfNullOrEmptyAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfNullOrEmptyAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).Count().IsEqualTo(1); _ = await Assert.That(diagnostics[0].Id).IsEqualTo("NEA0002"); } [Test] - public async Task Analyze_WhenIsNullOrWhiteSpaceCheckThrowsArgumentNullException_ReportsDiagnostic() + public async Task Analyze_WhenIsNullOrWhiteSpaceCheckThrowsArgumentNullException_ReportsDiagnostic( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -130,14 +173,22 @@ void M(string? argument) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfNullOrEmptyAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfNullOrEmptyAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).Count().IsEqualTo(1); } [Test] - public async Task CodeFix_WhenAppliedToIsNullOrWhiteSpaceThrowingArgumentNullException_ReplacesWithThrowIfNullOrWhiteSpaceCall() + public async Task CodeFix_WhenAppliedToIsNullOrWhiteSpaceThrowingArgumentNullException_ReplacesWithThrowIfNullOrWhiteSpaceCall( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -153,7 +204,8 @@ void M(string? argument) var fixedSource = await AnalyzerVerifier.ApplyFixAsync( new ThrowIfNullOrEmptyAnalyzer(), new ThrowIfNullOrEmptyCodeFixProvider(), - source + source, + cancellationToken: cancellationToken ); const string expected = """ @@ -172,8 +224,12 @@ void M(string? argument) } [Test] - public async Task Analyze_WhenBuiltInThrowIfNullOrEmptyAvailable_DoesNotReportDiagnostic() + public async Task Analyze_WhenBuiltInThrowIfNullOrEmptyAvailable_DoesNotReportDiagnostic( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -189,15 +245,19 @@ void M(string? argument) var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( new ThrowIfNullOrEmptyAnalyzer(), source, - useLegacyReferences: false + useLegacyReferences: false, + cancellationToken: cancellationToken ); _ = await Assert.That(diagnostics).IsEmpty(); } [Test] - public async Task Analyze_WhenOnlyThrowIfNullOrEmptyIsBuiltIn_StillReportsDiagnosticForIsNullOrWhiteSpace() + public async Task Analyze_WhenOnlyThrowIfNullOrEmptyIsBuiltIn_StillReportsDiagnosticForIsNullOrWhiteSpace( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); // Simulates net7.0's System.Runtime shape, where ArgumentException.ThrowIfNullOrEmpty already exists // but ArgumentException.ThrowIfNullOrWhiteSpace does not (it arrived only in .NET 8). Gating the whole // rule on a single probe for "ThrowIfNullOrEmpty" would wrongly suppress this IsNullOrWhiteSpace case, @@ -214,15 +274,21 @@ void M(string? argument) } """; - var diagnostics = await GetDiagnosticsWithOnlyThrowIfNullOrEmptyBuiltInAsync(source); + var diagnostics = await GetDiagnosticsWithOnlyThrowIfNullOrEmptyBuiltInAsync( + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).Count().IsEqualTo(1); _ = await Assert.That(diagnostics[0].Id).IsEqualTo("NEA0002"); } [Test] - public async Task Analyze_WhenOnlyThrowIfNullOrEmptyIsBuiltIn_DoesNotReportDiagnosticForIsNullOrEmpty() + public async Task Analyze_WhenOnlyThrowIfNullOrEmptyIsBuiltIn_DoesNotReportDiagnosticForIsNullOrEmpty( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); // Same simulated net7.0 shape as above, but for the branch whose built-in helper already exists: // that branch must stay suppressed to avoid duplicating the built-in CA1511 analyzer. const string source = """ @@ -237,7 +303,10 @@ void M(string? argument) } """; - var diagnostics = await GetDiagnosticsWithOnlyThrowIfNullOrEmptyBuiltInAsync(source); + var diagnostics = await GetDiagnosticsWithOnlyThrowIfNullOrEmptyBuiltInAsync( + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).IsEmpty(); } @@ -248,11 +317,15 @@ void M(string? argument) /// 's two reference sets (all built-ins present, or none) can represent. /// /// The C# source to analyze. + /// A token to monitor for cancellation requests. /// The diagnostics reports for . private static async Task> GetDiagnosticsWithOnlyThrowIfNullOrEmptyBuiltInAsync( - string source + string source, + CancellationToken cancellationToken = default ) { + cancellationToken.ThrowIfCancellationRequested(); + const string stubBclSource = """ namespace System { @@ -320,8 +393,8 @@ public class RuntimeCompatibilityAttribute : System.Attribute "TestAssembly", new[] { - CSharpSyntaxTree.ParseText(stubBclSource, parseOptions), - CSharpSyntaxTree.ParseText(source, parseOptions), + CSharpSyntaxTree.ParseText(stubBclSource, parseOptions, cancellationToken: cancellationToken), + CSharpSyntaxTree.ParseText(source, parseOptions, cancellationToken: cancellationToken), }, Array.Empty(), new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary) @@ -330,7 +403,7 @@ public class RuntimeCompatibilityAttribute : System.Attribute // Guard against the stub BCL silently failing to bind (e.g. a missing well-known type), which would // make the "no diagnostic" assertions in the calling tests pass for the wrong reason. var compilationErrors = compilation - .GetDiagnostics() + .GetDiagnostics(cancellationToken: cancellationToken) .Where(diagnostic => diagnostic.Severity == DiagnosticSeverity.Error) .ToImmutableArray(); @@ -349,8 +422,10 @@ public class RuntimeCompatibilityAttribute : System.Attribute } [Test] - public async Task Analyze_WhenIfHasElseClause_DoesNotReportDiagnostic() + public async Task Analyze_WhenIfHasElseClause_DoesNotReportDiagnostic(CancellationToken cancellationToken = default) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -369,14 +444,22 @@ void M(string? argument) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfNullOrEmptyAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfNullOrEmptyAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).IsEmpty(); } [Test] - public async Task Analyze_WhenMethodIsNotRecognized_DoesNotReportDiagnostic() + public async Task Analyze_WhenMethodIsNotRecognized_DoesNotReportDiagnostic( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -389,14 +472,22 @@ void M(string? argument) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfNullOrEmptyAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfNullOrEmptyAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).IsEmpty(); } [Test] - public async Task Analyze_WhenQualifierIsNotString_DoesNotReportDiagnostic() + public async Task Analyze_WhenQualifierIsNotString_DoesNotReportDiagnostic( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -414,14 +505,22 @@ void M(string? argument) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfNullOrEmptyAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfNullOrEmptyAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).IsEmpty(); } [Test] - public async Task Analyze_WhenQualifiedAsSystemString_ReportsDiagnostic() + public async Task Analyze_WhenQualifiedAsSystemString_ReportsDiagnostic( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -434,14 +533,22 @@ void M(string? argument) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfNullOrEmptyAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfNullOrEmptyAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).Count().IsEqualTo(1); } [Test] - public async Task CodeFix_WhenAppliedToIsNullOrEmpty_ReplacesWithThrowIfNullOrEmptyCall() + public async Task CodeFix_WhenAppliedToIsNullOrEmpty_ReplacesWithThrowIfNullOrEmptyCall( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -457,7 +564,8 @@ void M(string? argument) var fixedSource = await AnalyzerVerifier.ApplyFixAsync( new ThrowIfNullOrEmptyAnalyzer(), new ThrowIfNullOrEmptyCodeFixProvider(), - source + source, + cancellationToken: cancellationToken ); const string expected = """ @@ -476,8 +584,12 @@ void M(string? argument) } [Test] - public async Task CodeFix_WhenAppliedToIsNullOrWhiteSpace_ReplacesWithThrowIfNullOrWhiteSpaceCall() + public async Task CodeFix_WhenAppliedToIsNullOrWhiteSpace_ReplacesWithThrowIfNullOrWhiteSpaceCall( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -493,7 +605,8 @@ void M(string? argument) var fixedSource = await AnalyzerVerifier.ApplyFixAsync( new ThrowIfNullOrEmptyAnalyzer(), new ThrowIfNullOrEmptyCodeFixProvider(), - source + source, + cancellationToken: cancellationToken ); const string expected = """ diff --git a/tests/NetEvolve.Arguments.Analyser.Tests.Unit/ThrowIfOutOfRangeAnalyzerTests.cs b/tests/NetEvolve.Arguments.Analyser.Tests.Unit/ThrowIfOutOfRangeAnalyzerTests.cs index dc20277..95d2ca5 100644 --- a/tests/NetEvolve.Arguments.Analyser.Tests.Unit/ThrowIfOutOfRangeAnalyzerTests.cs +++ b/tests/NetEvolve.Arguments.Analyser.Tests.Unit/ThrowIfOutOfRangeAnalyzerTests.cs @@ -1,5 +1,7 @@ namespace NetEvolve.Arguments.Analyser.Tests.Unit; +using System.Threading; + public sealed class ThrowIfOutOfRangeAnalyzerTests { [Test] @@ -14,9 +16,12 @@ public sealed class ThrowIfOutOfRangeAnalyzerTests [Arguments("argument != 42", "ThrowIfNotEqual(argument, 42);")] public async Task Analyze_WhenComparisonThrowsArgumentOutOfRangeException_ReportsDiagnosticAndFixes( string condition, - string expectedInvocation + string expectedInvocation, + CancellationToken cancellationToken = default ) { + cancellationToken.ThrowIfCancellationRequested(); + var source = $$""" using System; @@ -29,7 +34,11 @@ void M(int argument) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfOutOfRangeAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfOutOfRangeAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).Count().IsEqualTo(1); _ = await Assert.That(diagnostics[0].Id).IsEqualTo("NEA0003"); @@ -37,7 +46,8 @@ void M(int argument) var fixedSource = await AnalyzerVerifier.ApplyFixAsync( new ThrowIfOutOfRangeAnalyzer(), new ThrowIfOutOfRangeCodeFixProvider(), - source + source, + cancellationToken: cancellationToken ); var expected = $$""" @@ -56,8 +66,12 @@ void M(int argument) } [Test] - public async Task Analyze_WhenBoundIsNotALiteral_ReportsDiagnosticAndFixes() + public async Task Analyze_WhenBoundIsNotALiteral_ReportsDiagnosticAndFixes( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -70,14 +84,19 @@ void M(int argument, int other) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfOutOfRangeAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfOutOfRangeAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).Count().IsEqualTo(1); var fixedSource = await AnalyzerVerifier.ApplyFixAsync( new ThrowIfOutOfRangeAnalyzer(), new ThrowIfOutOfRangeCodeFixProvider(), - source + source, + cancellationToken: cancellationToken ); const string expected = """ @@ -96,8 +115,12 @@ void M(int argument, int other) } [Test] - public async Task Analyze_WhenValueOperandIsLiteral_DoesNotReportDiagnostic() + public async Task Analyze_WhenValueOperandIsLiteral_DoesNotReportDiagnostic( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -110,14 +133,22 @@ void M(int argument) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfOutOfRangeAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfOutOfRangeAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).IsEmpty(); } [Test] - public async Task Analyze_WhenThrowingArgumentException_DoesNotReportDiagnostic() + public async Task Analyze_WhenThrowingArgumentException_DoesNotReportDiagnostic( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -130,14 +161,22 @@ void M(int argument) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfOutOfRangeAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfOutOfRangeAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).IsEmpty(); } [Test] - public async Task Analyze_WhenBuiltInThrowIfNegativeAvailable_DoesNotReportDiagnostic() + public async Task Analyze_WhenBuiltInThrowIfNegativeAvailable_DoesNotReportDiagnostic( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -153,15 +192,20 @@ void M(int argument) var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( new ThrowIfOutOfRangeAnalyzer(), source, - useLegacyReferences: false + useLegacyReferences: false, + cancellationToken: cancellationToken ); _ = await Assert.That(diagnostics).IsEmpty(); } [Test] - public async Task Analyze_WhenCombinedRangeThrowsArgumentOutOfRangeException_ReportsDiagnosticAndFixes() + public async Task Analyze_WhenCombinedRangeThrowsArgumentOutOfRangeException_ReportsDiagnosticAndFixes( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -174,7 +218,11 @@ void M(int argument) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfOutOfRangeAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfOutOfRangeAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).Count().IsEqualTo(1); _ = await Assert.That(diagnostics[0].Id).IsEqualTo("NEA0003"); @@ -182,7 +230,8 @@ void M(int argument) var fixedSource = await AnalyzerVerifier.ApplyFixAsync( new ThrowIfOutOfRangeAnalyzer(), new ThrowIfOutOfRangeCodeFixProvider(), - source + source, + cancellationToken: cancellationToken ); const string expected = """ @@ -201,8 +250,12 @@ void M(int argument) } [Test] - public async Task Analyze_WhenCombinedRangeOperandIsDouble_DoesNotReportDiagnostic() + public async Task Analyze_WhenCombinedRangeOperandIsDouble_DoesNotReportDiagnostic( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -215,7 +268,11 @@ void M(double argument) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfOutOfRangeAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfOutOfRangeAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).IsEmpty(); } @@ -225,8 +282,13 @@ void M(double argument) [Arguments("argument <= 42")] [Arguments("argument > 42")] [Arguments("argument >= 42")] - public async Task Analyze_WhenRelationalOperandIsFloat_DoesNotReportDiagnostic(string condition) + public async Task Analyze_WhenRelationalOperandIsFloat_DoesNotReportDiagnostic( + string condition, + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + var source = $$""" using System; @@ -239,14 +301,22 @@ void M(float argument) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfOutOfRangeAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfOutOfRangeAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).IsEmpty(); } [Test] - public async Task Analyze_WhenEqualityOperandIsDouble_ReportsDiagnostic() + public async Task Analyze_WhenEqualityOperandIsDouble_ReportsDiagnostic( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -259,15 +329,21 @@ void M(double argument) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfOutOfRangeAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfOutOfRangeAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).Count().IsEqualTo(1); _ = await Assert.That(diagnostics[0].Id).IsEqualTo("NEA0003"); } [Test] - public async Task Analyze_WhenIfHasElseClause_DoesNotReportDiagnostic() + public async Task Analyze_WhenIfHasElseClause_DoesNotReportDiagnostic(CancellationToken cancellationToken = default) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -286,14 +362,22 @@ void M(int argument) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfOutOfRangeAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfOutOfRangeAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).IsEmpty(); } [Test] - public async Task Analyze_WhenExceptionHasTooManyArguments_DoesNotReportDiagnostic() + public async Task Analyze_WhenExceptionHasTooManyArguments_DoesNotReportDiagnostic( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -306,14 +390,22 @@ void M(int argument) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfOutOfRangeAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfOutOfRangeAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).IsEmpty(); } [Test] - public async Task Analyze_WhenCombinedRangeOperandIsInvocation_DoesNotReportDiagnostic() + public async Task Analyze_WhenCombinedRangeOperandIsInvocation_DoesNotReportDiagnostic( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -328,14 +420,21 @@ void M() } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfOutOfRangeAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfOutOfRangeAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).IsEmpty(); } [Test] - public async Task Analyze_WhenCombinedRangeMemberAccessOperandNamesRootParameter_DoesNotReportDiagnostic() + public async Task Analyze_WhenCombinedRangeMemberAccessOperandNamesRootParameter_DoesNotReportDiagnostic( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); // The compared operand is the member-access chain "argument.Length", but the constructor here names // only the root parameter ("argument"). Rewriting to the throw-helper would capture the whole chain // via [CallerArgumentExpression] and change the reported ParamName from "argument" to "argument.Length", @@ -352,14 +451,22 @@ void M(string argument) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfOutOfRangeAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfOutOfRangeAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).IsEmpty(); } [Test] - public async Task Analyze_WhenParamNameArgumentDoesNotMatchComparedValue_DoesNotReportDiagnostic() + public async Task Analyze_WhenParamNameArgumentDoesNotMatchComparedValue_DoesNotReportDiagnostic( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -372,14 +479,22 @@ void M(int argument, int other) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfOutOfRangeAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfOutOfRangeAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).IsEmpty(); } [Test] - public async Task Analyze_WhenExceptionArgumentIsUnrelatedToComparedValue_DoesNotReportDiagnostic() + public async Task Analyze_WhenExceptionArgumentIsUnrelatedToComparedValue_DoesNotReportDiagnostic( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -392,14 +507,22 @@ void M() } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfOutOfRangeAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfOutOfRangeAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).IsEmpty(); } [Test] - public async Task Analyze_WhenCombinedRangeOperandIsElementAccess_DoesNotReportDiagnostic() + public async Task Analyze_WhenCombinedRangeOperandIsElementAccess_DoesNotReportDiagnostic( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -412,14 +535,22 @@ void M(int[] items) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfOutOfRangeAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfOutOfRangeAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).IsEmpty(); } [Test] - public async Task Analyze_WhenExceptionHasActualValueAndMessage_DoesNotReportDiagnostic() + public async Task Analyze_WhenExceptionHasActualValueAndMessage_DoesNotReportDiagnostic( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -432,14 +563,22 @@ void M(int argument) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfOutOfRangeAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfOutOfRangeAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).IsEmpty(); } [Test] - public async Task Analyze_WhenCombinedRangeOperandIsMemberAccess_ReportsDiagnosticAndFixes() + public async Task Analyze_WhenCombinedRangeOperandIsMemberAccess_ReportsDiagnosticAndFixes( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -452,7 +591,11 @@ void M(string argument) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfOutOfRangeAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfOutOfRangeAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).Count().IsEqualTo(1); _ = await Assert.That(diagnostics[0].Id).IsEqualTo("NEA0003"); @@ -460,7 +603,8 @@ void M(string argument) var fixedSource = await AnalyzerVerifier.ApplyFixAsync( new ThrowIfOutOfRangeAnalyzer(), new ThrowIfOutOfRangeCodeFixProvider(), - source + source, + cancellationToken: cancellationToken ); _ = await Assert @@ -469,8 +613,12 @@ void M(string argument) } [Test] - public async Task Analyze_WhenExceptionHasNoArguments_ReportsDiagnostic() + public async Task Analyze_WhenExceptionHasNoArguments_ReportsDiagnostic( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -483,7 +631,11 @@ void M(int argument) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfOutOfRangeAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfOutOfRangeAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).Count().IsEqualTo(1); } @@ -495,9 +647,12 @@ void M(int argument) [Arguments("int argument", "argument == 5 || argument > 100")] public async Task Analyze_WhenConditionIsUnrecognizedShape_DoesNotReportDiagnostic( string parameters, - string condition + string condition, + CancellationToken cancellationToken = default ) { + cancellationToken.ThrowIfCancellationRequested(); + var source = $$""" using System; @@ -510,14 +665,22 @@ void M({{parameters}}) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfOutOfRangeAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfOutOfRangeAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).IsEmpty(); } [Test] - public async Task Analyze_WhenOperandIsEnumComparedForEquality_DoesNotReportDiagnostic() + public async Task Analyze_WhenOperandIsEnumComparedForEquality_DoesNotReportDiagnostic( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -535,14 +698,20 @@ void M(Kind argument) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfOutOfRangeAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfOutOfRangeAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).IsEmpty(); } [Test] - public async Task Analyze_WhenOperandIsObject_DoesNotReportDiagnostic() + public async Task Analyze_WhenOperandIsObject_DoesNotReportDiagnostic(CancellationToken cancellationToken = default) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -555,14 +724,22 @@ void M(object argument, object other) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfOutOfRangeAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfOutOfRangeAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).IsEmpty(); } [Test] - public async Task Analyze_WhenOperandTypeImplementsNeitherEquatableNorComparable_DoesNotReportDiagnostic() + public async Task Analyze_WhenOperandTypeImplementsNeitherEquatableNorComparable_DoesNotReportDiagnostic( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -579,14 +756,22 @@ void M(UnsupportedType argument, UnsupportedType other) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfOutOfRangeAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfOutOfRangeAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).IsEmpty(); } [Test] - public async Task Analyze_WhenOperandTypeIsUnresolvedErrorType_DoesNotReportDiagnostic() + public async Task Analyze_WhenOperandTypeIsUnresolvedErrorType_DoesNotReportDiagnostic( + CancellationToken cancellationToken = default + ) { + cancellationToken.ThrowIfCancellationRequested(); + const string source = """ using System; @@ -599,7 +784,11 @@ void M(Undeclared argument) } """; - var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync(new ThrowIfOutOfRangeAnalyzer(), source); + var diagnostics = await AnalyzerVerifier.GetDiagnosticsAsync( + new ThrowIfOutOfRangeAnalyzer(), + source, + cancellationToken: cancellationToken + ); _ = await Assert.That(diagnostics).IsEmpty(); } diff --git a/tests/NetEvolve.Arguments.Tests.Unit/ArgumentOutOfRangeExceptionPolyfillsTests.cs b/tests/NetEvolve.Arguments.Tests.Unit/ArgumentOutOfRangeExceptionPolyfillsTests.cs index 5e2664d..35e1c76 100644 --- a/tests/NetEvolve.Arguments.Tests.Unit/ArgumentOutOfRangeExceptionPolyfillsTests.cs +++ b/tests/NetEvolve.Arguments.Tests.Unit/ArgumentOutOfRangeExceptionPolyfillsTests.cs @@ -33,7 +33,7 @@ public async Task ThrowIfZero_Int_WhenValueIsNotZero_DoesNotThrow(int value) public void ThrowIfZero_Double_WhenValueIsZero_ThrowsArgumentOutOfRangeException() { // Arrange - var value = 0.0; + var value = 0.0D; // Act void Act() => ArgumentOutOfRangeException.ThrowIfZero(value); @@ -44,12 +44,12 @@ public void ThrowIfZero_Double_WhenValueIsZero_ThrowsArgumentOutOfRangeException [Test] [Arguments(1.5)] - [Arguments(-1.5)] + [Arguments(-1.5D)] public async Task ThrowIfZero_Double_WhenValueIsNotZero_DoesNotThrow(double value) { // Act & Assert ArgumentOutOfRangeException.ThrowIfZero(value); - _ = await Assert.That(value).IsNotEqualTo(0.0); + _ = await Assert.That(value).IsNotEqualTo(0.0D); } [Test] @@ -80,7 +80,7 @@ public async Task ThrowIfNegative_Int_WhenValueIsNonNegative_DoesNotThrow(int va public void ThrowIfNegative_Double_WhenValueIsNegative_ThrowsArgumentOutOfRangeException() { // Arrange - var value = -1.5; + var value = -1.5D; // Act void Act() => ArgumentOutOfRangeException.ThrowIfNegative(value); @@ -96,7 +96,7 @@ public async Task ThrowIfNegative_Double_WhenValueIsNonNegative_DoesNotThrow(dou { // Act & Assert ArgumentOutOfRangeException.ThrowIfNegative(value); - _ = await Assert.That(value).IsGreaterThanOrEqualTo(0.0); + _ = await Assert.That(value).IsGreaterThanOrEqualTo(0.0D); } [Test] @@ -149,7 +149,7 @@ public async Task ThrowIfNegativeOrZero_Int_WhenValueIsPositive_DoesNotThrow(int public void ThrowIfNegativeOrZero_Double_WhenValueIsZero_ThrowsArgumentOutOfRangeException() { // Arrange - var value = 0.0; + var value = 0.0D; // Act void Act() => ArgumentOutOfRangeException.ThrowIfNegativeOrZero(value); @@ -162,7 +162,7 @@ public void ThrowIfNegativeOrZero_Double_WhenValueIsZero_ThrowsArgumentOutOfRang public void ThrowIfNegativeOrZero_Double_WhenValueIsNegative_ThrowsArgumentOutOfRangeException() { // Arrange - var value = -1.5; + var value = -1.5D; // Act void Act() => ArgumentOutOfRangeException.ThrowIfNegativeOrZero(value); @@ -178,7 +178,7 @@ public async Task ThrowIfNegativeOrZero_Double_WhenValueIsPositive_DoesNotThrow( { // Act & Assert ArgumentOutOfRangeException.ThrowIfNegativeOrZero(value); - _ = await Assert.That(value).IsGreaterThan(0.0); + _ = await Assert.That(value).IsGreaterThan(0.0D); } [Test] diff --git a/tests/NetEvolve.Arguments.Tests.Unit/ArgumentOutOfRangeException_ThrowIfInFutureTests.cs b/tests/NetEvolve.Arguments.Tests.Unit/ArgumentOutOfRangeException_ThrowIfInFutureTests.cs index c053639..6f56e00 100644 --- a/tests/NetEvolve.Arguments.Tests.Unit/ArgumentOutOfRangeException_ThrowIfInFutureTests.cs +++ b/tests/NetEvolve.Arguments.Tests.Unit/ArgumentOutOfRangeException_ThrowIfInFutureTests.cs @@ -9,7 +9,7 @@ public sealed class ArgumentOutOfRangeException_ThrowIfInFutureTests public void ThrowIfInFuture_DateTimeOffset_WhenValueIsInFuture_ThrowsArgumentOutOfRangeException() { // Arrange - var argument = DateTimeOffset.UtcNow.AddHours(1); + var argument = DateTimeOffset.UtcNow.AddHours(1D); // Act void Act() => ArgumentOutOfRangeException.ThrowIfInFuture(argument); @@ -26,7 +26,7 @@ public async Task ThrowIfInFuture_DateTimeOffset_WhenValueIsNow_DoesNotThrow() // Act & Assert ArgumentOutOfRangeException.ThrowIfInFuture(argument); - _ = await Assert.That(argument).IsLessThanOrEqualTo(DateTimeOffset.UtcNow.AddSeconds(5)); + _ = await Assert.That(argument).IsLessThanOrEqualTo(DateTimeOffset.UtcNow.AddSeconds(5D)); } [Test] @@ -44,7 +44,7 @@ public async Task ThrowIfInFuture_DateTimeOffset_WhenValueIsInPast_DoesNotThrow( public void ThrowIfInFuture_DateTime_WhenValueIsInFuture_ThrowsArgumentOutOfRangeException() { // Arrange - var argument = DateTime.UtcNow.AddHours(1); + var argument = DateTime.UtcNow.AddHours(1D); // Act void Act() => ArgumentOutOfRangeException.ThrowIfInFuture(argument); @@ -68,7 +68,7 @@ public async Task ThrowIfInFuture_DateTime_WhenValueIsInPast_DoesNotThrow() public void ThrowIfInFuture_DateOnly_WhenValueIsInFuture_ThrowsArgumentOutOfRangeException() { // Arrange - var argument = DateOnly.FromDateTime(DateTime.UtcNow.AddDays(1)); + var argument = DateOnly.FromDateTime(DateTime.UtcNow.AddDays(1D)); // Act void Act() => ArgumentOutOfRangeException.ThrowIfInFuture(argument); @@ -85,7 +85,7 @@ public async Task ThrowIfInFuture_DateOnly_WhenValueIsToday_DoesNotThrow() // Act & Assert ArgumentOutOfRangeException.ThrowIfInFuture(argument); - _ = await Assert.That(argument).IsLessThanOrEqualTo(DateOnly.FromDateTime(DateTime.UtcNow.AddDays(1))); + _ = await Assert.That(argument).IsLessThanOrEqualTo(DateOnly.FromDateTime(DateTime.UtcNow.AddDays(1D))); } } #endif diff --git a/tests/NetEvolve.Arguments.Tests.Unit/ArgumentOutOfRangeException_ThrowIfInPastTests.cs b/tests/NetEvolve.Arguments.Tests.Unit/ArgumentOutOfRangeException_ThrowIfInPastTests.cs index ca970c2..6be6771 100644 --- a/tests/NetEvolve.Arguments.Tests.Unit/ArgumentOutOfRangeException_ThrowIfInPastTests.cs +++ b/tests/NetEvolve.Arguments.Tests.Unit/ArgumentOutOfRangeException_ThrowIfInPastTests.cs @@ -22,7 +22,7 @@ public void ThrowIfInPast_DateTimeOffset_WhenValueIsInPast_ThrowsArgumentOutOfRa public async Task ThrowIfInPast_DateTimeOffset_WhenValueIsSlightlyInFuture_DoesNotThrow() { // Arrange - var argument = DateTimeOffset.UtcNow.AddSeconds(1); + var argument = DateTimeOffset.UtcNow.AddSeconds(1D); // Act & Assert ArgumentOutOfRangeException.ThrowIfInPast(argument); @@ -33,7 +33,7 @@ public async Task ThrowIfInPast_DateTimeOffset_WhenValueIsSlightlyInFuture_DoesN public async Task ThrowIfInPast_DateTimeOffset_WhenValueIsInFuture_DoesNotThrow() { // Arrange - var argument = DateTimeOffset.UtcNow.AddHours(1); + var argument = DateTimeOffset.UtcNow.AddHours(1D); // Act & Assert ArgumentOutOfRangeException.ThrowIfInPast(argument); @@ -57,7 +57,7 @@ public void ThrowIfInPast_DateTime_WhenValueIsInPast_ThrowsArgumentOutOfRangeExc public async Task ThrowIfInPast_DateTime_WhenValueIsInFuture_DoesNotThrow() { // Arrange - var argument = DateTime.UtcNow.AddHours(1); + var argument = DateTime.UtcNow.AddHours(1D); // Act & Assert ArgumentOutOfRangeException.ThrowIfInPast(argument); diff --git a/tests/NetEvolve.Arguments.Tests.Unit/ArgumentOutOfRangeException_ThrowIfOutOfRangeTests.cs b/tests/NetEvolve.Arguments.Tests.Unit/ArgumentOutOfRangeException_ThrowIfOutOfRangeTests.cs index 15e60f9..d6423d4 100644 --- a/tests/NetEvolve.Arguments.Tests.Unit/ArgumentOutOfRangeException_ThrowIfOutOfRangeTests.cs +++ b/tests/NetEvolve.Arguments.Tests.Unit/ArgumentOutOfRangeException_ThrowIfOutOfRangeTests.cs @@ -67,10 +67,10 @@ public async Task ThrowIfOutOfRange_WhenValueWithinRange_DoesNotThrow() public async Task ThrowIfOutOfRange_WithDoubles_WhenValueWithinRange_DoesNotThrow() { // Arrange - var argument = 7.5; + var argument = 7.5D; // Act & Assert - ArgumentOutOfRangeException.ThrowIfOutOfRange(argument, 5.0, 10.0); - _ = await Assert.That(argument).IsGreaterThanOrEqualTo(5.0).And.IsLessThanOrEqualTo(10.0); + ArgumentOutOfRangeException.ThrowIfOutOfRange(argument, 5.0D, 10.0D); + _ = await Assert.That(argument).IsGreaterThanOrEqualTo(5.0D).And.IsLessThanOrEqualTo(10.0D); } } diff --git a/tests/NetEvolve.Arguments.Tests.Unit/ArgumentTests_ThrowIfNullOrWhiteSpace.cs b/tests/NetEvolve.Arguments.Tests.Unit/ArgumentTests.cs similarity index 100% rename from tests/NetEvolve.Arguments.Tests.Unit/ArgumentTests_ThrowIfNullOrWhiteSpace.cs rename to tests/NetEvolve.Arguments.Tests.Unit/ArgumentTests.cs diff --git a/tests/NetEvolve.Arguments.Tests.Unit/ArgumentTests_ThrowIfEqual.cs b/tests/NetEvolve.Arguments.Tests.Unit/ArgumentTests_ThrowIfEqual.cs deleted file mode 100644 index 27ca09a..0000000 --- a/tests/NetEvolve.Arguments.Tests.Unit/ArgumentTests_ThrowIfEqual.cs +++ /dev/null @@ -1,34 +0,0 @@ -namespace NetEvolve.Arguments.Tests.Unit; - -using System; -using System.Threading.Tasks; - -public sealed partial class ArgumentTests -{ - [Test] - public void ThrowIfEqual_WhenArgumentIsEqualToMaximum_ThrowsArgumentOutOfRangeException() - { - // Arrange - var argument = 1; - var maximum = 1; - - // Act - void Act() => Argument.ThrowIfEqual(argument, maximum); - - // Assert - _ = Assert.Throws("argument", Act); - } - - [Test] - public async Task ThrowIfEqual_WhenArgumentIsNotEqualToMaximum_ReturnsArgument() - { - // Arrange - var argument = 2; - var maximum = 1; - - // Act - Argument.ThrowIfEqual(argument, maximum); - - _ = await Assert.That(maximum).IsEqualTo(1); - } -} diff --git a/tests/NetEvolve.Arguments.Tests.Unit/ArgumentTests_ThrowIfGreaterThan.cs b/tests/NetEvolve.Arguments.Tests.Unit/ArgumentTests_ThrowIfGreaterThan.cs deleted file mode 100644 index b6963e4..0000000 --- a/tests/NetEvolve.Arguments.Tests.Unit/ArgumentTests_ThrowIfGreaterThan.cs +++ /dev/null @@ -1,35 +0,0 @@ -namespace NetEvolve.Arguments.Tests.Unit; - -using System; -using System.Threading.Tasks; - -public sealed partial class ArgumentTests -{ - [Test] - public void ThrowIfGreaterThan_WhenArgumentIsGreaterThanMaximum_ThrowsArgumentOutOfRangeException() - { - // Arrange - var argument = 2; - var maximum = 1; - - // Act - void Act() => Argument.ThrowIfGreaterThan(argument, maximum); - - // Assert - _ = Assert.Throws("argument", Act); - } - - [Test] - public async Task ThrowIfGreaterThan_WhenArgumentIsEqualToMaximum_ReturnsArgument() - { - // Arrange - var argument = 1; - var maximum = 1; - - // Act - Argument.ThrowIfGreaterThan(argument, maximum); - - // Assert - _ = await Assert.That(maximum).IsEqualTo(1); - } -} diff --git a/tests/NetEvolve.Arguments.Tests.Unit/ArgumentTests_ThrowIfGreaterThanOrEqual.cs b/tests/NetEvolve.Arguments.Tests.Unit/ArgumentTests_ThrowIfGreaterThanOrEqual.cs deleted file mode 100644 index c02c438..0000000 --- a/tests/NetEvolve.Arguments.Tests.Unit/ArgumentTests_ThrowIfGreaterThanOrEqual.cs +++ /dev/null @@ -1,48 +0,0 @@ -namespace NetEvolve.Arguments.Tests.Unit; - -using System; - -public sealed partial class ArgumentTests -{ - [Test] - public void ThrowIfGreaterThanOrEqual_WhenArgumentIsGreaterThanOrEqualToMaximum_ThrowsArgumentOutOfRangeException() - { - // Arrange - var argument = 2; - var maximum = 1; - - // Act - void Act() => Argument.ThrowIfGreaterThanOrEqual(argument, maximum); - - // Assert - _ = Assert.Throws("argument", Act); - } - - [Test] - public void ThrowIfGreaterThanOrEqual_WhenArgumentIsEqualToMaximum_ReturnsArgument() - { - // Arrange - var argument = 1; - var maximum = 1; - - // Act - void Act() => Argument.ThrowIfGreaterThanOrEqual(argument, maximum); - - // Assert - _ = Assert.Throws("argument", Act); - } - - [Test] - public async Task ThrowIfGreaterThanOrEqual_WhenArgumentIsLessThanMaximum_ReturnsArgument() - { - // Arrange - var argument = 0; - var maximum = 1; - - // Act - Argument.ThrowIfGreaterThanOrEqual(argument, maximum); - - // Assert - _ = await Assert.That(maximum).IsEqualTo(1); - } -} diff --git a/tests/NetEvolve.Arguments.Tests.Unit/ArgumentTests_ThrowIfLessThan.cs b/tests/NetEvolve.Arguments.Tests.Unit/ArgumentTests_ThrowIfLessThan.cs deleted file mode 100644 index a95f704..0000000 --- a/tests/NetEvolve.Arguments.Tests.Unit/ArgumentTests_ThrowIfLessThan.cs +++ /dev/null @@ -1,34 +0,0 @@ -namespace NetEvolve.Arguments.Tests.Unit; - -using System; - -public sealed partial class ArgumentTests -{ - [Test] - public void ThrowIfLessThan_WhenArgumentIsLessThanMinimum_ThrowsArgumentOutOfRangeException() - { - // Arrange - var argument = 0; - var minimum = 1; - - // Act - void Act() => Argument.ThrowIfLessThan(argument, minimum); - - // Assert - _ = Assert.Throws("argument", Act); - } - - [Test] - public async Task ThrowIfLessThan_WhenArgumentIsEqualToMinimum_ReturnsArgument() - { - // Arrange - var argument = 1; - var minimum = 1; - - // Act - Argument.ThrowIfLessThan(argument, minimum); - - // Assert - _ = await Assert.That(minimum).IsEqualTo(1); - } -} diff --git a/tests/NetEvolve.Arguments.Tests.Unit/ArgumentTests_ThrowIfLessThanOrEqual.cs b/tests/NetEvolve.Arguments.Tests.Unit/ArgumentTests_ThrowIfLessThanOrEqual.cs deleted file mode 100644 index eb2382c..0000000 --- a/tests/NetEvolve.Arguments.Tests.Unit/ArgumentTests_ThrowIfLessThanOrEqual.cs +++ /dev/null @@ -1,48 +0,0 @@ -namespace NetEvolve.Arguments.Tests.Unit; - -using System; - -public sealed partial class ArgumentTests -{ - [Test] - public void ThrowIfLessThanOrEqual_WhenArgumentIsLessThanMinimum_ThrowsArgumentOutOfRangeException() - { - // Arrange - var argument = 0; - var minimum = 1; - - // Act - void Act() => Argument.ThrowIfLessThanOrEqual(argument, minimum); - - // Assert - _ = Assert.Throws("argument", Act); - } - - [Test] - public void ThrowIfLessThanOrEqual_WhenArgumentIsEqualToMinimum_ReturnsArgument() - { - // Arrange - var argument = 1; - var minimum = 1; - - // Act - void Act() => Argument.ThrowIfLessThanOrEqual(argument, minimum); - - // Assert - _ = Assert.Throws("argument", Act); - } - - [Test] - public async Task ThrowIfLessThanOrEqual_WhenArgumentIsGreaterThanMinimum_ReturnsArgument() - { - // Arrange - var argument = 2; - var minimum = 1; - - // Act - Argument.ThrowIfLessThanOrEqual(argument, minimum); - - // Assert - _ = await Assert.That(minimum).IsEqualTo(1); - } -} diff --git a/tests/NetEvolve.Arguments.Tests.Unit/ArgumentTests_ThrowIfNotEqual.cs b/tests/NetEvolve.Arguments.Tests.Unit/ArgumentTests_ThrowIfNotEqual.cs deleted file mode 100644 index c30d221..0000000 --- a/tests/NetEvolve.Arguments.Tests.Unit/ArgumentTests_ThrowIfNotEqual.cs +++ /dev/null @@ -1,34 +0,0 @@ -namespace NetEvolve.Arguments.Tests.Unit; - -using System; - -public sealed partial class ArgumentTests -{ - [Test] - public void ThrowIfNotEqual_WhenArgumentIsNotEqualToMaximum_ThrowsArgumentOutOfRangeException() - { - // Arrange - var argument = 2; - var maximum = 1; - - // Act - void Act() => Argument.ThrowIfNotEqual(argument, maximum); - - // Assert - _ = Assert.Throws("argument", Act); - } - - [Test] - public async Task ThrowIfNotEqual_WhenArgumentIsEqualToMaximum_ReturnsArgument() - { - // Arrange - var argument = 1; - var maximum = 1; - - // Act - Argument.ThrowIfNotEqual(argument, maximum); - - // Assert - _ = await Assert.That(maximum).IsEqualTo(1); - } -} diff --git a/tests/NetEvolve.Arguments.Tests.Unit/ArgumentTests_ThrowIfNull.cs b/tests/NetEvolve.Arguments.Tests.Unit/ArgumentTests_ThrowIfNull.cs deleted file mode 100644 index 8dcf097..0000000 --- a/tests/NetEvolve.Arguments.Tests.Unit/ArgumentTests_ThrowIfNull.cs +++ /dev/null @@ -1,47 +0,0 @@ -namespace NetEvolve.Arguments.Tests.Unit; - -using System; - -public sealed partial class ArgumentTests -{ - [Test] - public void ThrowIfNull_WhenArgumentIsNull_ThrowsArgumentNullException() - { - // Arrange - string? argument = null; - - // Act - void Act() => Argument.ThrowIfNull(argument); - - // Assert - _ = Assert.Throws("argument", Act); - } - - [Test] - public async Task ThrowIfNull_WhenArgumentIsNotEmpty_ReturnsArgument() - { - // Arrange - var argument = "argument"; - - // Act - Argument.ThrowIfNull(argument); - - // Assert - _ = await Assert.That(argument).IsNotNullOrWhiteSpace(); - } - - [Test] -#pragma warning disable S6640 // Make sure that using "unsafe" is safe here. - public unsafe void ThrowIfNull_WhenArgumentIsNullPointer_ThrowsArgumentNullException() -#pragma warning restore S6640 // Make sure that using "unsafe" is safe here. - { - // Arrange - int* argument = null; - - // Act - void Act() => Argument.ThrowIfNull(argument); - - // Assert - _ = Assert.Throws("argument", Act); - } -} diff --git a/tests/NetEvolve.Arguments.Tests.Unit/ArgumentTests_ThrowIfNullOrEmpty.cs b/tests/NetEvolve.Arguments.Tests.Unit/ArgumentTests_ThrowIfNullOrEmpty.cs deleted file mode 100644 index acfff47..0000000 --- a/tests/NetEvolve.Arguments.Tests.Unit/ArgumentTests_ThrowIfNullOrEmpty.cs +++ /dev/null @@ -1,89 +0,0 @@ -namespace NetEvolve.Arguments.Tests.Unit; - -using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using TUnit.Assertions.Extensions; - -public sealed partial class ArgumentTests -{ - [Test] - public void ThrowIfNullOrEmpty_WhenArgumentIsNull_ThrowsArgumentNullException() - { - // Arrange - string? argument = null; - - // Act - void Act() => Argument.ThrowIfNullOrEmpty(argument); - - // Assert - _ = Assert.Throws("argument", Act); - } - - [Test] - public void ThrowIfNullOrEmpty_WhenArgumentIsEmpty_ThrowsArgumentException() - { - // Arrange - var argument = string.Empty; - - // Act - void Act() => Argument.ThrowIfNullOrEmpty(argument); - - // Assert - _ = Assert.Throws("argument", Act); - } - - [Test] - public async Task ThrowIfNullOrEmpty_WhenArgumentIsNotEmpty_ReturnsArgument() - { - // Arrange - var argument = "argument"; - - // Act - Argument.ThrowIfNullOrEmpty(argument); - - // Assert - _ = await Assert.That(argument).IsNotNullOrWhiteSpace(); - } - - [Test] - public void ThrowIfNullOrEmpty_WhenIEnumerableNull_ThrowsArgumentNullException() - { - // Arrange - IEnumerable? argument = null; - - // Act - void Act() => Argument.ThrowIfNullOrEmpty(argument); - - // Assert - _ = Assert.Throws(nameof(argument), Act); - } - - [Test] - [MethodDataSource(nameof(ThrowIfNullOrEmptyEnumerableData))] - public void ThrowIfNullOrEmpty_WhenIEnumerableEmpty_ThrowsArgumentException(IEnumerable? argument) - { - // Act - void Act() => Argument.ThrowIfNullOrEmpty(argument); - - // Assert - _ = Assert.Throws(nameof(argument), Act); - } - - [Test] - [MethodDataSource(nameof(ThrowIfNullOrEmptyEnumerableWithData))] - public async Task ThrowIfNullOrEmpty_WhenIEnumerableEmpty_Expected(IEnumerable? argument) - { - // Act - Argument.ThrowIfNullOrEmpty(argument); - - // Assert - _ = await Assert.That(argument).IsNotNull().And.IsNotEmpty(); - } - - public static IEnumerable> ThrowIfNullOrEmptyEnumerableData => - [Array.Empty(), new List(), new HashSet()]; - - public static IEnumerable> ThrowIfNullOrEmptyEnumerableWithData => - [new[] { "argument" }, new List { "argument" }, new HashSet { "argument" }]; -}