From 6d23f749c49d7437b109f6e8d0b3ebc0aadd7efd Mon Sep 17 00:00:00 2001 From: Jihoon Park Date: Tue, 4 Jun 2024 22:06:48 -0400 Subject: [PATCH] Fix #713: Make best attempt at fixing trivia --- ...qualClassicModelAssertUsageCodeFixTests.cs | 46 +++++- ...qualClassicModelAssertUsageCodeFixTests.cs | 42 ++++++ ...SameClassicModelAssertUsageCodeFixTests.cs | 62 ++++++++ ...SameClassicModelAssertUsageCodeFixTests.cs | 64 ++++++++ ...ainsClassicModelAssertUsageCodeFixTests.cs | 62 ++++++++ ...aterClassicModelAssertUsageCodeFixTests.cs | 50 +++++++ ...qualClassicModelAssertUsageCodeFixTests.cs | 50 +++++++ ...mptyClassicModelAssertUsageCodeFixTests.cs | 56 +++++++ ...alseClassicModelAssertUsageCodeFixTests.cs | 67 +++++++++ ...ceOfClassicModelAssertUsageCodeFixTests.cs | 114 +++++++++++++++ ...sNaNClassicModelAssertUsageCodeFixTests.cs | 56 +++++++ ...mptyClassicModelAssertUsageCodeFixTests.cs | 56 +++++++ ...ceOfClassicModelAssertUsageCodeFixTests.cs | 87 +++++++++++ ...NullClassicModelAssertUsageCodeFixTests.cs | 71 +++++++++ ...NullClassicModelAssertUsageCodeFixTests.cs | 71 +++++++++ ...TrueClassicModelAssertUsageCodeFixTests.cs | 67 +++++++++ ...icModelAssertUsageCondensedCodeFixTests.cs | 67 +++++++++ ...LessClassicModelAssertUsageCodeFixTests.cs | 50 +++++++ ...qualClassicModelAssertUsageCodeFixTests.cs | 50 +++++++ ...ZeroClassicModelAssertUsageCodeFixTests.cs | 56 +++++++ ...ZeroClassicModelAssertUsageCodeFixTests.cs | 56 +++++++ .../CollectionAssertUsageCodeFixTests.cs | 137 +++++++++++++++++- .../ComparisonConstraintUsageCodeFixTests.cs | 49 +++++++ .../EqualConstraintUsageCodeFixTests.cs | 43 +++++- .../SomeItemsConstraintUsageCodeFixTests.cs | 60 ++++++-- .../StringConstraintUsageCodeFixTests.cs | 33 +++++ .../AreEqualClassicModelAssertUsageCodeFix.cs | 4 +- ...eNotEqualClassicModelAssertUsageCodeFix.cs | 2 +- ...reNotSameClassicModelAssertUsageCodeFix.cs | 2 +- .../AreSameClassicModelAssertUsageCodeFix.cs | 2 +- .../ClassicModelAssertUsageCodeFix.cs | 7 + .../ContainsClassicModelAssertUsageCodeFix.cs | 2 +- .../GreaterClassicModelAssertUsageCodeFix.cs | 4 +- ...erOrEqualClassicModelAssertUsageCodeFix.cs | 4 +- .../IsEmptyClassicModelAssertUsageCodeFix.cs | 2 +- ...eAndFalseClassicModelAssertUsageCodeFix.cs | 8 +- ...nstanceOfClassicModelAssertUsageCodeFix.cs | 4 +- .../IsNaNClassicModelAssertUsageCodeFix.cs | 2 +- ...sNotEmptyClassicModelAssertUsageCodeFix.cs | 2 +- ...nstanceOfClassicModelAssertUsageCodeFix.cs | 4 +- ...ndNotNullClassicModelAssertUsageCodeFix.cs | 2 +- ...llAndNullClassicModelAssertUsageCodeFix.cs | 2 +- ...ueAndTrueClassicModelAssertUsageCodeFix.cs | 2 +- .../LessClassicModelAssertUsageCodeFix.cs | 4 +- ...ssOrEqualClassicModelAssertUsageCodeFix.cs | 4 +- .../NotZeroClassicModelAssertUsageCodeFix.cs | 2 +- .../ZeroClassicModelAssertUsageCodeFix.cs | 2 +- .../CollectionAssertUsageCodeFix.cs | 11 +- .../BaseConditionConstraintCodeFix.cs | 26 +++- .../EqualConstraintUsageCodeFix.cs | 5 +- .../SomeItemsConstraintUsageCodeFix.cs | 7 +- .../StringConstraintUsageCodeFix.cs | 5 +- .../ArgumentListSyntaxExtensions.cs | 46 +++++- 53 files changed, 1715 insertions(+), 74 deletions(-) diff --git a/src/nunit.analyzers.tests/ClassicModelAssertUsage/AreEqualClassicModelAssertUsageCodeFixTests.cs b/src/nunit.analyzers.tests/ClassicModelAssertUsage/AreEqualClassicModelAssertUsageCodeFixTests.cs index eea3bf9c..4e86d833 100644 --- a/src/nunit.analyzers.tests/ClassicModelAssertUsage/AreEqualClassicModelAssertUsageCodeFixTests.cs +++ b/src/nunit.analyzers.tests/ClassicModelAssertUsage/AreEqualClassicModelAssertUsageCodeFixTests.cs @@ -295,15 +295,45 @@ public void Test(object actual, object expected) } [Test] - public void CodeFixPreservesLineBreakBeforeMessage() - { - var code = TestUtility.WrapInTestMethod(@" - ClassicAssert.AreEqual(2d, 3d, 0.0000001d, - ""message"");"); + public void CodeFixMaintainsReasonableTriviaWithEndOfLineClosingParen([Values] bool hasMessage) + { + var commaAndMessage = hasMessage + ? @", + ""message""" + : string.Empty; + var code = TestUtility.WrapInTestMethod($@" + ↓ClassicAssert.AreEqual( + 2d, + 3d, + 0.0000001d{commaAndMessage});"); + + var fixedCode = TestUtility.WrapInTestMethod($@" + Assert.That( + 3d, + Is.EqualTo(2d).Within(0.0000001d){commaAndMessage});"); + + RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode, fixTitle: ClassicModelAssertUsageCodeFix.TransformToConstraintModelDescription); + } + + [Test] + public void CodeFixMaintainsReasonableTriviaWithNewLineClosingParen([Values] bool hasMessage) + { + var commaAndMessage = hasMessage + ? @", + ""message""" + : string.Empty; + var code = TestUtility.WrapInTestMethod($@" + ↓ClassicAssert.AreEqual( + 2d, + 3d, + 0.0000001d{commaAndMessage} + );"); - var fixedCode = TestUtility.WrapInTestMethod(@" - Assert.That(3d, Is.EqualTo(2d).Within(0.0000001d), - ""message"");"); + var fixedCode = TestUtility.WrapInTestMethod($@" + Assert.That( + 3d, + Is.EqualTo(2d).Within(0.0000001d){commaAndMessage} + );"); RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode, fixTitle: ClassicModelAssertUsageCodeFix.TransformToConstraintModelDescription); } diff --git a/src/nunit.analyzers.tests/ClassicModelAssertUsage/AreNotEqualClassicModelAssertUsageCodeFixTests.cs b/src/nunit.analyzers.tests/ClassicModelAssertUsage/AreNotEqualClassicModelAssertUsageCodeFixTests.cs index e49697fa..fc13672d 100644 --- a/src/nunit.analyzers.tests/ClassicModelAssertUsage/AreNotEqualClassicModelAssertUsageCodeFixTests.cs +++ b/src/nunit.analyzers.tests/ClassicModelAssertUsage/AreNotEqualClassicModelAssertUsageCodeFixTests.cs @@ -103,5 +103,47 @@ public void TestMethod() }"); RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode, fixTitle: ClassicModelAssertUsageCodeFix.TransformToConstraintModelDescription); } + + [Test] + public void CodeFixMaintainsReasonableTriviaWithEndOfLineClosingParen([Values] bool hasMessage) + { + var commaAndMessage = hasMessage + ? @", + ""message""" + : string.Empty; + var code = TestUtility.WrapInTestMethod($@" + ↓ClassicAssert.AreNotEqual( + 2d, + 3d{commaAndMessage});"); + + var fixedCode = TestUtility.WrapInTestMethod($@" + Assert.That( + 3d, + Is.Not.EqualTo(2d){commaAndMessage});"); + + RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode, fixTitle: ClassicModelAssertUsageCodeFix.TransformToConstraintModelDescription); + } + + [Test] + public void CodeFixMaintainsReasonableTriviaWithNewLineClosingParen([Values] bool hasMessage) + { + var commaAndMessage = hasMessage + ? @", + ""message""" + : string.Empty; + var code = TestUtility.WrapInTestMethod($@" + ↓ClassicAssert.AreNotEqual( + 2d, + 3d{commaAndMessage} + );"); + + var fixedCode = TestUtility.WrapInTestMethod($@" + Assert.That( + 3d, + Is.Not.EqualTo(2d){commaAndMessage} + );"); + + RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode, fixTitle: ClassicModelAssertUsageCodeFix.TransformToConstraintModelDescription); + } } } diff --git a/src/nunit.analyzers.tests/ClassicModelAssertUsage/AreNotSameClassicModelAssertUsageCodeFixTests.cs b/src/nunit.analyzers.tests/ClassicModelAssertUsage/AreNotSameClassicModelAssertUsageCodeFixTests.cs index 25e26060..945846ff 100644 --- a/src/nunit.analyzers.tests/ClassicModelAssertUsage/AreNotSameClassicModelAssertUsageCodeFixTests.cs +++ b/src/nunit.analyzers.tests/ClassicModelAssertUsage/AreNotSameClassicModelAssertUsageCodeFixTests.cs @@ -133,5 +133,67 @@ public void TestMethod() }"); RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode, fixTitle: ClassicModelAssertUsageCodeFix.TransformToConstraintModelDescription); } + + [Test] + public void CodeFixMaintainsReasonableTriviaWithEndOfLineClosingParen([Values] bool hasMessage) + { + var commaAndMessage = hasMessage + ? @", + ""message""" + : string.Empty; + var code = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + var expected = new object(); + var actual = new object(); + + ↓ClassicAssert.AreNotSame( + expected, + actual{commaAndMessage}); + }}"); + var fixedCode = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + var expected = new object(); + var actual = new object(); + + Assert.That( + actual, + Is.Not.SameAs(expected){commaAndMessage}); + }}"); + RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode, fixTitle: ClassicModelAssertUsageCodeFix.TransformToConstraintModelDescription); + } + + [Test] + public void CodeFixMaintainsReasonableTriviaWithNewLineClosingParen([Values] bool hasMessage) + { + var commaAndMessage = hasMessage + ? @", + ""message""" + : string.Empty; + var code = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + var expected = new object(); + var actual = new object(); + + ↓ClassicAssert.AreNotSame( + expected, + actual{commaAndMessage} + ); + }}"); + var fixedCode = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + var expected = new object(); + var actual = new object(); + + Assert.That( + actual, + Is.Not.SameAs(expected){commaAndMessage} + ); + }}"); + RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode, fixTitle: ClassicModelAssertUsageCodeFix.TransformToConstraintModelDescription); + } } } diff --git a/src/nunit.analyzers.tests/ClassicModelAssertUsage/AreSameClassicModelAssertUsageCodeFixTests.cs b/src/nunit.analyzers.tests/ClassicModelAssertUsage/AreSameClassicModelAssertUsageCodeFixTests.cs index ca0dc975..ec069870 100644 --- a/src/nunit.analyzers.tests/ClassicModelAssertUsage/AreSameClassicModelAssertUsageCodeFixTests.cs +++ b/src/nunit.analyzers.tests/ClassicModelAssertUsage/AreSameClassicModelAssertUsageCodeFixTests.cs @@ -133,5 +133,69 @@ public void TestMethod() }"); RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode, fixTitle: ClassicModelAssertUsageCodeFix.TransformToConstraintModelDescription); } + + [Test] + public void CodeFixMaintainsReasonableTriviaWithEndOfLineClosingParen([Values] bool hasMessage) + { + var commaAndMessage = hasMessage + ? @", + ""message""" + : string.Empty; + var code = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + var expected = new object(); + var actual = new object(); + + ↓ClassicAssert.AreSame( + expected, + actual{commaAndMessage}); + }}"); + var fixedCode = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + var expected = new object(); + var actual = new object(); + + Assert.That( + actual, + Is.SameAs(expected){commaAndMessage}); + }}"); + RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode, fixTitle: ClassicModelAssertUsageCodeFix.TransformToConstraintModelDescription); + } + + [Test] + public void CodeFixMaintainsReasonableTriviaWithNewLineClosingParen([Values] bool hasMessage) + { + var commaAndMessage = hasMessage + ? @", + ""message""" + : string.Empty; + var code = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + var expected = new object(); + var actual = new object(); + + ↓ClassicAssert.AreSame( + expected, + actual, + ""message"" + ); + }}"); + var fixedCode = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + var expected = new object(); + var actual = new object(); + + Assert.That( + actual, + Is.SameAs(expected), + ""message"" + ); + }}"); + RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode, fixTitle: ClassicModelAssertUsageCodeFix.TransformToConstraintModelDescription); + } } } diff --git a/src/nunit.analyzers.tests/ClassicModelAssertUsage/ContainsClassicModelAssertUsageCodeFixTests.cs b/src/nunit.analyzers.tests/ClassicModelAssertUsage/ContainsClassicModelAssertUsageCodeFixTests.cs index 2e137c37..acd1de81 100644 --- a/src/nunit.analyzers.tests/ClassicModelAssertUsage/ContainsClassicModelAssertUsageCodeFixTests.cs +++ b/src/nunit.analyzers.tests/ClassicModelAssertUsage/ContainsClassicModelAssertUsageCodeFixTests.cs @@ -133,5 +133,67 @@ public void TestMethod() }"); RoslynAssert.CodeFix(analyzer, fix, instanceDiagnostic, code, fixedCode, fixTitle: ClassicModelAssertUsageCodeFix.TransformToConstraintModelDescription); } + + [Test] + public void CodeFixMaintainsReasonableTriviaWithEndOfLineClosingParen([Values] bool hasMessage) + { + var commaAndMessage = hasMessage + ? @", + ""message""" + : string.Empty; + var code = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + var instance = new object(); + var collection = Array.Empty(); + + ↓ClassicAssert.Contains( + instance, + collection{commaAndMessage}); + }}"); + var fixedCode = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + var instance = new object(); + var collection = Array.Empty(); + + Assert.That( + collection, + Does.Contain(instance){commaAndMessage}); + }}"); + RoslynAssert.CodeFix(analyzer, fix, instanceDiagnostic, code, fixedCode, fixTitle: ClassicModelAssertUsageCodeFix.TransformToConstraintModelDescription); + } + + [Test] + public void CodeFixMaintainsReasonableTriviaWithNewLineClosingParen([Values] bool hasMessage) + { + var commaAndMessage = hasMessage + ? @", + ""message""" + : string.Empty; + var code = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + var instance = new object(); + var collection = Array.Empty(); + + ↓ClassicAssert.Contains( + instance, + collection{commaAndMessage} + ); + }}"); + var fixedCode = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + var instance = new object(); + var collection = Array.Empty(); + + Assert.That( + collection, + Does.Contain(instance){commaAndMessage} + ); + }}"); + RoslynAssert.CodeFix(analyzer, fix, instanceDiagnostic, code, fixedCode, fixTitle: ClassicModelAssertUsageCodeFix.TransformToConstraintModelDescription); + } } } diff --git a/src/nunit.analyzers.tests/ClassicModelAssertUsage/GreaterClassicModelAssertUsageCodeFixTests.cs b/src/nunit.analyzers.tests/ClassicModelAssertUsage/GreaterClassicModelAssertUsageCodeFixTests.cs index 13c4cb2d..a9761f2d 100644 --- a/src/nunit.analyzers.tests/ClassicModelAssertUsage/GreaterClassicModelAssertUsageCodeFixTests.cs +++ b/src/nunit.analyzers.tests/ClassicModelAssertUsage/GreaterClassicModelAssertUsageCodeFixTests.cs @@ -231,5 +231,55 @@ public void TestMethod() }"); RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode, fixTitle: ClassicModelAssertUsageCodeFix.TransformToConstraintModelDescription); } + + [Test] + public void CodeFixMaintainsReasonableTriviaWithEndOfLineClosingParen([Values] bool hasMessage) + { + var commaAndMessage = hasMessage + ? @", + ""message""" + : string.Empty; + var code = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + ↓ClassicAssert.Greater( + 2d, + 3d{commaAndMessage}); + }}"); + var fixedCode = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + Assert.That( + 2d, + Is.GreaterThan(3d){commaAndMessage}); + }}"); + RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode, fixTitle: ClassicModelAssertUsageCodeFix.TransformToConstraintModelDescription); + } + + [Test] + public void CodeFixMaintainsReasonableTriviaWithNewLineClosingParen([Values] bool hasMessage) + { + var commaAndMessage = hasMessage + ? @", + ""message""" + : string.Empty; + var code = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + ↓ClassicAssert.Greater( + 2d, + 3d{commaAndMessage} + ); + }}"); + var fixedCode = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + Assert.That( + 2d, + Is.GreaterThan(3d){commaAndMessage} + ); + }}"); + RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode, fixTitle: ClassicModelAssertUsageCodeFix.TransformToConstraintModelDescription); + } } } diff --git a/src/nunit.analyzers.tests/ClassicModelAssertUsage/GreaterOrEqualClassicModelAssertUsageCodeFixTests.cs b/src/nunit.analyzers.tests/ClassicModelAssertUsage/GreaterOrEqualClassicModelAssertUsageCodeFixTests.cs index b5823959..3afb230f 100644 --- a/src/nunit.analyzers.tests/ClassicModelAssertUsage/GreaterOrEqualClassicModelAssertUsageCodeFixTests.cs +++ b/src/nunit.analyzers.tests/ClassicModelAssertUsage/GreaterOrEqualClassicModelAssertUsageCodeFixTests.cs @@ -231,5 +231,55 @@ public void TestMethod() }"); RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode, fixTitle: ClassicModelAssertUsageCodeFix.TransformToConstraintModelDescription); } + + [Test] + public void CodeFixMaintainsReasonableTriviaWithEndOfLineClosingParen([Values] bool hasMessage) + { + var commaAndMessage = hasMessage + ? @", + ""message""" + : string.Empty; + var code = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + ↓ClassicAssert.GreaterOrEqual( + 2d, + 3d{commaAndMessage}); + }}"); + var fixedCode = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + Assert.That( + 2d, + Is.GreaterThanOrEqualTo(3d){commaAndMessage}); + }}"); + RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode, fixTitle: ClassicModelAssertUsageCodeFix.TransformToConstraintModelDescription); + } + + [Test] + public void CodeFixMaintainsReasonableTriviaWithNewLineClosingParen([Values] bool hasMessage) + { + var commaAndMessage = hasMessage + ? @", + ""message""" + : string.Empty; + var code = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + ↓ClassicAssert.GreaterOrEqual( + 2d, + 3d{commaAndMessage} + ); + }}"); + var fixedCode = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + Assert.That( + 2d, + Is.GreaterThanOrEqualTo(3d){commaAndMessage} + ); + }}"); + RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode, fixTitle: ClassicModelAssertUsageCodeFix.TransformToConstraintModelDescription); + } } } diff --git a/src/nunit.analyzers.tests/ClassicModelAssertUsage/IsEmptyClassicModelAssertUsageCodeFixTests.cs b/src/nunit.analyzers.tests/ClassicModelAssertUsage/IsEmptyClassicModelAssertUsageCodeFixTests.cs index 756b3b47..f81d3e72 100644 --- a/src/nunit.analyzers.tests/ClassicModelAssertUsage/IsEmptyClassicModelAssertUsageCodeFixTests.cs +++ b/src/nunit.analyzers.tests/ClassicModelAssertUsage/IsEmptyClassicModelAssertUsageCodeFixTests.cs @@ -159,5 +159,61 @@ public void TestMethod() }"); RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode, fixTitle: ClassicModelAssertUsageCodeFix.TransformToConstraintModelDescription); } + + [Test] + public void CodeFixMaintainsReasonableTriviaWithEndOfLineClosingParen([Values] bool hasMessage) + { + var commaAndMessage = hasMessage + ? @", + ""message""" + : string.Empty; + var code = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + var collection = Array.Empty(); + + ↓ClassicAssert.IsEmpty( + collection{commaAndMessage}); + }}"); + var fixedCode = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + var collection = Array.Empty(); + + Assert.That( + collection, + Is.Empty{commaAndMessage}); + }}"); + RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode, fixTitle: ClassicModelAssertUsageCodeFix.TransformToConstraintModelDescription); + } + + [Test] + public void CodeFixMaintainsReasonableTriviaWithNewLineClosingParen([Values] bool hasMessage) + { + var commaAndMessage = hasMessage + ? @", + ""message""" + : string.Empty; + var code = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + var collection = Array.Empty(); + + ↓ClassicAssert.IsEmpty( + collection{commaAndMessage} + ); + }}"); + var fixedCode = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + var collection = Array.Empty(); + + Assert.That( + collection, + Is.Empty{commaAndMessage} + ); + }}"); + RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode, fixTitle: ClassicModelAssertUsageCodeFix.TransformToConstraintModelDescription); + } } } diff --git a/src/nunit.analyzers.tests/ClassicModelAssertUsage/IsFalseAndFalseClassicModelAssertUsageCodeFixTests.cs b/src/nunit.analyzers.tests/ClassicModelAssertUsage/IsFalseAndFalseClassicModelAssertUsageCodeFixTests.cs index 65a03a34..63642ed6 100644 --- a/src/nunit.analyzers.tests/ClassicModelAssertUsage/IsFalseAndFalseClassicModelAssertUsageCodeFixTests.cs +++ b/src/nunit.analyzers.tests/ClassicModelAssertUsage/IsFalseAndFalseClassicModelAssertUsageCodeFixTests.cs @@ -1,9 +1,12 @@ +using System.Collections.Generic; +using System.Linq; using Gu.Roslyn.Asserts; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.Diagnostics; using NUnit.Analyzers.ClassicModelAssertUsage; using NUnit.Analyzers.Constants; using NUnit.Framework; +using NUnit.Framework.Legacy; namespace NUnit.Analyzers.Tests.ClassicModelAssertUsage { @@ -12,6 +15,12 @@ public sealed class IsFalseAndFalseClassicModelAssertUsageCodeFixTests { private static readonly DiagnosticAnalyzer analyzer = new ClassicModelAssertUsageAnalyzer(); private static readonly CodeFixProvider fix = new IsFalseAndFalseClassicModelAssertUsageCodeFix(); + private static readonly Dictionary diagnosticIdsToAssertions = new() + { + { AnalyzerIdentifiers.FalseUsage, nameof(ClassicAssert.False) }, + { AnalyzerIdentifiers.IsFalseUsage, nameof(ClassicAssert.IsFalse) }, + }; + private static readonly string[] diagnosticIds = diagnosticIdsToAssertions.Keys.ToArray(); [Test] public void VerifyGetFixableDiagnosticIds() @@ -155,5 +164,63 @@ public void TestMethod() }"); RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode, fixTitle: ClassicModelAssertUsageCodeFix.TransformToConstraintModelDescription); } + + [Test] + public void CodeFixMaintainsReasonableTriviaWithEndOfLineClosingParen( + [ValueSource(nameof(diagnosticIds))] string diagnosticId, + [Values] bool hasMessage) + { + var assertion = diagnosticIdsToAssertions[diagnosticId]; + var commaAndMessage = hasMessage + ? @", + ""message""" + : string.Empty; + var expectedDiagnostic = ExpectedDiagnostic.Create(diagnosticId); + + var code = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + ↓ClassicAssert.{assertion}( + false{commaAndMessage}); + }}"); + var fixedCode = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + Assert.That( + false, + Is.False{commaAndMessage}); + }}"); + RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode, fixTitle: ClassicModelAssertUsageCodeFix.TransformToConstraintModelDescription); + } + + [Test] + public void CodeFixMaintainsReasonableTriviaWithNewLineClosingParen( + [ValueSource(nameof(diagnosticIds))] string diagnosticId, + [Values] bool hasMessage) + { + var assertion = diagnosticIdsToAssertions[diagnosticId]; + var commaAndMessage = hasMessage + ? @", + ""message""" + : string.Empty; + var expectedDiagnostic = ExpectedDiagnostic.Create(diagnosticId); + + var code = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + ↓ClassicAssert.{assertion}( + false{commaAndMessage} + ); + }}"); + var fixedCode = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + Assert.That( + false, + Is.False{commaAndMessage} + ); + }}"); + RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode, fixTitle: ClassicModelAssertUsageCodeFix.TransformToConstraintModelDescription); + } } } diff --git a/src/nunit.analyzers.tests/ClassicModelAssertUsage/IsInstanceOfClassicModelAssertUsageCodeFixTests.cs b/src/nunit.analyzers.tests/ClassicModelAssertUsage/IsInstanceOfClassicModelAssertUsageCodeFixTests.cs index 9c26ada2..0a63d344 100644 --- a/src/nunit.analyzers.tests/ClassicModelAssertUsage/IsInstanceOfClassicModelAssertUsageCodeFixTests.cs +++ b/src/nunit.analyzers.tests/ClassicModelAssertUsage/IsInstanceOfClassicModelAssertUsageCodeFixTests.cs @@ -301,5 +301,119 @@ public void VerifyIsInstanceOfGenericFixWithMessageAndArrayParamsInNonstandardOr Assert.That(actual, Is.InstanceOf(), $""{""first""}, {""second""}"");"); RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode, fixTitle: ClassicModelAssertUsageCodeFix.TransformToConstraintModelDescription); } + + [Test] + public void CodeFixMaintainsReasonableTriviaWithEndOfLineClosingParen() + { + var code = TestUtility.WrapMethodInClassNamespaceAndAddUsings(@" + public void TestMethod() + { + var expected = typeof(int); + var actual = 42; + + ↓ClassicAssert.IsInstanceOf( + expected, + actual, + ""message""); + }"); + var fixedCode = TestUtility.WrapMethodInClassNamespaceAndAddUsings(@" + public void TestMethod() + { + var expected = typeof(int); + var actual = 42; + + Assert.That( + actual, + Is.InstanceOf(expected), + ""message""); + }"); + RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode, fixTitle: ClassicModelAssertUsageCodeFix.TransformToConstraintModelDescription); + } + + [Test] + public void CodeFixMaintainsReasonableTriviaWithNewLineClosingParen() + { + var code = TestUtility.WrapMethodInClassNamespaceAndAddUsings(@" + public void TestMethod() + { + var expected = typeof(int); + var actual = 42; + + ↓ClassicAssert.IsInstanceOf( + expected, + actual, + ""message"" + ); + }"); + var fixedCode = TestUtility.WrapMethodInClassNamespaceAndAddUsings(@" + public void TestMethod() + { + var expected = typeof(int); + var actual = 42; + + Assert.That( + actual, + Is.InstanceOf(expected), + ""message"" + ); + }"); + RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode, fixTitle: ClassicModelAssertUsageCodeFix.TransformToConstraintModelDescription); + } + + [Test] + public void CodeFixForGenericMaintainsReasonableTriviaWithEndOfLineClosingParen([Values] bool hasMessage) + { + var commaAndMessage = hasMessage + ? @", + ""message""" + : string.Empty; + var code = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + var actual = 42; + + ↓ClassicAssert.IsInstanceOf( + actual{commaAndMessage}); + }}"); + var fixedCode = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + var actual = 42; + + Assert.That( + actual, + Is.InstanceOf(){commaAndMessage}); + }}"); + RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode, fixTitle: ClassicModelAssertUsageCodeFix.TransformToConstraintModelDescription); + } + + [Test] + public void CodeFixForGenericMaintainsReasonableTriviaWithNewLineClosingParen([Values] bool hasMessage) + { + var commaAndMessage = hasMessage + ? @", + ""message""" + : string.Empty; + var code = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + var actual = 42; + + ↓ClassicAssert.IsInstanceOf( + actual{commaAndMessage} + ); + }}"); + var fixedCode = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + var actual = 42; + + Assert.That( + actual, + Is.InstanceOf(){commaAndMessage} + ); + }}"); + RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode, fixTitle: ClassicModelAssertUsageCodeFix.TransformToConstraintModelDescription); + } } } diff --git a/src/nunit.analyzers.tests/ClassicModelAssertUsage/IsNaNClassicModelAssertUsageCodeFixTests.cs b/src/nunit.analyzers.tests/ClassicModelAssertUsage/IsNaNClassicModelAssertUsageCodeFixTests.cs index d474e249..9088ac71 100644 --- a/src/nunit.analyzers.tests/ClassicModelAssertUsage/IsNaNClassicModelAssertUsageCodeFixTests.cs +++ b/src/nunit.analyzers.tests/ClassicModelAssertUsage/IsNaNClassicModelAssertUsageCodeFixTests.cs @@ -123,5 +123,61 @@ public void TestMethod() }"); RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode, fixTitle: ClassicModelAssertUsageCodeFix.TransformToConstraintModelDescription); } + + [Test] + public void CodeFixMaintainsReasonableTriviaWithEndOfLineClosingParen([Values] bool hasMessage) + { + var commaAndMessage = hasMessage + ? @", + ""message""" + : string.Empty; + var code = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + var expr = double.NaN; + + ↓ClassicAssert.IsNaN( + expr{commaAndMessage}); + }}"); + var fixedCode = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + var expr = double.NaN; + + Assert.That( + expr, + Is.NaN{commaAndMessage}); + }}"); + RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode, fixTitle: ClassicModelAssertUsageCodeFix.TransformToConstraintModelDescription); + } + + [Test] + public void CodeFixMaintainsReasonableTriviaWithNewLineClosingParen([Values] bool hasMessage) + { + var commaAndMessage = hasMessage + ? @", + ""message""" + : string.Empty; + var code = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + var expr = double.NaN; + + ↓ClassicAssert.IsNaN( + expr{commaAndMessage} + ); + }}"); + var fixedCode = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + var expr = double.NaN; + + Assert.That( + expr, + Is.NaN{commaAndMessage} + ); + }}"); + RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode, fixTitle: ClassicModelAssertUsageCodeFix.TransformToConstraintModelDescription); + } } } diff --git a/src/nunit.analyzers.tests/ClassicModelAssertUsage/IsNotEmptyClassicModelAssertUsageCodeFixTests.cs b/src/nunit.analyzers.tests/ClassicModelAssertUsage/IsNotEmptyClassicModelAssertUsageCodeFixTests.cs index b410f513..e54797a9 100644 --- a/src/nunit.analyzers.tests/ClassicModelAssertUsage/IsNotEmptyClassicModelAssertUsageCodeFixTests.cs +++ b/src/nunit.analyzers.tests/ClassicModelAssertUsage/IsNotEmptyClassicModelAssertUsageCodeFixTests.cs @@ -195,5 +195,61 @@ public void TestMethod() }"); RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode, fixTitle: ClassicModelAssertUsageCodeFix.TransformToConstraintModelDescription); } + + [Test] + public void CodeFixMaintainsReasonableTriviaWithEndOfLineClosingParen([Values] bool hasMessage) + { + var commaAndMessage = hasMessage + ? @", + ""message""" + : string.Empty; + var code = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + var collection = Array.Empty(); + + ↓ClassicAssert.IsNotEmpty( + collection{commaAndMessage}); + }}"); + var fixedCode = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + var collection = Array.Empty(); + + Assert.That( + collection, + Is.Not.Empty{commaAndMessage}); + }}"); + RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode, fixTitle: ClassicModelAssertUsageCodeFix.TransformToConstraintModelDescription); + } + + [Test] + public void CodeFixMaintainsReasonableTriviaWithNewLineClosingParen([Values] bool hasMessage) + { + var commaAndMessage = hasMessage + ? @", + ""message""" + : string.Empty; + var code = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + var collection = Array.Empty(); + + ↓ClassicAssert.IsNotEmpty( + collection{commaAndMessage} + ); + }}"); + var fixedCode = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + var collection = Array.Empty(); + + Assert.That( + collection, + Is.Not.Empty{commaAndMessage} + ); + }}"); + RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode, fixTitle: ClassicModelAssertUsageCodeFix.TransformToConstraintModelDescription); + } } } diff --git a/src/nunit.analyzers.tests/ClassicModelAssertUsage/IsNotInstanceOfClassicModelAssertUsageCodeFixTests.cs b/src/nunit.analyzers.tests/ClassicModelAssertUsage/IsNotInstanceOfClassicModelAssertUsageCodeFixTests.cs index 259cd1bd..1136a02d 100644 --- a/src/nunit.analyzers.tests/ClassicModelAssertUsage/IsNotInstanceOfClassicModelAssertUsageCodeFixTests.cs +++ b/src/nunit.analyzers.tests/ClassicModelAssertUsage/IsNotInstanceOfClassicModelAssertUsageCodeFixTests.cs @@ -301,5 +301,92 @@ public void VerifyIsNotInstanceOfGenericFixWithMessageAndArrayParamsInNonstandar Assert.That(actual, Is.Not.InstanceOf(), $""{""first""}, {""second""}"");"); RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode, fixTitle: ClassicModelAssertUsageCodeFix.TransformToConstraintModelDescription); } + + [Test] + public void CodeFixMaintainsReasonableTriviaWithEndOfLineClosingParen() + { + var code = TestUtility.WrapMethodInClassNamespaceAndAddUsings(@" + public void TestMethod() + { + var expected = typeof(int); + var actual = 42; + + ↓ClassicAssert.IsNotInstanceOf( + expected, + actual, + ""message""); + }"); + var fixedCode = TestUtility.WrapMethodInClassNamespaceAndAddUsings(@" + public void TestMethod() + { + var expected = typeof(int); + var actual = 42; + + Assert.That( + actual, + Is.Not.InstanceOf(expected), + ""message""); + }"); + RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode, fixTitle: ClassicModelAssertUsageCodeFix.TransformToConstraintModelDescription); + } + + [Test] + public void CodeFixMaintainsReasonableTriviaWithNewLineClosingParen([Values] bool hasMessage) + { + var commaAndMessage = hasMessage + ? @", + ""message""" + : string.Empty; + var code = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + var expected = typeof(int); + var actual = 42; + + ↓ClassicAssert.IsNotInstanceOf( + expected, + actual{commaAndMessage} + ); + }}"); + var fixedCode = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + var expected = typeof(int); + var actual = 42; + + Assert.That( + actual, + Is.Not.InstanceOf(expected){commaAndMessage} + ); + }}"); + RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode, fixTitle: ClassicModelAssertUsageCodeFix.TransformToConstraintModelDescription); + } + + [Test] + public void CodeFixForGenericMaintainsReasonableTriviaWithNewLineClosingParen([Values] bool hasMessage) + { + var commaAndMessage = hasMessage + ? @", + ""message""" + : string.Empty; + var code = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + var actual = 42; + + ↓ClassicAssert.IsNotInstanceOf( + actual{commaAndMessage}); + }}"); + var fixedCode = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + var actual = 42; + + Assert.That( + actual, + Is.Not.InstanceOf(){commaAndMessage}); + }}"); + RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode, fixTitle: ClassicModelAssertUsageCodeFix.TransformToConstraintModelDescription); + } } } diff --git a/src/nunit.analyzers.tests/ClassicModelAssertUsage/IsNotNullAndNotNullClassicModelAssertUsageCodeFixTests.cs b/src/nunit.analyzers.tests/ClassicModelAssertUsage/IsNotNullAndNotNullClassicModelAssertUsageCodeFixTests.cs index f1c37fdc..1c64e5fb 100644 --- a/src/nunit.analyzers.tests/ClassicModelAssertUsage/IsNotNullAndNotNullClassicModelAssertUsageCodeFixTests.cs +++ b/src/nunit.analyzers.tests/ClassicModelAssertUsage/IsNotNullAndNotNullClassicModelAssertUsageCodeFixTests.cs @@ -1,9 +1,12 @@ +using System.Collections.Generic; +using System.Linq; using Gu.Roslyn.Asserts; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.Diagnostics; using NUnit.Analyzers.ClassicModelAssertUsage; using NUnit.Analyzers.Constants; using NUnit.Framework; +using NUnit.Framework.Legacy; namespace NUnit.Analyzers.Tests.ClassicModelAssertUsage { @@ -12,6 +15,12 @@ public sealed class IsNotNullAndNotNullClassicModelAssertUsageCodeFixTests { private static readonly DiagnosticAnalyzer analyzer = new ClassicModelAssertUsageAnalyzer(); private static readonly CodeFixProvider fix = new IsNotNullAndNotNullClassicModelAssertUsageCodeFix(); + private static readonly Dictionary diagnosticIdsToAssertions = new() + { + { AnalyzerIdentifiers.NotNullUsage, nameof(ClassicAssert.NotNull) }, + { AnalyzerIdentifiers.IsNotNullUsage, nameof(ClassicAssert.IsNotNull) }, + }; + private static readonly string[] diagnosticIds = diagnosticIdsToAssertions.Keys.ToArray(); [Test] public void VerifyGetFixableDiagnosticIds() @@ -126,5 +135,67 @@ public void TestMethod() }"); RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode, fixTitle: ClassicModelAssertUsageCodeFix.TransformToConstraintModelDescription); } + + [Test] + public void CodeFixMaintainsReasonableTriviaWithEndOfLineClosingParen( + [ValueSource(nameof(diagnosticIds))] string diagnosticId, + [Values] bool hasMessage) + { + var assertion = diagnosticIdsToAssertions[diagnosticId]; + var commaAndMessage = hasMessage + ? @", + ""message""" + : string.Empty; + var expectedDiagnostic = ExpectedDiagnostic.Create(diagnosticId); + + var code = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + object? obj = null; + ↓ClassicAssert.{assertion}( + obj{commaAndMessage}); + }}"); + var fixedCode = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + object? obj = null; + Assert.That( + obj, + Is.Not.Null{commaAndMessage}); + }}"); + RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode, fixTitle: ClassicModelAssertUsageCodeFix.TransformToConstraintModelDescription); + } + + [Test] + public void CodeFixMaintainsReasonableTriviaWithNewLineClosingParen( + [ValueSource(nameof(diagnosticIds))] string diagnosticId, + [Values] bool hasMessage) + { + var assertion = diagnosticIdsToAssertions[diagnosticId]; + var commaAndMessage = hasMessage + ? @", + ""message""" + : string.Empty; + var expectedDiagnostic = ExpectedDiagnostic.Create(diagnosticId); + + var code = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + object? obj = null; + ↓ClassicAssert.{assertion}( + obj{commaAndMessage} + ); + }}"); + var fixedCode = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + object? obj = null; + Assert.That( + obj, + Is.Not.Null{commaAndMessage} + ); + }}"); + RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode, fixTitle: ClassicModelAssertUsageCodeFix.TransformToConstraintModelDescription); + } } } diff --git a/src/nunit.analyzers.tests/ClassicModelAssertUsage/IsNullAndNullClassicModelAssertUsageCodeFixTests.cs b/src/nunit.analyzers.tests/ClassicModelAssertUsage/IsNullAndNullClassicModelAssertUsageCodeFixTests.cs index 6c517696..7a0cb78b 100644 --- a/src/nunit.analyzers.tests/ClassicModelAssertUsage/IsNullAndNullClassicModelAssertUsageCodeFixTests.cs +++ b/src/nunit.analyzers.tests/ClassicModelAssertUsage/IsNullAndNullClassicModelAssertUsageCodeFixTests.cs @@ -1,9 +1,12 @@ +using System.Collections.Generic; +using System.Linq; using Gu.Roslyn.Asserts; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.Diagnostics; using NUnit.Analyzers.ClassicModelAssertUsage; using NUnit.Analyzers.Constants; using NUnit.Framework; +using NUnit.Framework.Legacy; namespace NUnit.Analyzers.Tests.ClassicModelAssertUsage { @@ -12,6 +15,12 @@ public sealed class IsNullAndNullClassicModelAssertUsageCodeFixTests { private static readonly DiagnosticAnalyzer analyzer = new ClassicModelAssertUsageAnalyzer(); private static readonly CodeFixProvider fix = new IsNullAndNullClassicModelAssertUsageCodeFix(); + private static readonly Dictionary diagnosticIdsToAssertions = new() + { + { AnalyzerIdentifiers.NullUsage, nameof(ClassicAssert.Null) }, + { AnalyzerIdentifiers.IsNullUsage, nameof(ClassicAssert.IsNull) }, + }; + private static readonly string[] diagnosticIds = diagnosticIdsToAssertions.Keys.ToArray(); [Test] public void VerifyGetFixableDiagnosticIds() @@ -126,5 +135,67 @@ public void TestMethod() }"); RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode, fixTitle: ClassicModelAssertUsageCodeFix.TransformToConstraintModelDescription); } + + [Test] + public void CodeFixMaintainsReasonableTriviaWithEndOfLineClosingParen( + [ValueSource(nameof(diagnosticIds))] string diagnosticId, + [Values] bool hasMessage) + { + var assertion = diagnosticIdsToAssertions[diagnosticId]; + var commaAndMessage = hasMessage + ? @", + ""message""" + : string.Empty; + var expectedDiagnostic = ExpectedDiagnostic.Create(diagnosticId); + + var code = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + object? obj = null; + ↓ClassicAssert.{assertion}( + obj{commaAndMessage}); + }}"); + var fixedCode = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + object? obj = null; + Assert.That( + obj, + Is.Null{commaAndMessage}); + }}"); + RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode, fixTitle: ClassicModelAssertUsageCodeFix.TransformToConstraintModelDescription); + } + + [Test] + public void CodeFixMaintainsReasonableTriviaWithNewLineClosingParen( + [ValueSource(nameof(diagnosticIds))] string diagnosticId, + [Values] bool hasMessage) + { + var assertion = diagnosticIdsToAssertions[diagnosticId]; + var commaAndMessage = hasMessage + ? @", + ""message""" + : string.Empty; + var expectedDiagnostic = ExpectedDiagnostic.Create(diagnosticId); + + var code = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + object? obj = null; + ↓ClassicAssert.{assertion}( + obj{commaAndMessage} + ); + }}"); + var fixedCode = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + object? obj = null; + Assert.That( + obj, + Is.Null{commaAndMessage} + ); + }}"); + RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode, fixTitle: ClassicModelAssertUsageCodeFix.TransformToConstraintModelDescription); + } } } diff --git a/src/nunit.analyzers.tests/ClassicModelAssertUsage/IsTrueAndTrueClassicModelAssertUsageCodeFixTests.cs b/src/nunit.analyzers.tests/ClassicModelAssertUsage/IsTrueAndTrueClassicModelAssertUsageCodeFixTests.cs index be20d208..2dd739d0 100644 --- a/src/nunit.analyzers.tests/ClassicModelAssertUsage/IsTrueAndTrueClassicModelAssertUsageCodeFixTests.cs +++ b/src/nunit.analyzers.tests/ClassicModelAssertUsage/IsTrueAndTrueClassicModelAssertUsageCodeFixTests.cs @@ -1,9 +1,12 @@ +using System.Collections.Generic; +using System.Linq; using Gu.Roslyn.Asserts; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.Diagnostics; using NUnit.Analyzers.ClassicModelAssertUsage; using NUnit.Analyzers.Constants; using NUnit.Framework; +using NUnit.Framework.Legacy; namespace NUnit.Analyzers.Tests.ClassicModelAssertUsage { @@ -12,6 +15,12 @@ public sealed class IsTrueAndTrueClassicModelAssertUsageCodeFixTests { private static readonly DiagnosticAnalyzer analyzer = new ClassicModelAssertUsageAnalyzer(); private static readonly CodeFixProvider fix = new IsTrueAndTrueClassicModelAssertUsageCodeFix(); + private static readonly Dictionary diagnosticIdsToAssertions = new() + { + { AnalyzerIdentifiers.TrueUsage, nameof(ClassicAssert.True) }, + { AnalyzerIdentifiers.IsTrueUsage, nameof(ClassicAssert.IsTrue) }, + }; + private static readonly string[] diagnosticIds = diagnosticIdsToAssertions.Keys.ToArray(); [Test] public void VerifyGetFixableDiagnosticIds() @@ -194,5 +203,63 @@ public void TestMethod() }"); RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode, fixTitle: ClassicModelAssertUsageCodeFix.TransformToConstraintModelDescription); } + + [Test] + public void CodeFixMaintainsReasonableTriviaWithEndOfLineClosingParen( + [ValueSource(nameof(diagnosticIds))] string diagnosticId, + [Values] bool hasMessage) + { + var assertion = diagnosticIdsToAssertions[diagnosticId]; + var commaAndMessage = hasMessage + ? @", + ""message""" + : string.Empty; + var expectedDiagnostic = ExpectedDiagnostic.Create(diagnosticId); + + var code = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + ↓ClassicAssert.{assertion}( + true{commaAndMessage}); + }}"); + var fixedCode = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + Assert.That( + true, + Is.True{commaAndMessage}); + }}"); + RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode, fixTitle: ClassicModelAssertUsageCodeFix.TransformToConstraintModelDescription); + } + + [Test] + public void CodeFixMaintainsReasonableTriviaWithNewLineClosingParen( + [ValueSource(nameof(diagnosticIds))] string diagnosticId, + [Values] bool hasMessage) + { + var assertion = diagnosticIdsToAssertions[diagnosticId]; + var commaAndMessage = hasMessage + ? @", + ""message""" + : string.Empty; + var expectedDiagnostic = ExpectedDiagnostic.Create(diagnosticId); + + var code = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + ↓ClassicAssert.{assertion}( + true{commaAndMessage} + ); + }}"); + var fixedCode = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + Assert.That( + true, + Is.True{commaAndMessage} + ); + }}"); + RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode, fixTitle: ClassicModelAssertUsageCodeFix.TransformToConstraintModelDescription); + } } } diff --git a/src/nunit.analyzers.tests/ClassicModelAssertUsage/IsTrueAndTrueClassicModelAssertUsageCondensedCodeFixTests.cs b/src/nunit.analyzers.tests/ClassicModelAssertUsage/IsTrueAndTrueClassicModelAssertUsageCondensedCodeFixTests.cs index 2f840b1d..8f655242 100644 --- a/src/nunit.analyzers.tests/ClassicModelAssertUsage/IsTrueAndTrueClassicModelAssertUsageCondensedCodeFixTests.cs +++ b/src/nunit.analyzers.tests/ClassicModelAssertUsage/IsTrueAndTrueClassicModelAssertUsageCondensedCodeFixTests.cs @@ -1,9 +1,12 @@ +using System.Collections.Generic; +using System.Linq; using Gu.Roslyn.Asserts; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.Diagnostics; using NUnit.Analyzers.ClassicModelAssertUsage; using NUnit.Analyzers.Constants; using NUnit.Framework; +using NUnit.Framework.Legacy; namespace NUnit.Analyzers.Tests.ClassicModelAssertUsage { @@ -12,6 +15,12 @@ public sealed class IsTrueAndTrueClassicModelAssertUsageCondensedCodeFixTests { private static readonly DiagnosticAnalyzer analyzer = new ClassicModelAssertUsageAnalyzer(); private static readonly CodeFixProvider fix = new IsTrueAndTrueClassicModelAssertUsageCondensedCodeFix(); + private static readonly Dictionary diagnosticIdsToAssertions = new() + { + { AnalyzerIdentifiers.TrueUsage, nameof(ClassicAssert.True) }, + { AnalyzerIdentifiers.IsTrueUsage, nameof(ClassicAssert.IsTrue) }, + }; + private static readonly string[] diagnosticIds = diagnosticIdsToAssertions.Keys.ToArray(); [Test] public void VerifyGetFixableDiagnosticIds() @@ -121,5 +130,63 @@ public void TestMethod() RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode, fixTitle: ClassicModelAssertUsageCodeFix.TransformToConstraintModelDescription + IsTrueAndTrueClassicModelAssertUsageCondensedCodeFix.Suffix); } + + [Test] + public void CodeFixMaintainsReasonableTriviaWithEndOfLineClosingParen( + [ValueSource(nameof(diagnosticIds))] string diagnosticId, + [Values] bool hasMessage) + { + var assertion = diagnosticIdsToAssertions[diagnosticId]; + var commaAndMessage = hasMessage + ? @", + ""message""" + : string.Empty; + var expectedDiagnostic = ExpectedDiagnostic.Create(diagnosticId); + + var code = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + ↓ClassicAssert.{assertion}( + true{commaAndMessage}); + }}"); + var fixedCode = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + Assert.That( + true{commaAndMessage}); + }}"); + RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode, + fixTitle: ClassicModelAssertUsageCodeFix.TransformToConstraintModelDescription + IsTrueAndTrueClassicModelAssertUsageCondensedCodeFix.Suffix); + } + + [Test] + public void CodeFixMaintainsReasonableTriviaWithNewLineClosingParen( + [ValueSource(nameof(diagnosticIds))] string diagnosticId, + [Values] bool hasMessage) + { + var assertion = diagnosticIdsToAssertions[diagnosticId]; + var commaAndMessage = hasMessage + ? @", + ""message""" + : string.Empty; + var expectedDiagnostic = ExpectedDiagnostic.Create(diagnosticId); + + var code = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + ↓ClassicAssert.{assertion}( + true{commaAndMessage} + ); + }}"); + var fixedCode = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + Assert.That( + true{commaAndMessage} + ); + }}"); + RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode, + fixTitle: ClassicModelAssertUsageCodeFix.TransformToConstraintModelDescription + IsTrueAndTrueClassicModelAssertUsageCondensedCodeFix.Suffix); + } } } diff --git a/src/nunit.analyzers.tests/ClassicModelAssertUsage/LessClassicModelAssertUsageCodeFixTests.cs b/src/nunit.analyzers.tests/ClassicModelAssertUsage/LessClassicModelAssertUsageCodeFixTests.cs index f1198094..9380fff3 100644 --- a/src/nunit.analyzers.tests/ClassicModelAssertUsage/LessClassicModelAssertUsageCodeFixTests.cs +++ b/src/nunit.analyzers.tests/ClassicModelAssertUsage/LessClassicModelAssertUsageCodeFixTests.cs @@ -231,5 +231,55 @@ public void TestMethod() }"); RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode, fixTitle: ClassicModelAssertUsageCodeFix.TransformToConstraintModelDescription); } + + [Test] + public void CodeFixMaintainsReasonableTriviaWithEndOfLineClosingParen([Values] bool hasMessage) + { + var commaAndMessage = hasMessage + ? @", + ""message""" + : string.Empty; + var code = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + ↓ClassicAssert.Less( + 2d, + 3d{commaAndMessage}); + }}"); + var fixedCode = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + Assert.That( + 2d, + Is.LessThan(3d){commaAndMessage}); + }}"); + RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode, fixTitle: ClassicModelAssertUsageCodeFix.TransformToConstraintModelDescription); + } + + [Test] + public void CodeFixMaintainsReasonableTriviaWithNewLineClosingParen([Values] bool hasMessage) + { + var commaAndMessage = hasMessage + ? @", + ""message""" + : string.Empty; + var code = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + ↓ClassicAssert.Less( + 2d, + 3d{commaAndMessage} + ); + }}"); + var fixedCode = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + Assert.That( + 2d, + Is.LessThan(3d){commaAndMessage} + ); + }}"); + RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode, fixTitle: ClassicModelAssertUsageCodeFix.TransformToConstraintModelDescription); + } } } diff --git a/src/nunit.analyzers.tests/ClassicModelAssertUsage/LessOrEqualClassicModelAssertUsageCodeFixTests.cs b/src/nunit.analyzers.tests/ClassicModelAssertUsage/LessOrEqualClassicModelAssertUsageCodeFixTests.cs index c54be504..99d1f17e 100644 --- a/src/nunit.analyzers.tests/ClassicModelAssertUsage/LessOrEqualClassicModelAssertUsageCodeFixTests.cs +++ b/src/nunit.analyzers.tests/ClassicModelAssertUsage/LessOrEqualClassicModelAssertUsageCodeFixTests.cs @@ -231,5 +231,55 @@ public void TestMethod() }"); RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode, fixTitle: ClassicModelAssertUsageCodeFix.TransformToConstraintModelDescription); } + + [Test] + public void CodeFixMaintainsReasonableTriviaWithEndOfLineClosingParen([Values] bool hasMessage) + { + var commaAndMessage = hasMessage + ? @", + ""message""" + : string.Empty; + var code = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + ↓ClassicAssert.LessOrEqual( + 2d, + 3d{commaAndMessage}); + }}"); + var fixedCode = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + Assert.That( + 2d, + Is.LessThanOrEqualTo(3d){commaAndMessage}); + }}"); + RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode, fixTitle: ClassicModelAssertUsageCodeFix.TransformToConstraintModelDescription); + } + + [Test] + public void CodeFixMaintainsReasonableTriviaWithNewLineClosingParen([Values] bool hasMessage) + { + var commaAndMessage = hasMessage + ? @", + ""message""" + : string.Empty; + var code = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + ↓ClassicAssert.LessOrEqual( + 2d, + 3d{commaAndMessage} + ); + }}"); + var fixedCode = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + Assert.That( + 2d, + Is.LessThanOrEqualTo(3d){commaAndMessage} + ); + }}"); + RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode, fixTitle: ClassicModelAssertUsageCodeFix.TransformToConstraintModelDescription); + } } } diff --git a/src/nunit.analyzers.tests/ClassicModelAssertUsage/NotZeroClassicModelAssertUsageCodeFixTests.cs b/src/nunit.analyzers.tests/ClassicModelAssertUsage/NotZeroClassicModelAssertUsageCodeFixTests.cs index d05fbe00..66fb1ef5 100644 --- a/src/nunit.analyzers.tests/ClassicModelAssertUsage/NotZeroClassicModelAssertUsageCodeFixTests.cs +++ b/src/nunit.analyzers.tests/ClassicModelAssertUsage/NotZeroClassicModelAssertUsageCodeFixTests.cs @@ -123,5 +123,61 @@ public void TestMethod() }"); RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode, fixTitle: ClassicModelAssertUsageCodeFix.TransformToConstraintModelDescription); } + + [Test] + public void CodeFixMaintainsReasonableTriviaWithEndOfLineClosingParen([Values] bool hasMessage) + { + var commaAndMessage = hasMessage + ? @", + ""message""" + : string.Empty; + var code = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + var expr = default(int); + + ↓ClassicAssert.NotZero( + expr{commaAndMessage}); + }}"); + var fixedCode = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + var expr = default(int); + + Assert.That( + expr, + Is.Not.Zero{commaAndMessage}); + }}"); + RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode, fixTitle: ClassicModelAssertUsageCodeFix.TransformToConstraintModelDescription); + } + + [Test] + public void CodeFixMaintainsReasonableTriviaWithNewLineClosingParen([Values] bool hasMessage) + { + var commaAndMessage = hasMessage + ? @", + ""message""" + : string.Empty; + var code = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + var expr = default(int); + + ↓ClassicAssert.NotZero( + expr{commaAndMessage} + ); + }}"); + var fixedCode = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + var expr = default(int); + + Assert.That( + expr, + Is.Not.Zero{commaAndMessage} + ); + }}"); + RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode, fixTitle: ClassicModelAssertUsageCodeFix.TransformToConstraintModelDescription); + } } } diff --git a/src/nunit.analyzers.tests/ClassicModelAssertUsage/ZeroClassicModelAssertUsageCodeFixTests.cs b/src/nunit.analyzers.tests/ClassicModelAssertUsage/ZeroClassicModelAssertUsageCodeFixTests.cs index 5b8fdbe2..1a4d4790 100644 --- a/src/nunit.analyzers.tests/ClassicModelAssertUsage/ZeroClassicModelAssertUsageCodeFixTests.cs +++ b/src/nunit.analyzers.tests/ClassicModelAssertUsage/ZeroClassicModelAssertUsageCodeFixTests.cs @@ -123,5 +123,61 @@ public void TestMethod() }"); RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode, fixTitle: ClassicModelAssertUsageCodeFix.TransformToConstraintModelDescription); } + + [Test] + public void CodeFixMaintainsReasonableTriviaWithEndOfLineClosingParen([Values] bool hasMessage) + { + var commaAndMessage = hasMessage + ? @", + ""message""" + : string.Empty; + var code = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + var expr = default(int); + + ↓ClassicAssert.Zero( + expr{commaAndMessage}); + }}"); + var fixedCode = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + var expr = default(int); + + Assert.That( + expr, + Is.Zero{commaAndMessage}); + }}"); + RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode, fixTitle: ClassicModelAssertUsageCodeFix.TransformToConstraintModelDescription); + } + + [Test] + public void CodeFixMaintainsReasonableTriviaWithNewLineClosingParen([Values] bool hasMessage) + { + var commaAndMessage = hasMessage + ? @", + ""message""" + : string.Empty; + var code = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + var expr = default(int); + + ↓ClassicAssert.Zero( + expr{commaAndMessage} + ); + }}"); + var fixedCode = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@" + public void TestMethod() + {{ + var expr = default(int); + + Assert.That( + expr, + Is.Zero{commaAndMessage} + ); + }}"); + RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode, fixTitle: ClassicModelAssertUsageCodeFix.TransformToConstraintModelDescription); + } } } diff --git a/src/nunit.analyzers.tests/CollectionAssertUsage/CollectionAssertUsageCodeFixTests.cs b/src/nunit.analyzers.tests/CollectionAssertUsage/CollectionAssertUsageCodeFixTests.cs index 665d555e..2edbc393 100644 --- a/src/nunit.analyzers.tests/CollectionAssertUsage/CollectionAssertUsageCodeFixTests.cs +++ b/src/nunit.analyzers.tests/CollectionAssertUsage/CollectionAssertUsageCodeFixTests.cs @@ -123,6 +123,136 @@ public void AnalyzeTwoCollectionWhenNoMessageArgumentsAreUsed(string method) RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode); } + [Test] + public void CodeFixForOneCollectionParameterAssertMaintainsReasonableTriviaWithEndOfLineClosingParen( + [ValueSource(nameof(OneCollectionParameterAsserts))] string method, + [Values] bool hasMessage) + { + var commaAndMessage = hasMessage ? @", + ""message""" : string.Empty; + var code = TestUtility.WrapInTestMethod(@$" + var collection = new[] {{ 1, 2, 3 }}; + ↓CollectionAssert.{method}( + collection{commaAndMessage});"); + var fixedCode = TestUtility.WrapInTestMethod(@$" + var collection = new[] {{ 1, 2, 3 }}; + Assert.That( + collection, + {CollectionAssertUsageAnalyzer.OneCollectionParameterAsserts[method]}{commaAndMessage});"); + RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode); + } + + [Test] + public void CodeFixForOneCollectionParameterAssertMaintainsReasonableTriviaWithNewLineClosingParen( + [ValueSource(nameof(OneCollectionParameterAsserts))] string method, + [Values] bool hasMessage) + { + var commaAndMessage = hasMessage ? @", + ""message""" : string.Empty; + var code = TestUtility.WrapInTestMethod(@$" + var collection = new[] {{ 1, 2, 3 }}; + ↓CollectionAssert.{method}( + collection{commaAndMessage} + );"); + var fixedCode = TestUtility.WrapInTestMethod(@$" + var collection = new[] {{ 1, 2, 3 }}; + Assert.That( + collection, + {CollectionAssertUsageAnalyzer.OneCollectionParameterAsserts[method]}{commaAndMessage} + );"); + RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode); + } + + [Test] + public void CodeFixForTwoCollectionParameterAssertMaintainsReasonableTriviaWithEndOfLineClosingParen( + [ValueSource(nameof(TwoCollectionParameterAsserts))] string method, + [Values] bool hasMessage) + { + var commaAndMessage = hasMessage ? @", + ""message""" : string.Empty; + var code = TestUtility.WrapInTestMethod(@$" + var collection1 = new[] {{ 1, 2, 3 }}; + var collection2 = new[] {{ 2, 4, 6 }}; + ↓CollectionAssert.{method}( + collection1, + collection2{commaAndMessage});"); + var fixedCode = TestUtility.WrapInTestMethod(@$" + var collection1 = new[] {{ 1, 2, 3 }}; + var collection2 = new[] {{ 2, 4, 6 }}; + Assert.That( + {GetAdjustedTwoCollectionConstraint(method, insertNewline: true)}{commaAndMessage});"); + RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode); + } + + [Test] + public void CodeFixForTwoCollectionParameterAssertMaintainsReasonableTriviaWithNewLineClosingParen( + [ValueSource(nameof(TwoCollectionParameterAsserts))] string method, + [Values] bool hasMessage) + { + var commaAndMessage = hasMessage ? @", + ""message""" : string.Empty; + var code = TestUtility.WrapInTestMethod(@$" + var collection1 = new[] {{ 1, 2, 3 }}; + var collection2 = new[] {{ 2, 4, 6 }}; + ↓CollectionAssert.{method}( + collection1, + collection2{commaAndMessage} + );"); + var fixedCode = TestUtility.WrapInTestMethod(@$" + var collection1 = new[] {{ 1, 2, 3 }}; + var collection2 = new[] {{ 2, 4, 6 }}; + Assert.That( + {GetAdjustedTwoCollectionConstraint(method, insertNewline: true)}{commaAndMessage} + );"); + RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode); + } + + [Test] + public void CodeFixForCollectionAndItemParameterAssertMaintainsReasonableTriviaWithEndOfLineClosingParen( + [ValueSource(nameof(CollectionAndItemParameterAsserts))] string method, + [Values] bool hasMessage) + { + var commaAndMessage = hasMessage ? @", + ""message""" : string.Empty; + var code = TestUtility.WrapInTestMethod(@$" + var collection = new[] {{ typeof(byte), typeof(char) }}; + var expected = typeof(byte); + ↓CollectionAssert.{method}( + collection, + expected{commaAndMessage});"); + var fixedCode = TestUtility.WrapInTestMethod(@$" + var collection = new[] {{ typeof(byte), typeof(char) }}; + var expected = typeof(byte); + Assert.That( + collection, + {CollectionAssertUsageAnalyzer.CollectionAndItemParameterAsserts[method]}{commaAndMessage});"); + RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode); + } + + [Test] + public void CodeFixForCollectionAndItemParameterAssertMaintainsReasonableTriviaWithNewLineClosingParen( + [ValueSource(nameof(CollectionAndItemParameterAsserts))] string method, + [Values] bool hasMessage) + { + var commaAndMessage = hasMessage ? @", + ""message""" : string.Empty; + var code = TestUtility.WrapInTestMethod(@$" + var collection = new[] {{ typeof(byte), typeof(char) }}; + var expected = typeof(byte); + ↓CollectionAssert.{method}( + collection, + expected{commaAndMessage} + );"); + var fixedCode = TestUtility.WrapInTestMethod(@$" + var collection = new[] {{ typeof(byte), typeof(char) }}; + var expected = typeof(byte); + Assert.That( + collection, + {CollectionAssertUsageAnalyzer.CollectionAndItemParameterAsserts[method]}{commaAndMessage} + );"); + RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode); + } + [TestCaseSource(nameof(TwoCollectionParameterAsserts))] public void AnalyzeTwoCollectionWhenOnlyMessageArgumentIsUsed(string method) { @@ -325,7 +455,7 @@ public void AnalyzeCollectionAndItemWhenFormatAndParamsArgumentsAreUsedOutOfOrde RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode); } - private static string GetAdjustedTwoCollectionConstraint(string method) + private static string GetAdjustedTwoCollectionConstraint(string method, bool insertNewline = false) { (string actualArgument, string constraintArgument) = CollectionAssertUsageCodeFix.CollectionAssertToOneUnswappedParameterConstraints.ContainsKey(method) @@ -334,7 +464,10 @@ private static string GetAdjustedTwoCollectionConstraint(string method) string constraint = CollectionAssertUsageAnalyzer.TwoCollectionParameterAsserts[method] .Replace("expected", constraintArgument); - return $"{actualArgument}, {constraint}"; + return insertNewline + ? $@"{actualArgument}, + {constraint}" + : $"{actualArgument}, {constraint}"; } } } diff --git a/src/nunit.analyzers.tests/ConstraintsUsage/ComparisonConstraintUsageCodeFixTests.cs b/src/nunit.analyzers.tests/ConstraintsUsage/ComparisonConstraintUsageCodeFixTests.cs index 232872b0..7acafdb6 100644 --- a/src/nunit.analyzers.tests/ConstraintsUsage/ComparisonConstraintUsageCodeFixTests.cs +++ b/src/nunit.analyzers.tests/ConstraintsUsage/ComparisonConstraintUsageCodeFixTests.cs @@ -92,5 +92,54 @@ public void FixesWhenComparisonOperatorUseConstantOnLeftHandSide(string operator RoslynAssert.CodeFix(analyzer, fix, diagnostic, code, fixedCode); } + + [TestCase(">=", "Is.LessThan")] + [TestCase(">", "Is.LessThanOrEqualTo")] + [TestCase("<=", "Is.GreaterThan")] + [TestCase("<", "Is.GreaterThanOrEqualTo")] + public void CodeFixMaintainsReasonableTriviaWithEndOfLineClosingParen(string operatorToken, string constraint) + { + var code = TestUtility.WrapInTestMethod(@$" + int actual = 5; + Assert.That( + ↓actual {operatorToken} 9, + Is.False);"); + + var fixedCode = TestUtility.WrapInTestMethod(@$" + int actual = 5; + Assert.That( + actual, + {constraint}(9));"); + + var diagnostic = ExpectedDiagnostic.Create(AnalyzerIdentifiers.ComparisonConstraintUsage, + string.Format(CultureInfo.InvariantCulture, ComparisonConstraintUsageConstants.Message, constraint)); + + RoslynAssert.CodeFix(analyzer, fix, diagnostic, code, fixedCode); + } + + [TestCase(">=", "Is.GreaterThanOrEqualTo")] + [TestCase(">", "Is.GreaterThan")] + [TestCase("<=", "Is.LessThanOrEqualTo")] + [TestCase("<", "Is.LessThan")] + public void CodeFixMaintainsReasonableTriviaWithNewLineClosingParen(string operatorToken, string constraint) + { + var code = TestUtility.WrapInTestMethod(@$" + int actual = 5; + Assert.That( + ↓actual {operatorToken} 9 + );"); + + var fixedCode = TestUtility.WrapInTestMethod(@$" + int actual = 5; + Assert.That( + actual, + {constraint}(9) + );"); + + var diagnostic = ExpectedDiagnostic.Create(AnalyzerIdentifiers.ComparisonConstraintUsage, + string.Format(CultureInfo.InvariantCulture, ComparisonConstraintUsageConstants.Message, constraint)); + + RoslynAssert.CodeFix(analyzer, fix, diagnostic, code, fixedCode); + } } } diff --git a/src/nunit.analyzers.tests/ConstraintsUsage/EqualConstraintUsageCodeFixTests.cs b/src/nunit.analyzers.tests/ConstraintsUsage/EqualConstraintUsageCodeFixTests.cs index 9b6fc0be..3dd48a47 100644 --- a/src/nunit.analyzers.tests/ConstraintsUsage/EqualConstraintUsageCodeFixTests.cs +++ b/src/nunit.analyzers.tests/ConstraintsUsage/EqualConstraintUsageCodeFixTests.cs @@ -308,19 +308,46 @@ public void FixesEqualsMethodWithAssertFalseWithMessage() } [Test] - public void CodeFixPreservesLineBreakBeforeMessage() + public void CodeFixMaintainsReasonableTriviaWithEndOfLineClosingParen([Values] bool hasMessage) { - var code = TestUtility.WrapInTestMethod(@" + var commaAndMessage = hasMessage + ? @", + ""message""" + : string.Empty; + var code = TestUtility.WrapInTestMethod($@" var actual = ""abc""; + ClassicAssert.False( + actual.Equals(""bcd""){commaAndMessage});"); - ClassicAssert.False(actual.Equals(""bcd""), - ""Assertion message from new line"");"); - - var fixedCode = TestUtility.WrapInTestMethod(@" + var fixedCode = TestUtility.WrapInTestMethod($@" var actual = ""abc""; + Assert.That( + actual, + Is.Not.EqualTo(""bcd""){commaAndMessage});"); + + RoslynAssert.CodeFix(analyzer, fix, equalConstraintDiagnostic, code, fixedCode); + } - Assert.That(actual, Is.Not.EqualTo(""bcd""), - ""Assertion message from new line"");"); + [Test] + public void CodeFixMaintainsReasonableTriviaWithNewLineClosingParen([Values] bool hasMessage) + { + var commaAndMessage = hasMessage + ? @", + ""message""" + : string.Empty; + var code = TestUtility.WrapInTestMethod($@" + var actual = ""abc""; + Assert.That( + actual.Equals(""abc""), + Is.True{commaAndMessage} + );"); + + var fixedCode = TestUtility.WrapInTestMethod($@" + var actual = ""abc""; + Assert.That( + actual, + Is.EqualTo(""abc""){commaAndMessage} + );"); RoslynAssert.CodeFix(analyzer, fix, equalConstraintDiagnostic, code, fixedCode); } diff --git a/src/nunit.analyzers.tests/ConstraintsUsage/SomeItemsConstraintUsageCodeFixTests.cs b/src/nunit.analyzers.tests/ConstraintsUsage/SomeItemsConstraintUsageCodeFixTests.cs index 1c23876c..cc7948d8 100644 --- a/src/nunit.analyzers.tests/ConstraintsUsage/SomeItemsConstraintUsageCodeFixTests.cs +++ b/src/nunit.analyzers.tests/ConstraintsUsage/SomeItemsConstraintUsageCodeFixTests.cs @@ -24,11 +24,11 @@ public class SomeItemsConstraintUsageCodeFixTests public void AnalyzeWhenListContainsUsedAssertThat() { var testCode = TestUtility.WrapInTestMethod(@" - Assert.That(↓new List {1, 2, 3}.Contains(1));", + Assert.That(↓new List { 1, 2, 3 }.Contains(1));", additionalUsings: "using System.Collections.Generic;"); var fixedCode = TestUtility.WrapInTestMethod(@" - Assert.That(new List {1, 2, 3}, Does.Contain(1));", + Assert.That(new List { 1, 2, 3 }, Does.Contain(1));", additionalUsings: "using System.Collections.Generic;"); RoslynAssert.CodeFix(analyzer, fix, doesContainDiagnostic, testCode, fixedCode); @@ -38,11 +38,11 @@ public void AnalyzeWhenListContainsUsedAssertThat() public void AnalyzeWhenListContainsUsedAssertIsTrue() { var testCode = TestUtility.WrapInTestMethod(@" - ClassicAssert.IsTrue(↓new List {1, 2, 3}.Contains(1));", + ClassicAssert.IsTrue(↓new List { 1, 2, 3 }.Contains(1));", additionalUsings: "using System.Collections.Generic;"); var fixedCode = TestUtility.WrapInTestMethod(@" - Assert.That(new List {1, 2, 3}, Does.Contain(1));", + Assert.That(new List { 1, 2, 3 }, Does.Contain(1));", additionalUsings: "using System.Collections.Generic;"); RoslynAssert.CodeFix(analyzer, fix, doesContainDiagnostic, testCode, fixedCode); @@ -52,11 +52,11 @@ public void AnalyzeWhenListContainsUsedAssertIsTrue() public void AnalyzeWhenListContainsUsedAssertIsFalse() { var testCode = TestUtility.WrapInTestMethod(@" - ClassicAssert.IsFalse(↓new List {1, 2, 3}.Contains(1));", + ClassicAssert.IsFalse(↓new List { 1, 2, 3 }.Contains(1));", additionalUsings: "using System.Collections.Generic;"); var fixedCode = TestUtility.WrapInTestMethod(@" - Assert.That(new List {1, 2, 3}, Does.Not.Contain(1));", + Assert.That(new List { 1, 2, 3 }, Does.Not.Contain(1));", additionalUsings: "using System.Collections.Generic;"); RoslynAssert.CodeFix(analyzer, fix, doesNotContainDiagnostic, testCode, fixedCode); @@ -66,11 +66,11 @@ public void AnalyzeWhenListContainsUsedAssertIsFalse() public void AnalyzeWhenLinqContainsUsedAssertThat() { var testCode = TestUtility.WrapInTestMethod(@" - Assert.That(↓new[] {1, 2, 3}.Contains(1));", + Assert.That(↓new[] { 1, 2, 3 }.Contains(1));", additionalUsings: "using System.Linq;"); var fixedCode = TestUtility.WrapInTestMethod(@" - Assert.That(new[] {1, 2, 3}, Does.Contain(1));", + Assert.That(new[] { 1, 2, 3 }, Does.Contain(1));", additionalUsings: "using System.Linq;"); RoslynAssert.CodeFix(analyzer, fix, doesContainDiagnostic, testCode, fixedCode); @@ -80,11 +80,11 @@ public void AnalyzeWhenLinqContainsUsedAssertThat() public void AnalyzeWhenLinqContainsUsedAssertIsTrue() { var testCode = TestUtility.WrapInTestMethod(@" - ClassicAssert.IsTrue(↓new[] {1, 2, 3}.Contains(1));", + ClassicAssert.IsTrue(↓new[] { 1, 2, 3 }.Contains(1));", additionalUsings: "using System.Linq;"); var fixedCode = TestUtility.WrapInTestMethod(@" - Assert.That(new[] {1, 2, 3}, Does.Contain(1));", + Assert.That(new[] { 1, 2, 3 }, Does.Contain(1));", additionalUsings: "using System.Linq;"); RoslynAssert.CodeFix(analyzer, fix, doesContainDiagnostic, testCode, fixedCode); @@ -94,11 +94,47 @@ public void AnalyzeWhenLinqContainsUsedAssertIsTrue() public void AnalyzeWhenLinqContainsUsedAssertIsFalse() { var testCode = TestUtility.WrapInTestMethod(@" - ClassicAssert.IsFalse(↓new[] {1, 2, 3}.Contains(1));", + ClassicAssert.IsFalse(↓new[] { 1, 2, 3 }.Contains(1));", additionalUsings: "using System.Linq;"); var fixedCode = TestUtility.WrapInTestMethod(@" - Assert.That(new[] {1, 2, 3}, Does.Not.Contain(1));", + Assert.That(new[] { 1, 2, 3 }, Does.Not.Contain(1));", + additionalUsings: "using System.Linq;"); + + RoslynAssert.CodeFix(analyzer, fix, doesNotContainDiagnostic, testCode, fixedCode); + } + + [Test] + public void CodeFixMaintainsReasonableTriviaWithEndOfLineClosingParen() + { + var testCode = TestUtility.WrapInTestMethod(@" + ClassicAssert.IsFalse( + ↓new[] { 1, 2, 3 }.Contains(1));", + additionalUsings: "using System.Linq;"); + + var fixedCode = TestUtility.WrapInTestMethod(@" + Assert.That( + new[] { 1, 2, 3 }, + Does.Not.Contain(1));", + additionalUsings: "using System.Linq;"); + + RoslynAssert.CodeFix(analyzer, fix, doesNotContainDiagnostic, testCode, fixedCode); + } + + [Test] + public void CodeFixMaintainsReasonableTriviaWithNewLineClosingParen() + { + var testCode = TestUtility.WrapInTestMethod(@" + ClassicAssert.IsFalse( + ↓new[] { 1, 2, 3 }.Contains(1) + );", + additionalUsings: "using System.Linq;"); + + var fixedCode = TestUtility.WrapInTestMethod(@" + Assert.That( + new[] { 1, 2, 3 }, + Does.Not.Contain(1) + );", additionalUsings: "using System.Linq;"); RoslynAssert.CodeFix(analyzer, fix, doesNotContainDiagnostic, testCode, fixedCode); diff --git a/src/nunit.analyzers.tests/ConstraintsUsage/StringConstraintUsageCodeFixTests.cs b/src/nunit.analyzers.tests/ConstraintsUsage/StringConstraintUsageCodeFixTests.cs index 785f19dd..7da1d63b 100644 --- a/src/nunit.analyzers.tests/ConstraintsUsage/StringConstraintUsageCodeFixTests.cs +++ b/src/nunit.analyzers.tests/ConstraintsUsage/StringConstraintUsageCodeFixTests.cs @@ -121,5 +121,38 @@ public void AnalyzeStringBooleanMethodAssertThatIsFalse(string method, string an RoslynAssert.CodeFix(analyzer, fix, ExpectedDiagnostic.Create(analyzerId), code, fixedCode); } + + [TestCaseSource(nameof(NegativeAssertData))] + public void CodeFixMaintainsReasonableTriviaWithEndOfLineClosingParen(string method, string analyzerId, string suggestedConstraint) + { + var code = TestUtility.WrapInTestMethod($@" + ClassicAssert.IsFalse( + ↓""abc"".{method}(""ab""));"); + + var fixedCode = TestUtility.WrapInTestMethod($@" + Assert.That( + ""abc"", + {suggestedConstraint}(""ab""));"); + + RoslynAssert.CodeFix(analyzer, fix, ExpectedDiagnostic.Create(analyzerId), code, fixedCode); + } + + [TestCaseSource(nameof(NegativeAssertData))] + public void CodeFixMaintainsReasonableTriviaWithNewLineClosingParen(string method, string analyzerId, string suggestedConstraint) + { + var code = TestUtility.WrapInTestMethod($@" + Assert.That( + ↓""abc"".{method}(""ab""), + Is.False + );"); + + var fixedCode = TestUtility.WrapInTestMethod($@" + Assert.That( + ""abc"", + {suggestedConstraint}(""ab"") + );"); + + RoslynAssert.CodeFix(analyzer, fix, ExpectedDiagnostic.Create(analyzerId), code, fixedCode); + } } } diff --git a/src/nunit.analyzers/ClassicModelAssertUsage/AreEqualClassicModelAssertUsageCodeFix.cs b/src/nunit.analyzers/ClassicModelAssertUsage/AreEqualClassicModelAssertUsageCodeFix.cs index fc46671b..f349eae3 100644 --- a/src/nunit.analyzers/ClassicModelAssertUsage/AreEqualClassicModelAssertUsageCodeFix.cs +++ b/src/nunit.analyzers/ClassicModelAssertUsage/AreEqualClassicModelAssertUsageCodeFix.cs @@ -42,11 +42,11 @@ protected override (ArgumentSyntax ActualArgument, ArgumentSyntax? ConstraintArg equalToInvocationNode, SyntaxFactory.IdentifierName(NUnitFrameworkConstants.NameOfEqualConstraintWithin))) .WithArgumentList(SyntaxFactory.ArgumentList( - SyntaxFactory.SingletonSeparatedList(toleranceArgumentNoColon))); + SyntaxFactory.SingletonSeparatedList(toleranceArgumentNoColon.WithoutTrivia()))); } var actualArgument = argumentNamesToArguments[NUnitFrameworkConstants.NameOfActualParameter].WithNameColon(null); - return (actualArgument, SyntaxFactory.Argument(equalToInvocationNode)); + return (actualArgument, SyntaxFactory.Argument(equalToInvocationNode).WithTriviaFrom(actualArgument)); } } } diff --git a/src/nunit.analyzers/ClassicModelAssertUsage/AreNotEqualClassicModelAssertUsageCodeFix.cs b/src/nunit.analyzers/ClassicModelAssertUsage/AreNotEqualClassicModelAssertUsageCodeFix.cs index 55c2f91d..c1b54685 100644 --- a/src/nunit.analyzers/ClassicModelAssertUsage/AreNotEqualClassicModelAssertUsageCodeFix.cs +++ b/src/nunit.analyzers/ClassicModelAssertUsage/AreNotEqualClassicModelAssertUsageCodeFix.cs @@ -34,7 +34,7 @@ protected override (ArgumentSyntax ActualArgument, ArgumentSyntax? ConstraintArg SyntaxFactory.SingletonSeparatedList(expectedArgument)))); var actualArgument = argumentNamesToArguments[NUnitFrameworkConstants.NameOfActualParameter].WithNameColon(null); - return (actualArgument, constraintArgument); + return (actualArgument.WithoutTrailingTrivia(), constraintArgument.WithTriviaFrom(actualArgument)); } } } diff --git a/src/nunit.analyzers/ClassicModelAssertUsage/AreNotSameClassicModelAssertUsageCodeFix.cs b/src/nunit.analyzers/ClassicModelAssertUsage/AreNotSameClassicModelAssertUsageCodeFix.cs index f632ea51..92b8f3bf 100644 --- a/src/nunit.analyzers/ClassicModelAssertUsage/AreNotSameClassicModelAssertUsageCodeFix.cs +++ b/src/nunit.analyzers/ClassicModelAssertUsage/AreNotSameClassicModelAssertUsageCodeFix.cs @@ -34,7 +34,7 @@ protected override (ArgumentSyntax ActualArgument, ArgumentSyntax? ConstraintArg SyntaxFactory.SingletonSeparatedList(expectedArgument)))); var actualArgument = argumentNamesToArguments[NUnitFrameworkConstants.NameOfActualParameter].WithNameColon(null); - return (actualArgument, constraintArgument); + return (actualArgument, constraintArgument.WithTriviaFrom(actualArgument)); } } } diff --git a/src/nunit.analyzers/ClassicModelAssertUsage/AreSameClassicModelAssertUsageCodeFix.cs b/src/nunit.analyzers/ClassicModelAssertUsage/AreSameClassicModelAssertUsageCodeFix.cs index d1340ab1..58fa6725 100644 --- a/src/nunit.analyzers/ClassicModelAssertUsage/AreSameClassicModelAssertUsageCodeFix.cs +++ b/src/nunit.analyzers/ClassicModelAssertUsage/AreSameClassicModelAssertUsageCodeFix.cs @@ -31,7 +31,7 @@ protected override (ArgumentSyntax ActualArgument, ArgumentSyntax? ConstraintArg SyntaxFactory.SingletonSeparatedList(expectedArgument)))); var actualArgument = argumentNamesToArguments[NUnitFrameworkConstants.NameOfActualParameter].WithNameColon(null); - return (actualArgument, constraintArgument); + return (actualArgument, constraintArgument.WithTriviaFrom(actualArgument)); } } } diff --git a/src/nunit.analyzers/ClassicModelAssertUsage/ClassicModelAssertUsageCodeFix.cs b/src/nunit.analyzers/ClassicModelAssertUsage/ClassicModelAssertUsageCodeFix.cs index 58b12827..7067ee86 100644 --- a/src/nunit.analyzers/ClassicModelAssertUsage/ClassicModelAssertUsageCodeFix.cs +++ b/src/nunit.analyzers/ClassicModelAssertUsage/ClassicModelAssertUsageCodeFix.cs @@ -77,6 +77,13 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) if (CodeFixHelper.GetInterpolatedMessageArgumentOrDefault(messageArgument, args, unconditional: false, argsIsArray) is ArgumentSyntax interpolatedMessageArgument) newArguments.Add(interpolatedMessageArgument); + // Fix trailing trivia for the first and the last argument + if (newArguments.Count > 1) + newArguments[0] = newArguments[0].WithoutTrailingTrivia(); + var lastIndex = newArguments.Count - 1; + var previousLastArgument = invocationNode.ArgumentList.Arguments.Last(); + newArguments[lastIndex] = newArguments[lastIndex].WithTrailingTrivia(previousLastArgument.GetTrailingTrivia()); + var newArgumentsList = invocationNode.ArgumentList.WithArguments(newArguments); newInvocationNode = newInvocationNode.WithArgumentList(newArgumentsList); diff --git a/src/nunit.analyzers/ClassicModelAssertUsage/ContainsClassicModelAssertUsageCodeFix.cs b/src/nunit.analyzers/ClassicModelAssertUsage/ContainsClassicModelAssertUsageCodeFix.cs index 94876d81..afd5ef40 100644 --- a/src/nunit.analyzers/ClassicModelAssertUsage/ContainsClassicModelAssertUsageCodeFix.cs +++ b/src/nunit.analyzers/ClassicModelAssertUsage/ContainsClassicModelAssertUsageCodeFix.cs @@ -31,7 +31,7 @@ protected override (ArgumentSyntax ActualArgument, ArgumentSyntax? ConstraintArg SyntaxFactory.SingletonSeparatedList(expectedArgument)))); var actualArgument = argumentNamesToArguments[NUnitFrameworkConstants.NameOfActualParameter].WithNameColon(null); - return (actualArgument, constraintArgument); + return (actualArgument, constraintArgument.WithTriviaFrom(actualArgument)); } } } diff --git a/src/nunit.analyzers/ClassicModelAssertUsage/GreaterClassicModelAssertUsageCodeFix.cs b/src/nunit.analyzers/ClassicModelAssertUsage/GreaterClassicModelAssertUsageCodeFix.cs index 2045d853..3c45bbea 100644 --- a/src/nunit.analyzers/ClassicModelAssertUsage/GreaterClassicModelAssertUsageCodeFix.cs +++ b/src/nunit.analyzers/ClassicModelAssertUsage/GreaterClassicModelAssertUsageCodeFix.cs @@ -28,10 +28,10 @@ protected override (ArgumentSyntax ActualArgument, ArgumentSyntax? ConstraintArg SyntaxFactory.IdentifierName(NUnitFrameworkConstants.NameOfIs), SyntaxFactory.IdentifierName(NUnitFrameworkConstants.NameOfIsGreaterThan))) .WithArgumentList(SyntaxFactory.ArgumentList( - SyntaxFactory.SingletonSeparatedList(arg2Argument)))); + SyntaxFactory.SingletonSeparatedList(arg2Argument.WithoutTrivia())))); var arg1Argument = argumentNamesToArguments[NUnitFrameworkConstants.NameOfArg1Parameter].WithNameColon(null); - return (arg1Argument, constraintArgument); + return (arg1Argument, constraintArgument.WithTriviaFrom(arg1Argument)); } } } diff --git a/src/nunit.analyzers/ClassicModelAssertUsage/GreaterOrEqualClassicModelAssertUsageCodeFix.cs b/src/nunit.analyzers/ClassicModelAssertUsage/GreaterOrEqualClassicModelAssertUsageCodeFix.cs index 0fab1795..3a05a2fe 100644 --- a/src/nunit.analyzers/ClassicModelAssertUsage/GreaterOrEqualClassicModelAssertUsageCodeFix.cs +++ b/src/nunit.analyzers/ClassicModelAssertUsage/GreaterOrEqualClassicModelAssertUsageCodeFix.cs @@ -28,10 +28,10 @@ protected override (ArgumentSyntax ActualArgument, ArgumentSyntax? ConstraintArg SyntaxFactory.IdentifierName(NUnitFrameworkConstants.NameOfIs), SyntaxFactory.IdentifierName(NUnitFrameworkConstants.NameOfIsGreaterThanOrEqualTo))) .WithArgumentList(SyntaxFactory.ArgumentList( - SyntaxFactory.SingletonSeparatedList(arg2Argument)))); + SyntaxFactory.SingletonSeparatedList(arg2Argument.WithoutTrivia())))); var arg1Argument = argumentNamesToArguments[NUnitFrameworkConstants.NameOfArg1Parameter].WithNameColon(null); - return (arg1Argument, constraintArgument); + return (arg1Argument, constraintArgument.WithTriviaFrom(arg1Argument)); } } } diff --git a/src/nunit.analyzers/ClassicModelAssertUsage/IsEmptyClassicModelAssertUsageCodeFix.cs b/src/nunit.analyzers/ClassicModelAssertUsage/IsEmptyClassicModelAssertUsageCodeFix.cs index 3adb8b76..5dc55bac 100644 --- a/src/nunit.analyzers/ClassicModelAssertUsage/IsEmptyClassicModelAssertUsageCodeFix.cs +++ b/src/nunit.analyzers/ClassicModelAssertUsage/IsEmptyClassicModelAssertUsageCodeFix.cs @@ -32,7 +32,7 @@ protected override (ArgumentSyntax ActualArgument, ArgumentSyntax? ConstraintArg SyntaxKind.SimpleMemberAccessExpression, SyntaxFactory.IdentifierName(NUnitFrameworkConstants.NameOfIs), SyntaxFactory.IdentifierName(NUnitFrameworkConstants.NameOfIsEmpty))); - return (actualArgument, constraintArgument); + return (actualArgument, constraintArgument.WithTriviaFrom(actualArgument)); } } } diff --git a/src/nunit.analyzers/ClassicModelAssertUsage/IsFalseAndFalseClassicModelAssertUsageCodeFix.cs b/src/nunit.analyzers/ClassicModelAssertUsage/IsFalseAndFalseClassicModelAssertUsageCodeFix.cs index e52debad..a5f3fa43 100644 --- a/src/nunit.analyzers/ClassicModelAssertUsage/IsFalseAndFalseClassicModelAssertUsageCodeFix.cs +++ b/src/nunit.analyzers/ClassicModelAssertUsage/IsFalseAndFalseClassicModelAssertUsageCodeFix.cs @@ -27,8 +27,12 @@ protected override (ArgumentSyntax ActualArgument, ArgumentSyntax? ConstraintArg SyntaxFactory.MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, SyntaxFactory.IdentifierName(NUnitFrameworkConstants.NameOfIs), - SyntaxFactory.IdentifierName(NUnitFrameworkConstants.NameOfIsFalse))); - return (actualArgument, constraintArgument); + SyntaxFactory.IdentifierName(NUnitFrameworkConstants.NameOfIsFalse))) + .WithTriviaFrom(actualArgument); + + // Swallow the trailing trivia of actualArgument because the comma should immediately follow it + // This also removes comments, but ignore them for now. + return (actualArgument.WithoutTrailingTrivia(), constraintArgument); } } } diff --git a/src/nunit.analyzers/ClassicModelAssertUsage/IsInstanceOfClassicModelAssertUsageCodeFix.cs b/src/nunit.analyzers/ClassicModelAssertUsage/IsInstanceOfClassicModelAssertUsageCodeFix.cs index dc3a59ae..fd46d5d9 100644 --- a/src/nunit.analyzers/ClassicModelAssertUsage/IsInstanceOfClassicModelAssertUsageCodeFix.cs +++ b/src/nunit.analyzers/ClassicModelAssertUsage/IsInstanceOfClassicModelAssertUsageCodeFix.cs @@ -29,7 +29,7 @@ protected override (ArgumentSyntax ActualArgument, ArgumentSyntax ConstraintArgu SyntaxFactory.GenericName(NUnitFrameworkConstants.NameOfIsInstanceOf) .WithTypeArgumentList(typeArguments)))); var actualArgument = argumentNamesToArguments[NUnitFrameworkConstants.NameOfActualParameter].WithNameColon(null); - return (actualArgument, constraintArgument); + return (actualArgument, constraintArgument.WithTriviaFrom(actualArgument)); } protected override (ArgumentSyntax ActualArgument, ArgumentSyntax? ConstraintArgument) ConstructActualAndConstraintArguments( @@ -47,7 +47,7 @@ protected override (ArgumentSyntax ActualArgument, ArgumentSyntax? ConstraintArg SyntaxFactory.SingletonSeparatedList(expectedArgument)))); var actualArgument = argumentNamesToArguments[NUnitFrameworkConstants.NameOfActualParameter].WithNameColon(null); - return (actualArgument, constraintArgument); + return (actualArgument, constraintArgument.WithTriviaFrom(actualArgument)); } } } diff --git a/src/nunit.analyzers/ClassicModelAssertUsage/IsNaNClassicModelAssertUsageCodeFix.cs b/src/nunit.analyzers/ClassicModelAssertUsage/IsNaNClassicModelAssertUsageCodeFix.cs index 81295efc..fd346de1 100644 --- a/src/nunit.analyzers/ClassicModelAssertUsage/IsNaNClassicModelAssertUsageCodeFix.cs +++ b/src/nunit.analyzers/ClassicModelAssertUsage/IsNaNClassicModelAssertUsageCodeFix.cs @@ -27,7 +27,7 @@ protected override (ArgumentSyntax ActualArgument, ArgumentSyntax? ConstraintArg SyntaxKind.SimpleMemberAccessExpression, SyntaxFactory.IdentifierName(NUnitFrameworkConstants.NameOfIs), SyntaxFactory.IdentifierName(NUnitFrameworkConstants.NameOfIsNaN))); - return (actualArgument, constraintArgument); + return (actualArgument, constraintArgument.WithTriviaFrom(actualArgument)); } } } diff --git a/src/nunit.analyzers/ClassicModelAssertUsage/IsNotEmptyClassicModelAssertUsageCodeFix.cs b/src/nunit.analyzers/ClassicModelAssertUsage/IsNotEmptyClassicModelAssertUsageCodeFix.cs index 3f0a7724..dfa2fb7b 100644 --- a/src/nunit.analyzers/ClassicModelAssertUsage/IsNotEmptyClassicModelAssertUsageCodeFix.cs +++ b/src/nunit.analyzers/ClassicModelAssertUsage/IsNotEmptyClassicModelAssertUsageCodeFix.cs @@ -34,7 +34,7 @@ protected override (ArgumentSyntax ActualArgument, ArgumentSyntax? ConstraintArg SyntaxFactory.IdentifierName(NUnitFrameworkConstants.NameOfIs), SyntaxFactory.IdentifierName(NUnitFrameworkConstants.NameOfIsNot)), SyntaxFactory.IdentifierName(NUnitFrameworkConstants.NameOfIsEmpty))); - return (actualArgument, constraintArgument); + return (actualArgument, constraintArgument.WithTriviaFrom(actualArgument)); } } } diff --git a/src/nunit.analyzers/ClassicModelAssertUsage/IsNotInstanceOfClassicModelAssertUsageCodeFix.cs b/src/nunit.analyzers/ClassicModelAssertUsage/IsNotInstanceOfClassicModelAssertUsageCodeFix.cs index 39cb57c1..7c4b54bf 100644 --- a/src/nunit.analyzers/ClassicModelAssertUsage/IsNotInstanceOfClassicModelAssertUsageCodeFix.cs +++ b/src/nunit.analyzers/ClassicModelAssertUsage/IsNotInstanceOfClassicModelAssertUsageCodeFix.cs @@ -32,7 +32,7 @@ protected override (ArgumentSyntax ActualArgument, ArgumentSyntax ConstraintArgu SyntaxFactory.GenericName(NUnitFrameworkConstants.NameOfIsInstanceOf) .WithTypeArgumentList(typeArguments)))); var actualArgument = argumentNamesToArguments[NUnitFrameworkConstants.NameOfActualParameter].WithNameColon(null); - return (actualArgument, constraintArgument); + return (actualArgument, constraintArgument.WithTriviaFrom(actualArgument)); } protected override (ArgumentSyntax ActualArgument, ArgumentSyntax? ConstraintArgument) ConstructActualAndConstraintArguments( @@ -53,7 +53,7 @@ protected override (ArgumentSyntax ActualArgument, ArgumentSyntax? ConstraintArg SyntaxFactory.SingletonSeparatedList(expectedArgument)))); var actualArgument = argumentNamesToArguments[NUnitFrameworkConstants.NameOfActualParameter].WithNameColon(null); - return (actualArgument, constraintArgument); + return (actualArgument, constraintArgument.WithTriviaFrom(actualArgument)); } } } diff --git a/src/nunit.analyzers/ClassicModelAssertUsage/IsNotNullAndNotNullClassicModelAssertUsageCodeFix.cs b/src/nunit.analyzers/ClassicModelAssertUsage/IsNotNullAndNotNullClassicModelAssertUsageCodeFix.cs index 8d5f9ea9..c31b4e9d 100644 --- a/src/nunit.analyzers/ClassicModelAssertUsage/IsNotNullAndNotNullClassicModelAssertUsageCodeFix.cs +++ b/src/nunit.analyzers/ClassicModelAssertUsage/IsNotNullAndNotNullClassicModelAssertUsageCodeFix.cs @@ -32,7 +32,7 @@ protected override (ArgumentSyntax ActualArgument, ArgumentSyntax? ConstraintArg SyntaxFactory.IdentifierName(NUnitFrameworkConstants.NameOfIsNull))); var actualArgument = argumentNamesToArguments[NUnitFrameworkConstants.NameOfAnObjectParameter].WithNameColon(null); - return (actualArgument, constraintArgument); + return (actualArgument, constraintArgument.WithTriviaFrom(actualArgument)); } } } diff --git a/src/nunit.analyzers/ClassicModelAssertUsage/IsNullAndNullClassicModelAssertUsageCodeFix.cs b/src/nunit.analyzers/ClassicModelAssertUsage/IsNullAndNullClassicModelAssertUsageCodeFix.cs index 908ee2cb..5f5137bb 100644 --- a/src/nunit.analyzers/ClassicModelAssertUsage/IsNullAndNullClassicModelAssertUsageCodeFix.cs +++ b/src/nunit.analyzers/ClassicModelAssertUsage/IsNullAndNullClassicModelAssertUsageCodeFix.cs @@ -29,7 +29,7 @@ protected override (ArgumentSyntax ActualArgument, ArgumentSyntax? ConstraintArg SyntaxFactory.IdentifierName(NUnitFrameworkConstants.NameOfIsNull))); var actualArgument = argumentNamesToArguments[NUnitFrameworkConstants.NameOfAnObjectParameter].WithNameColon(null); - return (actualArgument, constraintArgument); + return (actualArgument, constraintArgument.WithTriviaFrom(actualArgument)); } } } diff --git a/src/nunit.analyzers/ClassicModelAssertUsage/IsTrueAndTrueClassicModelAssertUsageCodeFix.cs b/src/nunit.analyzers/ClassicModelAssertUsage/IsTrueAndTrueClassicModelAssertUsageCodeFix.cs index 2eb25e67..9f7d0c05 100644 --- a/src/nunit.analyzers/ClassicModelAssertUsage/IsTrueAndTrueClassicModelAssertUsageCodeFix.cs +++ b/src/nunit.analyzers/ClassicModelAssertUsage/IsTrueAndTrueClassicModelAssertUsageCodeFix.cs @@ -29,7 +29,7 @@ protected override (ArgumentSyntax ActualArgument, ArgumentSyntax? ConstraintArg SyntaxFactory.IdentifierName(NUnitFrameworkConstants.NameOfIsTrue))); var actualArgument = argumentNamesToArguments[NUnitFrameworkConstants.NameOfConditionParameter].WithNameColon(null); - return (actualArgument, constraintArgument); + return (actualArgument, constraintArgument.WithTriviaFrom(actualArgument)); } } } diff --git a/src/nunit.analyzers/ClassicModelAssertUsage/LessClassicModelAssertUsageCodeFix.cs b/src/nunit.analyzers/ClassicModelAssertUsage/LessClassicModelAssertUsageCodeFix.cs index e0cb12ca..efc8263b 100644 --- a/src/nunit.analyzers/ClassicModelAssertUsage/LessClassicModelAssertUsageCodeFix.cs +++ b/src/nunit.analyzers/ClassicModelAssertUsage/LessClassicModelAssertUsageCodeFix.cs @@ -28,10 +28,10 @@ protected override (ArgumentSyntax ActualArgument, ArgumentSyntax? ConstraintArg SyntaxFactory.IdentifierName(NUnitFrameworkConstants.NameOfIs), SyntaxFactory.IdentifierName(NUnitFrameworkConstants.NameOfIsLessThan))) .WithArgumentList(SyntaxFactory.ArgumentList( - SyntaxFactory.SingletonSeparatedList(arg2Argument)))); + SyntaxFactory.SingletonSeparatedList(arg2Argument.WithoutTrivia())))); var arg1Argument = argumentNamesToArguments[NUnitFrameworkConstants.NameOfArg1Parameter].WithNameColon(null); - return (arg1Argument, constraintArgument); + return (arg1Argument, constraintArgument.WithTriviaFrom(arg1Argument)); } } } diff --git a/src/nunit.analyzers/ClassicModelAssertUsage/LessOrEqualClassicModelAssertUsageCodeFix.cs b/src/nunit.analyzers/ClassicModelAssertUsage/LessOrEqualClassicModelAssertUsageCodeFix.cs index 4c69a932..7a43f69f 100644 --- a/src/nunit.analyzers/ClassicModelAssertUsage/LessOrEqualClassicModelAssertUsageCodeFix.cs +++ b/src/nunit.analyzers/ClassicModelAssertUsage/LessOrEqualClassicModelAssertUsageCodeFix.cs @@ -28,10 +28,10 @@ protected override (ArgumentSyntax ActualArgument, ArgumentSyntax? ConstraintArg SyntaxFactory.IdentifierName(NUnitFrameworkConstants.NameOfIs), SyntaxFactory.IdentifierName(NUnitFrameworkConstants.NameOfIsLessThanOrEqualTo))) .WithArgumentList(SyntaxFactory.ArgumentList( - SyntaxFactory.SingletonSeparatedList(arg2Argument)))); + SyntaxFactory.SingletonSeparatedList(arg2Argument.WithoutTrivia())))); var arg1Argument = argumentNamesToArguments[NUnitFrameworkConstants.NameOfArg1Parameter].WithNameColon(null); - return (arg1Argument, constraintArgument); + return (arg1Argument, constraintArgument.WithTriviaFrom(arg1Argument)); } } } diff --git a/src/nunit.analyzers/ClassicModelAssertUsage/NotZeroClassicModelAssertUsageCodeFix.cs b/src/nunit.analyzers/ClassicModelAssertUsage/NotZeroClassicModelAssertUsageCodeFix.cs index c76db4cf..05ec00cf 100644 --- a/src/nunit.analyzers/ClassicModelAssertUsage/NotZeroClassicModelAssertUsageCodeFix.cs +++ b/src/nunit.analyzers/ClassicModelAssertUsage/NotZeroClassicModelAssertUsageCodeFix.cs @@ -30,7 +30,7 @@ protected override (ArgumentSyntax ActualArgument, ArgumentSyntax? ConstraintArg SyntaxFactory.IdentifierName(NUnitFrameworkConstants.NameOfIs), SyntaxFactory.IdentifierName(NUnitFrameworkConstants.NameOfIsNot)), SyntaxFactory.IdentifierName(NUnitFrameworkConstants.NameOfIsZero))); - return (actualArgument, constraintArgument); + return (actualArgument, constraintArgument.WithTriviaFrom(actualArgument)); } } } diff --git a/src/nunit.analyzers/ClassicModelAssertUsage/ZeroClassicModelAssertUsageCodeFix.cs b/src/nunit.analyzers/ClassicModelAssertUsage/ZeroClassicModelAssertUsageCodeFix.cs index 4eb547d9..9a9e0ec4 100644 --- a/src/nunit.analyzers/ClassicModelAssertUsage/ZeroClassicModelAssertUsageCodeFix.cs +++ b/src/nunit.analyzers/ClassicModelAssertUsage/ZeroClassicModelAssertUsageCodeFix.cs @@ -27,7 +27,7 @@ protected override (ArgumentSyntax ActualArgument, ArgumentSyntax? ConstraintArg SyntaxKind.SimpleMemberAccessExpression, SyntaxFactory.IdentifierName(NUnitFrameworkConstants.NameOfIs), SyntaxFactory.IdentifierName(NUnitFrameworkConstants.NameOfIsZero))); - return (actualArgument, constraintArgument); + return (actualArgument, constraintArgument.WithTriviaFrom(actualArgument)); } } } diff --git a/src/nunit.analyzers/CollectionAssertUsage/CollectionAssertUsageCodeFix.cs b/src/nunit.analyzers/CollectionAssertUsage/CollectionAssertUsageCodeFix.cs index 043bc667..c1694864 100644 --- a/src/nunit.analyzers/CollectionAssertUsage/CollectionAssertUsageCodeFix.cs +++ b/src/nunit.analyzers/CollectionAssertUsage/CollectionAssertUsageCodeFix.cs @@ -93,11 +93,12 @@ protected override (ArgumentSyntax ActualArgument, ArgumentSyntax? ConstraintArg Diagnostic diagnostic, IReadOnlyDictionary argumentNamesToArguments) { - var (actualArgument, constraintArgument) = GetActualAndConstraintArguments(diagnostic, argumentNamesToArguments); + var (actualArgument, originalConstraintArgument) = GetActualAndConstraintArguments(diagnostic, argumentNamesToArguments); + var newConstraintArgument = originalConstraintArgument; if (argumentNamesToArguments.TryGetValue(NameOfComparerParameter, out ArgumentSyntax? comparerArgument)) { - ExpressionSyntax expression = constraintArgument.Expression; + ExpressionSyntax expression = originalConstraintArgument.Expression; // We need to drop the 'AsCollection' when using an IComparer. if (expression is MemberAccessExpressionSyntax memberAccessExpression && @@ -106,7 +107,7 @@ protected override (ArgumentSyntax ActualArgument, ArgumentSyntax? ConstraintArg expression = memberAccessExpression.Expression; } - constraintArgument = Argument( + newConstraintArgument = Argument( InvocationExpression( MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, @@ -115,7 +116,7 @@ protected override (ArgumentSyntax ActualArgument, ArgumentSyntax? ConstraintArg ArgumentList(SingletonSeparatedList(comparerArgument)))); } - return (actualArgument, constraintArgument); + return (actualArgument.WithoutTrailingTrivia(), newConstraintArgument.WithTriviaFrom(actualArgument)); } private static (ArgumentSyntax actualArgument, ArgumentSyntax constraintArgument) GetActualAndConstraintArguments( @@ -142,7 +143,7 @@ private static (ArgumentSyntax actualArgument, ArgumentSyntax constraintArgument { var secondParameterName = CollectionAssertToSecondParameterName[methodName]; var secondArgument = argumentNamesToArguments[secondParameterName].WithNameColon(null); - var constraintArgument = Argument(constraints.CreateConstraint(secondArgument)); + var constraintArgument = Argument(constraints.CreateConstraint(secondArgument.WithoutTrivia())); return (firstArgument, constraintArgument); } diff --git a/src/nunit.analyzers/ConstraintUsage/BaseConditionConstraintCodeFix.cs b/src/nunit.analyzers/ConstraintUsage/BaseConditionConstraintCodeFix.cs index 406a50ab..043dcc4b 100644 --- a/src/nunit.analyzers/ConstraintUsage/BaseConditionConstraintCodeFix.cs +++ b/src/nunit.analyzers/ConstraintUsage/BaseConditionConstraintCodeFix.cs @@ -8,6 +8,7 @@ using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Formatting; using NUnit.Analyzers.Extensions; using NUnit.Analyzers.Helpers; using static NUnit.Analyzers.Constants.NUnitFrameworkConstants; @@ -73,7 +74,7 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context) if (assertMethod is null) return; - var newAssertNode = UpdateAssertNode(assertNode, assertMethod, actual, constraintExpression); + var newAssertNode = UpdateAssertNode(assertNode, conditionNode, assertMethod, actual, constraintExpression); if (newAssertNode is null) return; @@ -107,10 +108,10 @@ protected virtual (ExpressionSyntax? actual, ExpressionSyntax? constraintExpress return SyntaxFactory.InvocationExpression( SyntaxFactory.ParseExpression(constraintString), - SyntaxFactory.ArgumentList(SyntaxFactory.SingletonSeparatedList(SyntaxFactory.Argument(expected)))); + SyntaxFactory.ArgumentList(SyntaxFactory.SingletonSeparatedList(SyntaxFactory.Argument(expected.WithoutTrivia())))); } - protected static InvocationExpressionSyntax? UpdateAssertNode(InvocationExpressionSyntax assertNode, IMethodSymbol assertMethod, + protected static InvocationExpressionSyntax? UpdateAssertNode(InvocationExpressionSyntax assertNode, ExpressionSyntax? conditionNode, IMethodSymbol assertMethod, ExpressionSyntax actual, ExpressionSyntax constraintExpression) { // Replace the original ClassicAssert. invocation name into Assert.That @@ -126,13 +127,26 @@ protected virtual (ExpressionSyntax? actual, ExpressionSyntax? constraintExpress ? assertNode.ArgumentList.Arguments.Skip(2) : assertNode.ArgumentList.Arguments.Skip(1); + var actualArgument = SyntaxFactory.Argument(actual); + var actualArgumentWithRightTrivia = conditionNode is not null + ? actualArgument.WithLeadingTrivia(conditionNode.GetLeadingTrivia()) // ignore the trailing trivia, as there is a following argument + : actualArgument; + + var lastOriginalArgument = assertNode.ArgumentList.Arguments.Last(); + var constraintArgument = SyntaxFactory.Argument(constraintExpression).WithTriviaFrom(lastOriginalArgument); + var constraintArgumentWithRightTrivia = remainingArguments.Any() + ? constraintArgument.WithoutTrailingTrivia() // remove the trailing trivia, as there is a following argument + : constraintArgument; + var newArguments = new[] { - SyntaxFactory.Argument(actual), - SyntaxFactory.Argument(constraintExpression) + actualArgumentWithRightTrivia, + constraintArgumentWithRightTrivia }.Union(remainingArguments); - var newArgumentsList = assertNode.ArgumentList.WithArguments(newArguments); + var newArgumentsList = assertNode.ArgumentList + .WithArguments(newArguments) + .WithAdditionalAnnotations(Formatter.Annotation); return newAssertNode.WithArgumentList(newArgumentsList); } diff --git a/src/nunit.analyzers/ConstraintUsage/EqualConstraintUsageCodeFix.cs b/src/nunit.analyzers/ConstraintUsage/EqualConstraintUsageCodeFix.cs index cc059520..91c9438b 100644 --- a/src/nunit.analyzers/ConstraintUsage/EqualConstraintUsageCodeFix.cs +++ b/src/nunit.analyzers/ConstraintUsage/EqualConstraintUsageCodeFix.cs @@ -35,7 +35,10 @@ protected override (ExpressionSyntax? actual, ExpressionSyntax? constraintExpres constraintExpression = null; } - return (actual, constraintExpression); + // Fix trivia + return actual is not null && constraintExpression is not null + ? (actual.WithTriviaFrom(constraintExpression), constraintExpression.WithTriviaFrom(actual)) + : (actual, constraintExpression); } private static (ExpressionSyntax? actual, ExpressionOrPatternSyntax? expected) GetActualExpected(SyntaxNode conditionNode) diff --git a/src/nunit.analyzers/ConstraintUsage/SomeItemsConstraintUsageCodeFix.cs b/src/nunit.analyzers/ConstraintUsage/SomeItemsConstraintUsageCodeFix.cs index 026c3e49..34a62194 100644 --- a/src/nunit.analyzers/ConstraintUsage/SomeItemsConstraintUsageCodeFix.cs +++ b/src/nunit.analyzers/ConstraintUsage/SomeItemsConstraintUsageCodeFix.cs @@ -23,7 +23,12 @@ protected override (ExpressionSyntax? actual, ExpressionSyntax? constraintExpres var expected = invocation.ArgumentList.Arguments.FirstOrDefault()?.Expression; var constraintExpression = GetConstraintExpression(suggestedConstraintString, expected); - return (actual, constraintExpression); + // Fix trivia + return ( + actual, + constraintExpression is not null + ? constraintExpression.WithTriviaFrom(conditionNode) + : constraintExpression); } else { diff --git a/src/nunit.analyzers/ConstraintUsage/StringConstraintUsageCodeFix.cs b/src/nunit.analyzers/ConstraintUsage/StringConstraintUsageCodeFix.cs index 59031cff..6a950c64 100644 --- a/src/nunit.analyzers/ConstraintUsage/StringConstraintUsageCodeFix.cs +++ b/src/nunit.analyzers/ConstraintUsage/StringConstraintUsageCodeFix.cs @@ -26,7 +26,10 @@ protected override (ExpressionSyntax? actual, ExpressionSyntax? constraintExpres var expected = invocation.ArgumentList.Arguments.FirstOrDefault()?.Expression; var constraintExpression = GetConstraintExpression(suggestedConstraintString, expected); - return (actual, constraintExpression); + // Fix trivia + return actual is not null && constraintExpression is not null + ? (actual.WithTriviaFrom(constraintExpression), constraintExpression.WithTriviaFrom(actual)) + : (actual, constraintExpression); } else { diff --git a/src/nunit.analyzers/Extensions/ArgumentListSyntaxExtensions.cs b/src/nunit.analyzers/Extensions/ArgumentListSyntaxExtensions.cs index dffbd509..4f606afb 100644 --- a/src/nunit.analyzers/Extensions/ArgumentListSyntaxExtensions.cs +++ b/src/nunit.analyzers/Extensions/ArgumentListSyntaxExtensions.cs @@ -13,7 +13,19 @@ public static ArgumentListSyntax WithArguments( IEnumerable newArguments) { var originalArguments = @this.Arguments; - var originalSeparators = originalArguments.GetSeparators(); + var originalSeparators = originalArguments.GetSeparators().ToArray(); + + // To match the old style as closely as possible, do not attempt anything if the number of arguments stayed the same + if (originalArguments.Count == newArguments.Count()) + { + return @this.WithArguments(SyntaxFactory.SeparatedList(newArguments, originalSeparators)); + } + + // Otherwise, the number of arguments has either increased or decreased, in which case + // there is no one-size-fits-all answer on what to do about the trivias around separators. + // Therefore, add a newline after the the separator if either the opening parenthesis + // or any of the original separators had a trailing newline. + var shouldAddTrailingNewlineAfterComma = TryGetFirstEndOfLineTrivia(@this.OpenParenToken, originalSeparators, out var trailingTrivia); var nodesAndTokens = new List { newArguments.First() }; @@ -25,7 +37,10 @@ public static ArgumentListSyntax WithArguments( if (separator == default(SyntaxToken)) { - separator = SyntaxFactory.Token(SyntaxKind.CommaToken); + separator = SyntaxFactory.Token( + SyntaxFactory.TriviaList(), + SyntaxKind.CommaToken, + shouldAddTrailingNewlineAfterComma ? SyntaxFactory.TriviaList(trailingTrivia) : SyntaxFactory.TriviaList()); } nodesAndTokens.Add(separator); @@ -36,5 +51,32 @@ public static ArgumentListSyntax WithArguments( return @this.WithArguments(newSeparatedList); } + + private static bool TryGetFirstEndOfLineTrivia(SyntaxToken openParenToken, SyntaxToken[] separators, out SyntaxTrivia trailingTrivia) + { + foreach (var trivia in openParenToken.TrailingTrivia) + { + if (trivia.IsKind(SyntaxKind.EndOfLineTrivia)) + { + trailingTrivia = trivia; + return true; + } + } + + foreach (var separator in separators) + { + foreach (var trivia in separator.TrailingTrivia) + { + if (trivia.IsKind(SyntaxKind.EndOfLineTrivia)) + { + trailingTrivia = trivia; + return true; + } + } + } + + trailingTrivia = default; + return false; + } } }