File: src\Analyzers\CSharp\Tests\GenerateMethod\GenerateMethodTests_Razor.cs
Web Access
Project: src\src\CodeStyle\CSharp\Tests\Microsoft.CodeAnalysis.CSharp.CodeStyle.UnitTests.csproj (Microsoft.CodeAnalysis.CSharp.CodeStyle.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.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CSharp.CodeFixes.GenerateMethod;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;
 
namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Diagnostics.GenerateMethod;
 
public sealed partial class GenerateMethodTests
{
    private sealed record RazorGeneratedDocumentData(string HintName, string GeneratedCode);
 
    protected override void InitializeWorkspace(TestWorkspace workspace, TestParameters parameters)
    {
        if (parameters.fixProviderData is not RazorGeneratedDocumentData generatedDocument)
        {
            return;
        }
 
        var project = workspace.CurrentSolution.Projects.Single();
        var updatedProject = project.AddAnalyzerReference(
            new TestGeneratorReference(
                new Microsoft.NET.Sdk.Razor.SourceGenerators.RazorSourceGenerator(
                    context => context.AddSource(generatedDocument.HintName, generatedDocument.GeneratedCode))));
 
        Assert.True(workspace.TryApplyChanges(updatedProject.Solution));
    }
 
    private static TestParameters WithRazorGeneratedDocument(string generatedCode, string hintName = "Component.razor.g.cs")
        => new(fixProviderData: new RazorGeneratedDocumentData(hintName, generatedCode));
 
    private async Task TestGeneratingInRazorSourceGeneratedDocumentAsync(
        string workspaceMarkup,
        string generatedCode,
        string expectedGeneratedCode,
        bool requestFromSourceGeneratedDocument)
    {
        using var workspace = CreateWorkspaceFromOptions(workspaceMarkup, WithRazorGeneratedDocument(generatedCode));
 
        var project = workspace.CurrentSolution.Projects.Single();
        var sourceGeneratedDocument = Assert.Single(await project.GetSourceGeneratedDocumentsAsync(CancellationToken.None));
        Assert.Contains("Microsoft.NET.Sdk.Razor.SourceGenerators.RazorSourceGenerator", sourceGeneratedDocument.FilePath);
        Assert.StartsWith(
            "// <auto-generated />",
            (await sourceGeneratedDocument.GetTextAsync(CancellationToken.None)).ToString());
 
        var requestDocument = requestFromSourceGeneratedDocument
            ? sourceGeneratedDocument
            : project.Documents.Single();
 
        var requestTree = await requestDocument.GetSyntaxTreeAsync(CancellationToken.None);
        var compilation = await project.GetCompilationAsync(CancellationToken.None);
        Assert.NotNull(requestTree);
        Assert.NotNull(compilation);
 
        var diagnostic = Assert.Single(
            compilation!.GetDiagnostics(CancellationToken.None).Where(
                diagnostic => diagnostic.Severity == DiagnosticSeverity.Error && diagnostic.Location.SourceTree == requestTree));
 
        var codeActions = new List<CodeAction>();
        var context = new CodeFixContext(
            requestDocument,
            diagnostic.Location.SourceSpan,
            [diagnostic],
            (action, _) => codeActions.Add(action),
            CancellationToken.None);
 
        var provider = new GenerateMethodCodeFixProvider();
        await provider.RegisterCodeFixesAsync(context);
 
        var operations = await Assert.Single(codeActions).GetOperationsAsync(CancellationToken.None);
        var changedSolutions = await ApplyOperationsAndGetSolutionAsync(workspace, operations);
        var newSourceGeneratedDocument = await changedSolutions.Item2.GetSourceGeneratedDocumentAsync(sourceGeneratedDocument.Id, CancellationToken.None);
 
        Assert.NotNull(newSourceGeneratedDocument);
        AssertEx.EqualOrDiff(
            expectedGeneratedCode,
            (await newSourceGeneratedDocument!.GetTextAsync(CancellationToken.None)).ToString());
    }
 
    [Fact]
    public Task TestGeneratingIntoRazorSourceGeneratedDocumentFromRegularDocument()
        => TestGeneratingInRazorSourceGeneratedDocumentAsync(
            """
            <Workspace>
                <Project Language="C#" AssemblyName="ClassLibrary1" CommonReferences="true">
                    <Document>
            public class C
            {
                public void M()
                {
                    Component.Me$$thod();
                }
            }
                    </Document>
                </Project>
            </Workspace>
            """,
            """
            // <auto-generated />
 
            using System;
 
            public partial class Component
            {
            }
            """,
            """
            // <auto-generated />
 
            using System;
 
            public partial class Component
            {
                internal static void Method()
                {
                    throw new NotImplementedException();
                }
            }
            """,
            requestFromSourceGeneratedDocument: false);
 
    [Fact]
    public Task TestGeneratingInRazorSourceGeneratedDocument()
        => TestGeneratingInRazorSourceGeneratedDocumentAsync(
            """
            <Workspace>
                <Project Language="C#" AssemblyName="ClassLibrary1" CommonReferences="true">
                    <Document>
            public class Placeholder
            {
            }
                    </Document>
                </Project>
            </Workspace>
            """,
            """
            // <auto-generated />
 
            using System;
 
            public partial class Component
            {
                public void M()
                {
                    MissingMethod();
                }
            }
            """,
            """
            // <auto-generated />
 
            using System;
 
            public partial class Component
            {
                public void M()
                {
                    MissingMethod();
                }
 
                private void MissingMethod()
                {
                    throw new NotImplementedException();
                }
            }
            """,
            requestFromSourceGeneratedDocument: true);
 
    [Fact]
    public Task TestGeneratingIntoHiddenRazorSourceGeneratedDocumentFromRegularDocument()
        => TestGeneratingInRazorSourceGeneratedDocumentAsync(
            """
            <Workspace>
                <Project Language="C#" AssemblyName="ClassLibrary1" CommonReferences="true">
                    <Document>
            public class C
            {
                public void M()
                {
                    Component.Me$$thod();
                }
            }
                    </Document>
                </Project>
            </Workspace>
            """,
            """
            // <auto-generated />
 
            using System;
 
            #line hidden
            public partial class Component
            {
            }
            #line default
            """,
            """
            // <auto-generated />
 
            using System;
 
            #line hidden
            public partial class Component
            {
                internal static void Method()
                {
                    throw new NotImplementedException();
                }
            }
            #line default
            """,
            requestFromSourceGeneratedDocument: false);
 
    [Fact]
    public Task TestGeneratingInHiddenRazorSourceGeneratedDocument()
        => TestGeneratingInRazorSourceGeneratedDocumentAsync(
            """
            <Workspace>
                <Project Language="C#" AssemblyName="ClassLibrary1" CommonReferences="true">
                    <Document>
            public class Placeholder
            {
            }
                    </Document>
                </Project>
            </Workspace>
            """,
            """
            // <auto-generated />
 
            using System;
 
            #line hidden
            public partial class Component
            {
                public void M()
                {
                    MissingMethod();
                }
            }
            #line default
            """,
            """
            // <auto-generated />
 
            using System;
 
            #line hidden
            public partial class Component
            {
                public void M()
                {
                    MissingMethod();
                }
 
                private void MissingMethod()
                {
                    throw new NotImplementedException();
                }
            }
            #line default
            """,
            requestFromSourceGeneratedDocument: true);
}