|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Razor.Language.Intermediate;
using Xunit;
namespace Microsoft.AspNetCore.Razor.Language.Components;
// These tests are really basic and cover a few different structures. The components part of this
// pass is hard to unit test, so component cases are covered by integration tests.
public class ComponentDuplicateAttributeDiagnosticPassTest
{
public ComponentDuplicateAttributeDiagnosticPassTest()
{
ProjectEngine = RazorProjectEngine.Create(
RazorConfiguration.Default,
RazorProjectFileSystem.Create(Environment.CurrentDirectory),
b =>
{
// Don't run the markup mutating passes.
b.Features.Remove(b.Features.OfType<ComponentMarkupDiagnosticPass>().Single());
b.Features.Remove(b.Features.OfType<ComponentMarkupBlockPass>().Single());
b.Features.Remove(b.Features.OfType<ComponentMarkupEncodingPass>().Single());
});
Engine = ProjectEngine.Engine;
Pass = new ComponentMarkupDiagnosticPass()
{
Engine = Engine
};
}
private RazorProjectEngine ProjectEngine { get; }
private RazorEngine Engine { get; }
private ComponentMarkupDiagnosticPass Pass { get; }
[Fact]
public void Execute_NoDuplicates()
{
// Arrange
var document = CreateDocument(@"
<html>
<head cool=""beans"">
<div></div>
<ul a=""d"" b="""" c>
<li id=""15""></li>
</ul>
</head>
</html>");
var documentNode = Lower(document);
// Act
Pass.Execute(document, documentNode);
// Assert
Assert.Empty(documentNode.GetAllDiagnostics());
}
[Fact]
public void Execute_FindDuplicate()
{
// Arrange
var document = CreateDocument(@"
<html>
<head cool=""beans"">
<div></div>
<ul a=""d"" b="""" c a=""another"">
<li id=""15""></li>
</ul>
</head>
</html>");
var documentNode = Lower(document);
// Act
Pass.Execute(document, documentNode);
// Assert
var diagnostic = Assert.Single(documentNode.GetAllDiagnostics());
Assert.Equal(ComponentDiagnosticFactory.DuplicateMarkupAttribute.Id, diagnostic.Id);
var node = documentNode.FindDescendantNodes<HtmlAttributeIntermediateNode>().Where(n => n.HasDiagnostics).Single();
Assert.Equal("a", node.AttributeName);
Assert.Equal(node.Source, diagnostic.Span);
}
[Fact]
public void Execute_FindDuplicate_CaseInsensitive()
{
// Arrange
var document = CreateDocument(@"
<html>
<head cool=""beans"">
<div></div>
<ul attr=""d"" b="""" c ATTR=""another"">
<li id=""15""></li>
</ul>
</head>
</html>");
var documentNode = Lower(document);
// Act
Pass.Execute(document, documentNode);
// Assert
var diagnostic = Assert.Single(documentNode.GetAllDiagnostics());
Assert.Equal(ComponentDiagnosticFactory.DuplicateMarkupAttribute.Id, diagnostic.Id);
var node = documentNode.FindDescendantNodes<HtmlAttributeIntermediateNode>().Where(n => n.HasDiagnostics).Single();
Assert.Equal("attr", node.AttributeName);
Assert.Equal(node.Source, diagnostic.Span);
}
[Fact]
public void Execute_FindDuplicate_Multiple()
{
// Arrange
var document = CreateDocument(@"
<html>
<head cool=""beans"">
<div></div>
<ul attr=""d"" b="""" c attr=""another"" attr>
<li id=""15""></li>
</ul>
</head>
</html>");
var documentNode = Lower(document);
// Act
Pass.Execute(document, documentNode);
// Assert
var diagnostics = documentNode.GetAllDiagnostics();
var nodes = documentNode.FindDescendantNodes<HtmlAttributeIntermediateNode>().Where(n => n.HasDiagnostics).ToArray();
Assert.Equal(2, diagnostics.Length);
Assert.Equal(2, nodes.Length);
for (var i = 0; i < 2; i++)
{
var diagnostic = diagnostics[i];
var node = nodes[i];
Assert.Equal(ComponentDiagnosticFactory.DuplicateMarkupAttribute.Id, diagnostic.Id);
Assert.Equal("attr", node.AttributeName);
Assert.Equal(node.Source, diagnostic.Span);
}
}
private RazorCodeDocument CreateDocument(string content)
{
// Normalize newlines since we are testing lengths of things.
content = content.Replace("\r", "");
content = content.Replace("\n", "\r\n");
var source = RazorSourceDocument.Create(content, "test.cshtml");
return ProjectEngine.CreateCodeDocument(source, RazorFileKind.Component);
}
private DocumentIntermediateNode Lower(RazorCodeDocument codeDocument)
{
foreach (var phase in Engine.Phases)
{
if (phase is IRazorCSharpLoweringPhase)
{
break;
}
codeDocument = phase.Execute(codeDocument);
}
var document = codeDocument.GetRequiredDocumentNode();
Engine.GetFeatures<ComponentDocumentClassifierPass>().Single().Execute(codeDocument, document);
return document;
}
}
|