|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Globalization;
using Microsoft.AspNetCore.Razor.Language.Components;
using Microsoft.CodeAnalysis.CSharp;
using Xunit;
namespace Microsoft.AspNetCore.Razor.Language.IntegrationTests;
public class ComponentChildContentIntegrationTest : RazorIntegrationTestBase
{
private readonly CSharpSyntaxTree RenderChildContentComponent = Parse(@"
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Rendering;
namespace Test
{
public class RenderChildContent : ComponentBase
{
protected override void BuildRenderTree(RenderTreeBuilder builder)
{
builder.AddContent(0, ChildContent);
}
[Parameter]
public RenderFragment ChildContent { get; set; }
}
}
");
private readonly CSharpSyntaxTree RenderChildContentStringComponent = Parse(@"
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Rendering;
namespace Test
{
public class RenderChildContentString : ComponentBase
{
protected override void BuildRenderTree(RenderTreeBuilder builder)
{
builder.AddContent(0, ChildContent, Value);
}
[Parameter]
public RenderFragment<string> ChildContent { get; set; }
[Parameter]
public string Value { get; set; }
}
}
");
internal override RazorFileKind? FileKind => RazorFileKind.Component;
internal override bool UseTwoPhaseCompilation => true;
[Fact]
public void ChildContent_AttributeAndBody_ProducesDiagnostic()
{
// Arrange
AdditionalSyntaxTrees.Add(RenderChildContentComponent);
// Act
var generated = CompileToCSharp(@"
@{ RenderFragment<string> template = @<div>@context.ToLowerInvariant()</div>; }
<RenderChildContent ChildContent=""@template.WithValue(""HI"")"">
Some Content
</RenderChildContent>");
// Assert
var diagnostic = Assert.Single(generated.RazorDiagnostics);
Assert.Same(ComponentDiagnosticFactory.ChildContentSetByAttributeAndBody.Id, diagnostic.Id);
}
[Fact]
public void ChildContent_AttributeAndExplicitChildContent_ProducesDiagnostic()
{
// Arrange
AdditionalSyntaxTrees.Add(RenderChildContentComponent);
// Act
var generated = CompileToCSharp(@"
@{ RenderFragment<string> template = @<div>@context.ToLowerInvariant()</div>; }
<RenderChildContent ChildContent=""@template.WithValue(""HI"")"">
<ChildContent>
Some Content
</ChildContent>
</RenderChildContent>");
// Assert
var diagnostic = Assert.Single(generated.RazorDiagnostics);
Assert.Same(ComponentDiagnosticFactory.ChildContentSetByAttributeAndBody.Id, diagnostic.Id);
}
[Fact]
public void ChildContent_ExplicitChildContent_UnrecogizedContent_ProducesDiagnostic()
{
// Arrange
AdditionalSyntaxTrees.Add(RenderChildContentComponent);
// Act
var generated = CompileToCSharp(@"
<RenderChildContent>
<ChildContent>
</ChildContent>
@somethingElse
</RenderChildContent>");
// Assert
var diagnostic = Assert.Single(generated.RazorDiagnostics);
Assert.Same(ComponentDiagnosticFactory.ChildContentMixedWithExplicitChildContent.Id, diagnostic.Id);
Assert.Equal("""
Unrecognized child content inside component 'RenderChildContent'. The component 'RenderChildContent' accepts child content through the following top-level items: 'ChildContent'.
""",
diagnostic.GetMessage(CultureInfo.CurrentCulture));
}
[Theory]
[InlineData(true)]
[InlineData(false)]
public void ChildContent_ExplicitChildContent_UnrecogizedElement_ProducesDiagnostic(bool supportLocalizedComponentNames)
{
// Arrange
AdditionalSyntaxTrees.Add(RenderChildContentComponent);
// Act
var generated = CompileToCSharp(@"
<RenderChildContent>
<ChildContent>
</ChildContent>
<UnrecognizedChildContent></UnrecognizedChildContent>
</RenderChildContent>", supportLocalizedComponentNames: supportLocalizedComponentNames);
// Assert
Assert.Collection(
generated.RazorDiagnostics,
d => Assert.Equal("RZ10012", d.Id),
d => Assert.Equal("RZ9996", d.Id));
}
[Fact]
public void ChildContent_ExplicitChildContent_StartsWithCharThatIsOtherLetterCategory_WhenLocalizedComponentNamesIsAllowed()
{
// Arrange
AdditionalSyntaxTrees.Add(RenderChildContentComponent);
// Act
var generated = CompileToCSharp(@$"
<RenderChildContent>
<ChildContent>
</ChildContent>
<繁体字></繁体字>
</RenderChildContent>", supportLocalizedComponentNames: true);
// Assert
Assert.Collection(
generated.RazorDiagnostics,
d => Assert.Equal("RZ10012", d.Id),
d => Assert.Equal("RZ9996", d.Id));
}
[Fact]
public void ChildContent_ExplicitChildContent_StartsWithCharThatIsOtherLetterCategory_WhenLocalizedComponentNamesIsDisallowed()
{
// Arrange
AdditionalSyntaxTrees.Add(RenderChildContentComponent);
// Act
var generated = CompileToCSharp(@$"
<RenderChildContent>
<ChildContent>
</ChildContent>
<繁体字></繁体字>
</RenderChildContent>", supportLocalizedComponentNames: false);
// Assert
Assert.Collection(
generated.RazorDiagnostics,
d => Assert.Equal("RZ9996", d.Id));
}
[Fact]
public void ChildContent_ExplicitChildContent_UnrecogizedAttribute_ProducesDiagnostic()
{
// Arrange
AdditionalSyntaxTrees.Add(RenderChildContentComponent);
// Act
var generated = CompileToCSharp(@"
<RenderChildContent>
<ChildContent attr>
</ChildContent>
</RenderChildContent>");
// Assert
var diagnostic = Assert.Single(generated.RazorDiagnostics);
Assert.Same(ComponentDiagnosticFactory.ChildContentHasInvalidAttribute.Id, diagnostic.Id);
}
[Fact]
public void ChildContent_ExplicitChildContent_InvalidParameterName_ProducesDiagnostic()
{
// Arrange
AdditionalSyntaxTrees.Add(RenderChildContentStringComponent);
// Act
var generated = CompileToCSharp(@"
<RenderChildContentString>
<ChildContent Context=""@(""HI"")"">
</ChildContent>
</RenderChildContentString>");
// Assert
var diagnostic = Assert.Single(generated.RazorDiagnostics);
Assert.Same(ComponentDiagnosticFactory.ChildContentHasInvalidParameter.Id, diagnostic.Id);
}
[Fact]
public void ChildContent_ExplicitChildContent_RepeatedParameterName_GeneratesDiagnostic()
{
// Arrange
AdditionalSyntaxTrees.Add(RenderChildContentStringComponent);
// Act
var generated = CompileToCSharp(@"
<RenderChildContentString>
<ChildContent>
<RenderChildContentString>
<ChildContent Context=""context"">
</ChildContent>
</RenderChildContentString>
</ChildContent>
</RenderChildContentString>");
// Assert
var diagnostic = Assert.Single(generated.RazorDiagnostics);
Assert.Same(ComponentDiagnosticFactory.ChildContentRepeatedParameterName.Id, diagnostic.Id);
Assert.Equal("""
The child content element 'ChildContent' of component 'RenderChildContentString' uses the same parameter name ('context') as enclosing child content element 'ChildContent' of component 'RenderChildContentString'. Specify the parameter name like: '<ChildContent Context="another_name"> to resolve the ambiguity
""",
diagnostic.GetMessage(CultureInfo.CurrentCulture));
}
[Fact]
public void ChildContent_ContextParameterNameOnComponent_Invalid_ProducesDiagnostic()
{
// Arrange
AdditionalSyntaxTrees.Add(RenderChildContentStringComponent);
// Act
var generated = CompileToCSharp(@"
<RenderChildContentString Context=""@Foo()"">
</RenderChildContentString>");
// Assert
var diagnostic = Assert.Single(generated.RazorDiagnostics);
Assert.Same(ComponentDiagnosticFactory.ChildContentHasInvalidParameterOnComponent.Id, diagnostic.Id);
Assert.Equal(
"Invalid parameter name. The parameter name attribute 'Context' on component 'RenderChildContentString' can only include literal text.",
diagnostic.GetMessage(CultureInfo.CurrentCulture));
}
[Fact]
public void ChildContent_ExplicitChildContent_ContainsDirectiveAttribute_ProducesDiagnostic()
{
// Arrange
AdditionalSyntaxTrees.Add(RenderChildContentStringComponent);
// Act
var generated = CompileToCSharp(@"
<RenderChildContentString>
<ChildContent Context=""items"" @key=""Hello"">
</ChildContent>
</RenderChildContentString>");
// Assert
var diagnostic = Assert.Single(generated.RazorDiagnostics);
Assert.Same(ComponentDiagnosticFactory.ChildContentHasInvalidAttribute.Id, diagnostic.Id);
Assert.Equal(
"Unrecognized attribute '@key' on child content element 'ChildContent'.",
diagnostic.GetMessage(CultureInfo.CurrentCulture));
}
}
|