File: src\Analyzers\CSharp\Tests\DocumentationComments\RemoveDocCommentNodeCodeFixProviderTests.cs
Web Access
Project: src\src\Features\CSharpTest\Microsoft.CodeAnalysis.CSharp.Features.UnitTests.csproj (Microsoft.CodeAnalysis.CSharp.Features.UnitTests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.DocumentationComments;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Diagnostics;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;
using Xunit.Abstractions;
 
namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.DocumentationComments;
 
[Trait(Traits.Feature, Traits.Features.CodeActionsRemoveDocCommentNode)]
public class RemoveDocCommentNodeCodeFixProviderTests : AbstractCSharpDiagnosticProviderBasedUserDiagnosticTest_NoEditor
{
    private static readonly CSharpParseOptions Regular = new(kind: SourceCodeKind.Regular);
 
    public RemoveDocCommentNodeCodeFixProviderTests(ITestOutputHelper logger)
       : base(logger)
    {
    }
 
    internal override (DiagnosticAnalyzer?, CodeFixProvider) CreateDiagnosticProviderAndFixer(Workspace workspace)
        => (null, new CSharpRemoveDocCommentNodeCodeFixProvider());
 
    private async Task TestAsync(string initial, string expected)
    {
        var parseOptions = Regular.WithDocumentationMode(DocumentationMode.Diagnose);
        await TestAsync(initial, expected, parseOptions: parseOptions);
    }
 
    [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveDocCommentNode)]
    public async Task RemovesDuplicateParamTag()
    {
        var initial =
            """
            class Program
            {
                /// <summary>
                /// 
                /// </summary>
                /// <param name="value"></param>
                /// <param [|name="value"|]></param>
                public void Fizz(int value) {}
            }
            """;
 
        var expected =
            """
            class Program
            {
                /// <summary>
                /// 
                /// </summary>
                /// <param name="value"></param>
                public void Fizz(int value) {}
            }
            """;
        await TestAsync(initial, expected);
    }
 
    [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveDocCommentNode)]
    public async Task RemovesDuplicateParamTag_OnlyParamTags()
    {
        var initial =
            """
            class Program
            {
                /// <param name="value"></param>
                /// <param [|name="value"|]></param>
                public void Fizz(int value) {}
            }
            """;
 
        var expected =
            """
            class Program
            {
                /// <param name="value"></param>
                public void Fizz(int value) {}
            }
            """;
        await TestAsync(initial, expected);
    }
 
    [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveDocCommentNode)]
    public async Task RemovesDuplicateParamTag_TagBelowOffendingParamTag()
    {
        var initial =
            """
            class Program
            {
                /// <param name="value"></param>
                /// <param [|name="value"|]></param>
                /// <returns></returns>
                public int Fizz(int value) { return 0; }
            }
            """;
 
        var expected =
            """
            class Program
            {
                /// <param name="value"></param>
                /// <returns></returns>
                public int Fizz(int value) { return 0; }
            }
            """;
        await TestAsync(initial, expected);
    }
 
    [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveDocCommentNode)]
    public async Task RemovesDuplicateParamTag_BothParamTagsOnSameLine_DocCommentTagBetweenThem()
    {
        var initial =
            """
            class Program
            {
                /// <summary>
                /// 
                /// </summary>
                /// <param name="value"></param>    /// <param [|name="value"|]></param>
                public void Fizz(int value) {}
            }
            """;
 
        var expected =
            """
            class Program
            {
                /// <summary>
                /// 
                /// </summary>
                /// <param name="value"></param>
                public void Fizz(int value) {}
            }
            """;
        await TestAsync(initial, expected);
    }
 
    [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveDocCommentNode)]
    public async Task RemovesDuplicateParamTag_BothParamTagsOnSameLine_WhitespaceBetweenThem()
    {
        var initial =
            """
            class Program
            {
                /// <summary>
                /// 
                /// </summary>
                /// <param name="value"></param>     <param [|name="value"|]></param>
                public void Fizz(int value) {}
            }
            """;
 
        var expected =
            """
            class Program
            {
                /// <summary>
                /// 
                /// </summary>
                /// <param name="value"></param>
                public void Fizz(int value) {}
            }
            """;
        await TestAsync(initial, expected);
    }
 
    [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveDocCommentNode)]
    public async Task RemovesDuplicateParamTag_BothParamTagsOnSameLine_NothingBetweenThem1()
    {
        var initial =
            """
            class Program
            {
                /// <summary>
                /// 
                /// </summary>
                /// <param name="value"></param><param [|name="value"|]></param>
                public void Fizz(int value) {}
            }
            """;
 
        var expected =
            """
            class Program
            {
                /// <summary>
                /// 
                /// </summary>
                /// <param name="value"></param>
                public void Fizz(int value) {}
            }
            """;
        await TestAsync(initial, expected);
    }
 
    [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveDocCommentNode)]
    [WorkItem("https://github.com/dotnet/roslyn/issues/13436")]
    public async Task RemovesTag_BothParamTagsOnSameLine_NothingBetweenThem2()
    {
        var initial =
            """
            class Program
            {
                /// <summary>
                /// 
                /// </summary>
                /// <param [|name="a"|]></param><param name="value"></param>
                public void Fizz(int value) {}
            }
            """;
 
        var expected =
            """
            class Program
            {
                /// <summary>
                /// 
                /// </summary>
                /// <param name="value"></param>
                public void Fizz(int value) {}
            }
            """;
        await TestAsync(initial, expected);
    }
 
    [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveDocCommentNode)]
    [WorkItem("https://github.com/dotnet/roslyn/issues/13436")]
    public async Task RemovesTag_TrailingTextAfterTag()
    {
        var initial =
            """
            class Program
            {
                /// <summary>
                /// 
                /// </summary>
                /// <param [|name="a"|]></param> a
                public void Fizz(int value) {}
            }
            """;
 
        var expected =
            """
            class Program
            {
                /// <summary>
                /// 
                /// </summary>
                ///  a
                public void Fizz(int value) {}
            }
            """;
        await TestAsync(initial, expected);
    }
 
    [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveDocCommentNode)]
    public async Task RemovesDuplicateParamTag_RawTextBeforeAndAfterNode()
    {
        var initial =
            """
            class Program
            {
                /// <summary>
                /// 
                /// </summary>
                /// <param name="value"></param>
                /// some comment<param [|name="value"|]></param>out of the XML nodes
                public void Fizz(int value) {}
            }
            """;
 
        var expected =
            """
            class Program
            {
                /// <summary>
                /// 
                /// </summary>
                /// <param name="value"></param>
                /// some commentout of the XML nodes
                public void Fizz(int value) {}
            }
            """;
        await TestAsync(initial, expected);
    }
 
    [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveDocCommentNode)]
    public async Task RemovesDuplicateTypeparamTag()
    {
        var initial =
            """
            class Program
            {
                /// <summary>
                /// 
                /// </summary>
                /// <typeparam name="T"></typeparam>
                /// <typeparam [|name="T"|]></typeparam>
                public void Fizz<T>() { }
            }
            """;
 
        var expected =
            """
            class Program
            {
                /// <summary>
                /// 
                /// </summary>
                /// <typeparam name="T"></typeparam>
                public void Fizz<T>() { }
            }
            """;
        await TestAsync(initial, expected);
    }
 
    [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveDocCommentNode)]
    public async Task RemovesParamTagWithNoMatchingParameter()
    {
        var initial =
            """
            class Program
            {
                /// <summary>
                /// 
                /// </summary>
                /// <param name="[|val|]"></param>
                public void Fizz(int value) {}
            }
            """;
 
        var expected =
            """
            class Program
            {
                /// <summary>
                /// 
                /// </summary>
                public void Fizz(int value) {}
            }
            """;
        await TestAsync(initial, expected);
    }
 
    [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveDocCommentNode)]
    public async Task RemovesParamTag_NestedInSummaryTag()
    {
        var initial =
            """
            class Program
            {
                /// <summary>
                /// <param name="value"></param>
                /// <param [|name="value"|]></param>
                /// </summary>
                public void Fizz(int value) {}
            }
            """;
 
        var expected =
            """
            class Program
            {
                /// <summary>
                /// <param name="value"></param>
                /// </summary>
                public void Fizz(int value) {}
            }
            """;
        await TestAsync(initial, expected);
    }
 
    [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveDocCommentNode)]
    public async Task RemovesParamTag_NestedInSummaryTag_WithChildren()
    {
        var initial =
            """
            class Program
            {
                /// <summary>
                ///   <param name="value"></param>
                ///   <param [|name="value"|]>
                ///     <xmlnode></xmlnode>
                ///   </param>
                /// </summary>
                public void Fizz(int value) {}
            }
            """;
 
        var expected =
            """
            class Program
            {
                /// <summary>
                ///   <param name="value"></param>
                /// </summary>
                public void Fizz(int value) {}
            }
            """;
        await TestAsync(initial, expected);
    }
 
    [Fact]
    [Trait(Traits.Feature, Traits.Features.CodeActionsFixAllOccurrences)]
    public async Task TestFixAllTypeparamInDocument_DoesNotFixDuplicateParamTags()
    {
        var initial = """
            <Workspace>
                <Project Language="C#" AssemblyName="Assembly1" CommonReferences="true" DocumentationMode="Diagnose">
                    <Document>
            <![CDATA[
            class Program1
            {
                /// <summary>
                /// 
                /// </summary>
                /// <param name="value"></param>
                /// <param name="value"></param>
                /// <typeparam name="T"></typeparam>
                /// <typeparam {|FixAllInDocument:name="T"|}></typeparam>
                /// <typeparam name="U"></typeparam>
                public void Fizz<T, U>(int value) {}
 
                /// <summary>
                /// 
                /// </summary>
                /// <param name="value"></param>
                /// <param name="value"></param>
                /// <typeparam name="T"></typeparam>
                /// <typeparam name="T"></typeparam>
                /// <typeparam name="U"></typeparam>
                /// <returns></returns>
                public int Buzz<T, U>(int value) { returns 0; }
            }]]>
                    </Document>
                    <Document>
            <![CDATA[
            class Program2
            {
                /// <summary>
                /// 
                /// </summary>
                /// <param name="value"></param>
                /// <param name="value"></param>
                public void Fizz(int value) {}
            }]]>
                    </Document>
                </Project>
                <Project Language="C#" AssemblyName="Assembly2" CommonReferences="true" DocumentationMode="Diagnose">
                    <Document>
            <![CDATA[
            class Program3
            {
                /// <summary>
                /// 
                /// </summary>
                /// <param name="value"></param>
                /// <param name="value"></param>
                public void Fizz(int value) {}
            }]]>
                    </Document>
                </Project>
            </Workspace>
            """;
 
        var expected = """
            <Workspace>
                <Project Language="C#" AssemblyName="Assembly1" CommonReferences="true" DocumentationMode="Diagnose">
                    <Document>
            <![CDATA[
            class Program1
            {
                /// <summary>
                /// 
                /// </summary>
                /// <param name="value"></param>
                /// <param name="value"></param>
                /// <typeparam name="T"></typeparam>
                /// <typeparam name="U"></typeparam>
                public void Fizz<T, U>(int value) {}
 
                /// <summary>
                /// 
                /// </summary>
                /// <param name="value"></param>
                /// <param name="value"></param>
                /// <typeparam name="T"></typeparam>
                /// <typeparam name="U"></typeparam>
                /// <returns></returns>
                public int Buzz<T, U>(int value) { returns 0; }
            }]]>
                    </Document>
                    <Document>
            <![CDATA[
            class Program2
            {
                /// <summary>
                /// 
                /// </summary>
                /// <param name="value"></param>
                /// <param name="value"></param>
                public void Fizz(int value) {}
            }]]>
                    </Document>
                </Project>
                <Project Language="C#" AssemblyName="Assembly2" CommonReferences="true" DocumentationMode="Diagnose">
                    <Document>
            <![CDATA[
            class Program3
            {
                /// <summary>
                /// 
                /// </summary>
                /// <param name="value"></param>
                /// <param name="value"></param>
                public void Fizz(int value) {}
            }]]>
                    </Document>
                </Project>
            </Workspace>
            """;
 
        await TestAsync(initial, expected);
    }
 
    [Fact]
    [Trait(Traits.Feature, Traits.Features.CodeActionsFixAllOccurrences)]
    public async Task TestFixAllInDocument()
    {
        var initial = """
            <Workspace>
                <Project Language="C#" AssemblyName="Assembly1" CommonReferences="true" DocumentationMode="Diagnose">
                    <Document>
            <![CDATA[
            class Program1
            {
                /// <summary>
                /// 
                /// </summary>
                /// <param name="value"></param>
                /// <param {|FixAllInDocument:name="value"|}></param>
                public void Fizz(int value) {}
 
                /// <summary>
                /// 
                /// </summary>
                /// <param name="value"></param>
                /// <param name="value"></param>
                /// <returns></returns>
                public int Buzz(int value) { returns 0; }
            }]]>
                    </Document>
                    <Document>
            <![CDATA[
            class Program2
            {
                /// <summary>
                /// 
                /// </summary>
                /// <param name="value"></param>
                /// <param name="value"></param>
                public void Fizz(int value) {}
            }]]>
                    </Document>
                </Project>
                <Project Language="C#" AssemblyName="Assembly2" CommonReferences="true" DocumentationMode="Diagnose">
                    <Document>
            <![CDATA[
            class Program3
            {
                /// <summary>
                /// 
                /// </summary>
                /// <param name="value"></param>
                /// <param name="value"></param>
                public void Fizz(int value) {}
            }]]>
                    </Document>
                </Project>
            </Workspace>
            """;
 
        var expected = """
            <Workspace>
                <Project Language="C#" AssemblyName="Assembly1" CommonReferences="true" DocumentationMode="Diagnose">
                    <Document>
            <![CDATA[
            class Program1
            {
                /// <summary>
                /// 
                /// </summary>
                /// <param name="value"></param>
                public void Fizz(int value) {}
 
                /// <summary>
                /// 
                /// </summary>
                /// <param name="value"></param>
                /// <returns></returns>
                public int Buzz(int value) { returns 0; }
            }]]>
                    </Document>
                    <Document>
            <![CDATA[
            class Program2
            {
                /// <summary>
                /// 
                /// </summary>
                /// <param name="value"></param>
                /// <param name="value"></param>
                public void Fizz(int value) {}
            }]]>
                    </Document>
                </Project>
                <Project Language="C#" AssemblyName="Assembly2" CommonReferences="true" DocumentationMode="Diagnose">
                    <Document>
            <![CDATA[
            class Program3
            {
                /// <summary>
                /// 
                /// </summary>
                /// <param name="value"></param>
                /// <param name="value"></param>
                public void Fizz(int value) {}
            }]]>
                    </Document>
                </Project>
            </Workspace>
            """;
 
        await TestAsync(initial, expected);
    }
 
    [Fact]
    [Trait(Traits.Feature, Traits.Features.CodeActionsFixAllOccurrences)]
    public async Task TestFixAllInProject()
    {
        var initial = """
            <Workspace>
                <Project Language="C#" AssemblyName="Assembly1" CommonReferences="true" DocumentationMode="Diagnose">
                    <Document>
            <![CDATA[
            class Program1
            {
                /// <summary>
                /// 
                /// </summary>
                /// <param name="value"></param>
                /// <param {|FixAllInProject:name="value"|}></param>
                public void Fizz(int value) {}
            }]]>
                    </Document>
                    <Document>
            <![CDATA[
            class Program2
            {
                /// <summary>
                /// 
                /// </summary>
                /// <param name="value"></param>
                /// <param name="value"></param>
                public void Fizz(int value) {}
            }]]>
                    </Document>
                </Project>
                <Project Language="C#" AssemblyName="Assembly2" CommonReferences="true" DocumentationMode="Diagnose">
                    <Document>
            <![CDATA[
            class Program3
            {
                /// <summary>
                /// 
                /// </summary>
                /// <param name="value"></param>
                /// <param name="value"></param>
                public void Fizz(int value) {}
            }]]>
                    </Document>
                </Project>
            </Workspace>
            """;
 
        var expected = """
            <Workspace>
                <Project Language="C#" AssemblyName="Assembly1" CommonReferences="true">
                    <Document>
            <![CDATA[
            class Program1
            {
                /// <summary>
                /// 
                /// </summary>
                /// <param name="value"></param>
                public void Fizz(int value) {}
            }]]>
                    </Document>
                    <Document>
            <![CDATA[
            class Program2
            {
                /// <summary>
                /// 
                /// </summary>
                /// <param name="value"></param>
                public void Fizz(int value) {}
            }]]>
                    </Document>
                </Project>
                <Project Language="C#" AssemblyName="Assembly2" CommonReferences="true">
                    <Document>
            <![CDATA[
            class Program3
            {
                /// <summary>
                /// 
                /// </summary>
                /// <param name="value"></param>
                /// <param name="value"></param>
                public void Fizz(int value) {}
            }]]>
                    </Document>
                </Project>
            </Workspace>
            """;
 
        await TestAsync(initial, expected);
    }
 
    [Fact]
    [Trait(Traits.Feature, Traits.Features.CodeActionsFixAllOccurrences)]
    public async Task TestFixAllInSolution()
    {
        var initial = """
            <Workspace>
                <Project Language="C#" AssemblyName="Assembly1" CommonReferences="true" DocumentationMode="Diagnose">
                    <Document>
            <![CDATA[
            class Program1
            {
                /// <summary>
                /// 
                /// </summary>
                /// <param name="value"></param>
                /// <param {|FixAllInSolution:name="value"|}></param>
                public void Fizz(int value) {}
            }]]>
                    </Document>
                    <Document>
            <![CDATA[
            class Program2
            {
                /// <summary>
                /// 
                /// </summary>
                /// <param name="value"></param>
                /// <param name="value"></param>
                public void Fizz(int value) {}
            }]]>
                    </Document>
                </Project>
                <Project Language="C#" AssemblyName="Assembly2" CommonReferences="true" DocumentationMode="Diagnose">
                    <Document>
            <![CDATA[
            class Program3
            {
                /// <summary>
                /// 
                /// </summary>
                /// <param name="value"></param>
                /// <param name="value"></param>
                public void Fizz(int value) {}
            }]]>
                    </Document>
                </Project>
            </Workspace>
            """;
 
        var expected = """
            <Workspace>
                <Project Language="C#" AssemblyName="Assembly1" CommonReferences="true" DocumentationMode="Diagnose">
                    <Document>
            <![CDATA[
            class Program1
            {
                /// <summary>
                /// 
                /// </summary>
                /// <param name="value"></param>
                public void Fizz(int value) {}
            }]]>
                    </Document>
                    <Document>
            <![CDATA[
            class Program2
            {
                /// <summary>
                /// 
                /// </summary>
                /// <param name="value"></param>
                public void Fizz(int value) {}
            }]]>
                    </Document>
                </Project>
                <Project Language="C#" AssemblyName="Assembly2" CommonReferences="true" DocumentationMode="Diagnose">
                    <Document>
            <![CDATA[
            class Program3
            {
                /// <summary>
                /// 
                /// </summary>
                /// <param name="value"></param>
                public void Fizz(int value) {}
            }]]>
                    </Document>
                </Project>
            </Workspace>
            """;
 
        await TestAsync(initial, expected);
    }
}