File: IntegrationTests\ComponentDeclarationIntegrationTest.cs
Web Access
Project: src\src\Razor\src\Compiler\Microsoft.AspNetCore.Razor.Language\test\Microsoft.AspNetCore.Razor.Language.UnitTests.csproj (Microsoft.AspNetCore.Razor.Language.UnitTests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
#nullable disable
 
using System.Linq;
using Microsoft.CodeAnalysis;
using Roslyn.Test.Utilities;
using Xunit;
 
namespace Microsoft.AspNetCore.Razor.Language.IntegrationTests;
 
public class ComponentDeclarationRazorIntegrationTest : RazorIntegrationTestBase
{
    public ComponentDeclarationRazorIntegrationTest()
    {
        AdditionalSyntaxTrees.Add(Parse(AdditionalCode));
    }
 
    internal override RazorFileKind? FileKind => RazorFileKind.Component;
 
    internal override bool DeclarationOnly => true;
 
    [Fact]
    public void DeclarationConfiguration_IncludesFunctions()
    {
        // Arrange & Act
        var component = CompileToComponent(@"
@functions {
    public string Value { get; set; }
}");
 
        // Assert
        var property = component.GetMembers("Value").Single();
        AssertEx.Equal("public System.String Test.TestComponent.Value { get; set; }", property.ToTestDisplayString());
    }
 
    [Fact]
    public void DeclarationConfiguration_IncludesInject()
    {
        // Arrange & Act
        var component = CompileToComponent(@"
@inject string Value
");
 
        // Assert
        var property = component.GetMembers("Value").Single();
        AssertEx.Equal("private System.String Test.TestComponent.Value { get; set; }", property.ToTestDisplayString());
    }
 
    [Fact]
    public void DeclarationConfiguration_IncludesUsings()
    {
        // Arrange & Act
        var component = CompileToComponent(@"
@using System.Text
@inject StringBuilder Value
");
 
        // Assert
        var property = component.GetMembers("Value").Single();
        AssertEx.Equal("private System.Text.StringBuilder Test.TestComponent.Value { get; set; }", property.ToTestDisplayString());
    }
 
    [Fact]
    public void DeclarationConfiguration_IncludesInherits()
    {
        // Arrange & Act
        var component = CompileToComponent(@"
@inherits TestNamespace.BaseClass
");
 
        // Assert
        AssertEx.Equal("Test.TestComponent", component.ToTestDisplayString());
        AssertEx.Equal("TestNamespace.BaseClass", component.BaseType.ToTestDisplayString());
    }
 
    [Fact]
    public void DeclarationConfiguration_IncludesImplements()
    {
        // Arrange & Act
        var component = CompileToComponent(@"
@implements TestNamespace.IDoCoolThings
");
 
        // Assert
        AssertEx.Equal("Test.TestComponent", component.ToTestDisplayString());
        AssertEx.Equal("TestNamespace.IDoCoolThings", component.Interfaces.Single().ToTestDisplayString());
    }
 
    [Fact, WorkItem("https://github.com/dotnet/blazor/issues/453")]
    public void DeclarationConfiguration_FunctionsBlockHasLineMappings_MappingsApplyToError()
    {
        // Arrange & Act 1
        var generated = CompileToCSharp(@"
@functions {
    public StringBuilder Builder { get; set; }
}
");
 
        // Assert 1
        AssertSourceEquals(@"
// <auto-generated/>
#pragma warning disable 1591
#pragma warning disable 0414
#pragma warning disable 0649
#pragma warning disable 0169
 
namespace Test
{
    #line default
    using global::System;
    using global::System.Collections.Generic;
    using global::System.Linq;
    using global::System.Threading.Tasks;
    using global::Microsoft.AspNetCore.Components;
    #line default
    #line hidden
    #nullable restore
    public partial class TestComponent : global::Microsoft.AspNetCore.Components.ComponentBase
    #nullable disable
    {
        #pragma warning disable 1998
        protected override void BuildRenderTree(global::Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder)
        {
        }
        #pragma warning restore 1998
#nullable restore
#line (1,13)-(3,1) ""x:\dir\subdir\Test\TestComponent.cshtml""
 
    public StringBuilder Builder { get; set; }
 
#line default
#line hidden
#nullable disable
 
    }
}
#pragma warning restore 1591
", generated);
 
        // Act 2
        CompileToAssembly(generated,
            // /dir/subdir/Test/TestComponent.cshtml(2,12): error CS0246: The type or namespace name 'StringBuilder' could not be found (are you missing a using directive or an assembly reference?)
            //     public StringBuilder Builder { get; set; }
            Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "StringBuilder").WithArguments("StringBuilder").WithLocation(2, 12));
    }
 
    private const string AdditionalCode =
    """
    using Microsoft.AspNetCore.Components;
    using Microsoft.AspNetCore.Components.Rendering;
    using System.Threading.Tasks;
 
    namespace TestNamespace;
 
    public class BaseClass : IComponent
    {
        public void Attach(RenderHandle renderHandle)
        {
        }
 
        protected virtual void BuildRenderTree(RenderTreeBuilder builder)
        {
        }
 
        public Task SetParametersAsync(ParameterView parameters)
        {
            throw new System.NotImplementedException();
        }
    }
 
    public interface IDoCoolThings
    {
    }
    """;
 
    [Fact]
    public void DeclarationConfiguration_IncludesUtf8StringLiterals()
    {
        // Arrange & Act
        var component = CompileToComponent(""""
@using System.Text
@code {
    private ReadOnlySpan<byte> GetUtf8Data()
    {
        return "hello"u8;
    }
    
    private void ProcessData()
    {
        ReadOnlySpan<byte> data = "world"U8;
        var result = Encoding.UTF8.GetString(data);
    }
    
    private ReadOnlySpan<byte> GetRawUtf8Data()
    {
        return """raw string"""u8;
    }
}
"""");
 
        // Assert - Should compile without RZ1000 errors
        var method = component.GetMembers("GetUtf8Data").Single();
        AssertEx.Equal("private System.ReadOnlySpan<System.Byte> Test.TestComponent.GetUtf8Data()", method.ToTestDisplayString());
    }
}