Generate the class name from relative path
This commit is contained in:
parent
44048331e9
commit
eb820106e2
|
|
@ -1,4 +1,7 @@
|
|||
using System.Globalization;
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Globalization;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.Razor.Internal
|
||||
|
|
|
|||
|
|
@ -0,0 +1,34 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Razor.Evolution;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.Razor.Internal
|
||||
{
|
||||
public static class RazorCodeDocumentExtensions
|
||||
{
|
||||
private const string RelativePathKey = "relative-path";
|
||||
|
||||
public static string GetRelativePath(this RazorCodeDocument document)
|
||||
{
|
||||
if (document == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(document));
|
||||
}
|
||||
|
||||
return document.Items[RelativePathKey] as string;
|
||||
}
|
||||
|
||||
|
||||
public static void SetRelativePath(this RazorCodeDocument document, string relativePath)
|
||||
{
|
||||
if (document == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(document));
|
||||
}
|
||||
|
||||
document.Items[RelativePathKey] = relativePath;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -46,7 +46,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Host
|
|||
}
|
||||
}
|
||||
|
||||
if (document.DocumentKind == RazorPageDocumentClassifier.RazorPageDocumentKind)
|
||||
if (document.DocumentKind == RazorPageDocumentClassifierPass.RazorPageDocumentKind)
|
||||
{
|
||||
return visitor.Class.Name;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,9 +21,11 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Host
|
|||
ClassDeclarationIRNode @class,
|
||||
RazorMethodDeclarationIRNode method)
|
||||
{
|
||||
var filePath = codeDocument.GetRelativePath() ?? codeDocument.Source.Filename;
|
||||
|
||||
base.OnDocumentStructureCreated(codeDocument, @namespace, @class, method);
|
||||
@class.Name = ClassName.GetClassNameFromPath(codeDocument.Source.Filename);
|
||||
@class.BaseType = "Microsoft.AspNetCore.Mvc.Razor.RazorPage<TModel>";
|
||||
@class.Name = ClassName.GetClassNameFromPath(filePath);
|
||||
@class.BaseType = "global::Microsoft.AspNetCore.Mvc.Razor.RazorPage<TModel>";
|
||||
@class.AccessModifier = "public";
|
||||
@namespace.Content = "AspNetCore";
|
||||
method.Name = "ExecuteAsync";
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Host
|
|||
|
||||
public DocumentIRNode Execute(RazorCodeDocument codeDocument, DocumentIRNode irDocument)
|
||||
{
|
||||
if (irDocument.DocumentKind != RazorPageDocumentClassifier.RazorPageDocumentKind)
|
||||
if (irDocument.DocumentKind != RazorPageDocumentClassifierPass.RazorPageDocumentKind)
|
||||
{
|
||||
return irDocument;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ using Microsoft.AspNetCore.Razor.Evolution.Intermediate;
|
|||
|
||||
namespace Microsoft.AspNetCore.Mvc.Razor.Host
|
||||
{
|
||||
public class RazorPageDocumentClassifier : DocumentClassifierPassBase
|
||||
public class RazorPageDocumentClassifierPass : DocumentClassifierPassBase
|
||||
{
|
||||
public static readonly string RazorPageDocumentKind = "mvc.1.0.razor-page";
|
||||
|
||||
|
|
@ -19,11 +19,17 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Host
|
|||
return PageDirective.TryGetRouteTemplate(irDocument, out routePrefix);
|
||||
}
|
||||
|
||||
protected override void OnDocumentStructureCreated(RazorCodeDocument codeDocument, NamespaceDeclarationIRNode @namespace, ClassDeclarationIRNode @class, RazorMethodDeclarationIRNode method)
|
||||
protected override void OnDocumentStructureCreated(
|
||||
RazorCodeDocument codeDocument,
|
||||
NamespaceDeclarationIRNode @namespace,
|
||||
ClassDeclarationIRNode @class,
|
||||
RazorMethodDeclarationIRNode method)
|
||||
{
|
||||
var filePath = codeDocument.GetRelativePath() ?? codeDocument.Source.Filename;
|
||||
|
||||
base.OnDocumentStructureCreated(codeDocument, @namespace, @class, method);
|
||||
@class.BaseType = "Microsoft.AspNetCore.Mvc.RazorPages.Page";
|
||||
@class.Name = ClassName.GetClassNameFromPath(codeDocument.Source.Filename);
|
||||
@class.BaseType = "global::Microsoft.AspNetCore.Mvc.RazorPages.Page";
|
||||
@class.Name = ClassName.GetClassNameFromPath(filePath);
|
||||
@class.AccessModifier = "public";
|
||||
@namespace.Content = "AspNetCore";
|
||||
method.Name = "ExecuteAsync";
|
||||
|
|
@ -188,7 +188,7 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
b.Features.Add(new ModelExpressionPass());
|
||||
b.Features.Add(new PagesPropertyInjectionPass());
|
||||
b.Features.Add(new ViewComponentTagHelperPass());
|
||||
b.Features.Add(new RazorPageDocumentClassifier());
|
||||
b.Features.Add(new RazorPageDocumentClassifierPass());
|
||||
b.Features.Add(new MvcViewDocumentClassifierPass());
|
||||
b.Features.Add(new DefaultInstrumentationPass());
|
||||
|
||||
|
|
|
|||
|
|
@ -124,7 +124,9 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal
|
|||
}
|
||||
}
|
||||
|
||||
return RazorCodeDocument.Create(source, imports);
|
||||
var codeDocument = RazorCodeDocument.Create(source, imports);
|
||||
codeDocument.SetRelativePath(relativePath);
|
||||
return codeDocument;
|
||||
}
|
||||
|
||||
public virtual RazorCSharpDocument ProcessCodeDocument(RazorCodeDocument codeDocument)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,246 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Microsoft.AspNetCore.Mvc.Razor.Internal;
|
||||
using Microsoft.AspNetCore.Razor.Evolution;
|
||||
using Microsoft.AspNetCore.Razor.Evolution.Intermediate;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.Razor.Host
|
||||
{
|
||||
public class MvcViewDocumentClassifierPassTest
|
||||
{
|
||||
[Fact]
|
||||
public void MvcViewDocumentClassifierPass_SetsDocumentKind()
|
||||
{
|
||||
// Arrange
|
||||
var codeDocument = CreateDocument("some-content");
|
||||
var engine = CreateEngine();
|
||||
var irDocument = CreateIRDocument(engine, codeDocument);
|
||||
var pass = new MvcViewDocumentClassifierPass
|
||||
{
|
||||
Engine = engine
|
||||
};
|
||||
|
||||
// Act
|
||||
pass.Execute(codeDocument, irDocument);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("mvc.1.0.view", irDocument.DocumentKind);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MvcViewDocumentClassifierPass_NoOpsIfDocumentKindIsAlreadySet()
|
||||
{
|
||||
// Arrange
|
||||
var codeDocument = CreateDocument("some-content");
|
||||
var engine = CreateEngine();
|
||||
var irDocument = CreateIRDocument(engine, codeDocument);
|
||||
irDocument.DocumentKind = "some-value";
|
||||
var pass = new MvcViewDocumentClassifierPass
|
||||
{
|
||||
Engine = engine
|
||||
};
|
||||
|
||||
// Act
|
||||
pass.Execute(codeDocument, irDocument);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("some-value", irDocument.DocumentKind);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MvcViewDocumentClassifierPass_SetsNamespace()
|
||||
{
|
||||
// Arrange
|
||||
var codeDocument = CreateDocument("some-content");
|
||||
var engine = CreateEngine();
|
||||
var irDocument = CreateIRDocument(engine, codeDocument);
|
||||
var pass = new MvcViewDocumentClassifierPass
|
||||
{
|
||||
Engine = engine
|
||||
};
|
||||
|
||||
// Act
|
||||
pass.Execute(codeDocument, irDocument);
|
||||
var visitor = new Visitor();
|
||||
visitor.Visit(irDocument);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("AspNetCore", visitor.Namespace.Content);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MvcViewDocumentClassifierPass_SetsClass()
|
||||
{
|
||||
// Arrange
|
||||
var codeDocument = CreateDocument("some-content");
|
||||
var engine = CreateEngine();
|
||||
var irDocument = CreateIRDocument(engine, codeDocument);
|
||||
var pass = new MvcViewDocumentClassifierPass
|
||||
{
|
||||
Engine = engine
|
||||
};
|
||||
codeDocument.SetRelativePath("Test.cshtml");
|
||||
|
||||
// Act
|
||||
pass.Execute(codeDocument, irDocument);
|
||||
var visitor = new Visitor();
|
||||
visitor.Visit(irDocument);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("global::Microsoft.AspNetCore.Mvc.Razor.RazorPage<TModel>", visitor.Class.BaseType);
|
||||
Assert.Equal("public", visitor.Class.AccessModifier);
|
||||
Assert.Equal("Test_cshtml", visitor.Class.Name);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("/Views/Home/Index.cshtml", "_Views_Home_Index_cshtml")]
|
||||
[InlineData("/Areas/MyArea/Views/Home/About.cshtml", "_Areas_MyArea_Views_Home_About_cshtml")]
|
||||
public void MvcViewDocumentClassifierPass_UsesRelativePathToGenerateTypeName(string relativePath, string expected)
|
||||
{
|
||||
// Arrange
|
||||
var codeDocument = CreateDocument("some-content");
|
||||
codeDocument.SetRelativePath(relativePath);
|
||||
var engine = CreateEngine();
|
||||
var irDocument = CreateIRDocument(engine, codeDocument);
|
||||
var pass = new MvcViewDocumentClassifierPass
|
||||
{
|
||||
Engine = engine
|
||||
};
|
||||
|
||||
// Act
|
||||
pass.Execute(codeDocument, irDocument);
|
||||
var visitor = new Visitor();
|
||||
visitor.Visit(irDocument);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expected, visitor.Class.Name);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MvcViewDocumentClassifierPass_UsesAbsolutePath_IfRelativePathIsNotSet()
|
||||
{
|
||||
// Arrange
|
||||
var expected = "x___application_Views_Home_Index_cshtml";
|
||||
var path = @"x::\application\Views\Home\Index.cshtml";
|
||||
var codeDocument = CreateDocument("some-content", path);
|
||||
var engine = CreateEngine();
|
||||
var irDocument = CreateIRDocument(engine, codeDocument);
|
||||
var pass = new MvcViewDocumentClassifierPass
|
||||
{
|
||||
Engine = engine
|
||||
};
|
||||
|
||||
// Act
|
||||
pass.Execute(codeDocument, irDocument);
|
||||
var visitor = new Visitor();
|
||||
visitor.Visit(irDocument);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expected, visitor.Class.Name);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MvcViewDocumentClassifierPass_SanitizesClassName()
|
||||
{
|
||||
// Arrange
|
||||
var expected = "path_with_invalid_chars";
|
||||
var codeDocument = CreateDocument("some-content");
|
||||
codeDocument.SetRelativePath("path.with+invalid-chars");
|
||||
var engine = CreateEngine();
|
||||
var irDocument = CreateIRDocument(engine, codeDocument);
|
||||
var pass = new MvcViewDocumentClassifierPass
|
||||
{
|
||||
Engine = engine
|
||||
};
|
||||
|
||||
// Act
|
||||
pass.Execute(codeDocument, irDocument);
|
||||
var visitor = new Visitor();
|
||||
visitor.Visit(irDocument);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expected, visitor.Class.Name);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MvcViewDocumentClassifierPass_SetsUpExecuteAsyncMethod()
|
||||
{
|
||||
// Arrange
|
||||
var codeDocument = CreateDocument("some-content");
|
||||
var engine = CreateEngine();
|
||||
var irDocument = CreateIRDocument(engine, codeDocument);
|
||||
var pass = new MvcViewDocumentClassifierPass
|
||||
{
|
||||
Engine = engine
|
||||
};
|
||||
|
||||
// Act
|
||||
pass.Execute(codeDocument, irDocument);
|
||||
var visitor = new Visitor();
|
||||
visitor.Visit(irDocument);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("ExecuteAsync", visitor.Method.Name);
|
||||
Assert.Equal("public", visitor.Method.AccessModifier);
|
||||
Assert.Equal("global::System.Threading.Tasks.Task", visitor.Method.ReturnType);
|
||||
Assert.Equal(new[] { "async", "override" }, visitor.Method.Modifiers);
|
||||
}
|
||||
|
||||
private static RazorCodeDocument CreateDocument(string content, string filePath = null)
|
||||
{
|
||||
filePath = filePath ?? Path.Combine(Directory.GetCurrentDirectory(), "Test.cshtml");
|
||||
|
||||
var bytes = Encoding.UTF8.GetBytes(content);
|
||||
using (var stream = new MemoryStream(bytes))
|
||||
{
|
||||
var source = RazorSourceDocument.ReadFrom(stream, filePath);
|
||||
return RazorCodeDocument.Create(source);
|
||||
}
|
||||
}
|
||||
|
||||
private static RazorEngine CreateEngine() => RazorEngine.Create();
|
||||
|
||||
private static DocumentIRNode CreateIRDocument(RazorEngine engine, RazorCodeDocument codeDocument)
|
||||
{
|
||||
var phases = engine.Phases.TakeWhile(p => !(p is IRazorIRPhase));
|
||||
|
||||
foreach (var phase in phases)
|
||||
{
|
||||
phase.Execute(codeDocument);
|
||||
}
|
||||
|
||||
return codeDocument.GetIRDocument();
|
||||
}
|
||||
|
||||
private class Visitor : RazorIRNodeWalker
|
||||
{
|
||||
public NamespaceDeclarationIRNode Namespace { get; private set; }
|
||||
|
||||
public ClassDeclarationIRNode Class { get; private set; }
|
||||
|
||||
public RazorMethodDeclarationIRNode Method { get; private set; }
|
||||
|
||||
public override void VisitRazorMethodDeclaration(RazorMethodDeclarationIRNode node)
|
||||
{
|
||||
Method = node;
|
||||
}
|
||||
|
||||
public override void VisitNamespace(NamespaceDeclarationIRNode node)
|
||||
{
|
||||
Namespace = node;
|
||||
base.VisitNamespace(node);
|
||||
}
|
||||
|
||||
public override void VisitClass(ClassDeclarationIRNode node)
|
||||
{
|
||||
Class = node;
|
||||
base.VisitClass(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,272 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Microsoft.AspNetCore.Mvc.Razor.Internal;
|
||||
using Microsoft.AspNetCore.Razor.Evolution;
|
||||
using Microsoft.AspNetCore.Razor.Evolution.Intermediate;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.Razor.Host
|
||||
{
|
||||
public class RazorPageDocumentClassifierPassTest
|
||||
{
|
||||
[Fact]
|
||||
public void RazorPageDocumentClassifierPass_SetsDocumentKind()
|
||||
{
|
||||
// Arrange
|
||||
var codeDocument = CreateDocument("@page");
|
||||
var engine = CreateEngine();
|
||||
var irDocument = CreateIRDocument(engine, codeDocument);
|
||||
var pass = new RazorPageDocumentClassifierPass
|
||||
{
|
||||
Engine = engine
|
||||
};
|
||||
|
||||
// Act
|
||||
pass.Execute(codeDocument, irDocument);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("mvc.1.0.razor-page", irDocument.DocumentKind);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RazorPageDocumentClassifierPass_NoOpsIfDocumentKindIsAlreadySet()
|
||||
{
|
||||
// Arrange
|
||||
var codeDocument = CreateDocument("@page");
|
||||
var engine = CreateEngine();
|
||||
var irDocument = CreateIRDocument(engine, codeDocument);
|
||||
irDocument.DocumentKind = "some-value";
|
||||
var pass = new RazorPageDocumentClassifierPass
|
||||
{
|
||||
Engine = engine
|
||||
};
|
||||
|
||||
// Act
|
||||
pass.Execute(codeDocument, irDocument);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("some-value", irDocument.DocumentKind);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RazorPageDocumentClassifierPass_NoOpsIfPageDirectiveIsMalformed()
|
||||
{
|
||||
// Arrange
|
||||
var codeDocument = CreateDocument("@page+1");
|
||||
var engine = CreateEngine();
|
||||
var irDocument = CreateIRDocument(engine, codeDocument);
|
||||
irDocument.DocumentKind = "some-value";
|
||||
var pass = new RazorPageDocumentClassifierPass
|
||||
{
|
||||
Engine = engine
|
||||
};
|
||||
|
||||
// Act
|
||||
pass.Execute(codeDocument, irDocument);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("some-value", irDocument.DocumentKind);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RazorPageDocumentClassifierPass_SetsNamespace()
|
||||
{
|
||||
// Arrange
|
||||
var codeDocument = CreateDocument("@page");
|
||||
var engine = CreateEngine();
|
||||
var irDocument = CreateIRDocument(engine, codeDocument);
|
||||
var pass = new RazorPageDocumentClassifierPass
|
||||
{
|
||||
Engine = engine
|
||||
};
|
||||
|
||||
// Act
|
||||
pass.Execute(codeDocument, irDocument);
|
||||
var visitor = new Visitor();
|
||||
visitor.Visit(irDocument);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("AspNetCore", visitor.Namespace.Content);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RazorPageDocumentClassifierPass_SetsClass()
|
||||
{
|
||||
// Arrange
|
||||
var codeDocument = CreateDocument("@page");
|
||||
var engine = CreateEngine();
|
||||
var irDocument = CreateIRDocument(engine, codeDocument);
|
||||
var pass = new RazorPageDocumentClassifierPass
|
||||
{
|
||||
Engine = engine
|
||||
};
|
||||
codeDocument.SetRelativePath("Test.cshtml");
|
||||
|
||||
// Act
|
||||
pass.Execute(codeDocument, irDocument);
|
||||
var visitor = new Visitor();
|
||||
visitor.Visit(irDocument);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("global::Microsoft.AspNetCore.Mvc.RazorPages.Page", visitor.Class.BaseType);
|
||||
Assert.Equal("public", visitor.Class.AccessModifier);
|
||||
Assert.Equal("Test_cshtml", visitor.Class.Name);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("/Views/Home/Index.cshtml", "_Views_Home_Index_cshtml")]
|
||||
[InlineData("/Areas/MyArea/Views/Home/About.cshtml", "_Areas_MyArea_Views_Home_About_cshtml")]
|
||||
public void RazorPageDocumentClassifierPass_UsesRelativePathToGenerateTypeName(string relativePath, string expected)
|
||||
{
|
||||
// Arrange
|
||||
var codeDocument = CreateDocument("@page");
|
||||
codeDocument.SetRelativePath(relativePath);
|
||||
var engine = CreateEngine();
|
||||
var irDocument = CreateIRDocument(engine, codeDocument);
|
||||
var pass = new RazorPageDocumentClassifierPass
|
||||
{
|
||||
Engine = engine
|
||||
};
|
||||
|
||||
// Act
|
||||
pass.Execute(codeDocument, irDocument);
|
||||
var visitor = new Visitor();
|
||||
visitor.Visit(irDocument);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expected, visitor.Class.Name);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RazorPageDocumentClassifierPass_UsesAbsolutePath_IfRelativePathIsNotSet()
|
||||
{
|
||||
// Arrange
|
||||
var expected = "x___application_Views_Home_Index_cshtml";
|
||||
var path = @"x::\application\Views\Home\Index.cshtml";
|
||||
var codeDocument = CreateDocument("@page", path);
|
||||
var engine = CreateEngine();
|
||||
var irDocument = CreateIRDocument(engine, codeDocument);
|
||||
var pass = new RazorPageDocumentClassifierPass
|
||||
{
|
||||
Engine = engine
|
||||
};
|
||||
|
||||
// Act
|
||||
pass.Execute(codeDocument, irDocument);
|
||||
var visitor = new Visitor();
|
||||
visitor.Visit(irDocument);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expected, visitor.Class.Name);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RazorPageDocumentClassifierPass_SanitizesClassName()
|
||||
{
|
||||
// Arrange
|
||||
var expected = "path_with_invalid_chars";
|
||||
var codeDocument = CreateDocument("@page");
|
||||
codeDocument.SetRelativePath("path.with+invalid-chars");
|
||||
var engine = CreateEngine();
|
||||
var irDocument = CreateIRDocument(engine, codeDocument);
|
||||
var pass = new RazorPageDocumentClassifierPass
|
||||
{
|
||||
Engine = engine
|
||||
};
|
||||
|
||||
// Act
|
||||
pass.Execute(codeDocument, irDocument);
|
||||
var visitor = new Visitor();
|
||||
visitor.Visit(irDocument);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expected, visitor.Class.Name);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RazorPageDocumentClassifierPass_SetsUpExecuteAsyncMethod()
|
||||
{
|
||||
// Arrange
|
||||
var codeDocument = CreateDocument("@page");
|
||||
var engine = CreateEngine();
|
||||
var irDocument = CreateIRDocument(engine, codeDocument);
|
||||
var pass = new RazorPageDocumentClassifierPass
|
||||
{
|
||||
Engine = engine
|
||||
};
|
||||
|
||||
// Act
|
||||
pass.Execute(codeDocument, irDocument);
|
||||
var visitor = new Visitor();
|
||||
visitor.Visit(irDocument);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("ExecuteAsync", visitor.Method.Name);
|
||||
Assert.Equal("public", visitor.Method.AccessModifier);
|
||||
Assert.Equal("global::System.Threading.Tasks.Task", visitor.Method.ReturnType);
|
||||
Assert.Equal(new[] { "async", "override" }, visitor.Method.Modifiers);
|
||||
}
|
||||
|
||||
private static RazorCodeDocument CreateDocument(string content, string filePath = null)
|
||||
{
|
||||
filePath = filePath ?? Path.Combine(Directory.GetCurrentDirectory(), "Test.cshtml");
|
||||
|
||||
var bytes = Encoding.UTF8.GetBytes(content);
|
||||
using (var stream = new MemoryStream(bytes))
|
||||
{
|
||||
var source = RazorSourceDocument.ReadFrom(stream, filePath);
|
||||
return RazorCodeDocument.Create(source);
|
||||
}
|
||||
}
|
||||
|
||||
private static RazorEngine CreateEngine()
|
||||
{
|
||||
return RazorEngine.Create(b =>
|
||||
{
|
||||
PageDirective.Register(b);
|
||||
});
|
||||
}
|
||||
|
||||
private static DocumentIRNode CreateIRDocument(RazorEngine engine, RazorCodeDocument codeDocument)
|
||||
{
|
||||
var phases = engine.Phases.TakeWhile(p => !(p is IRazorIRPhase));
|
||||
|
||||
foreach (var phase in phases)
|
||||
{
|
||||
phase.Execute(codeDocument);
|
||||
}
|
||||
|
||||
return codeDocument.GetIRDocument();
|
||||
}
|
||||
|
||||
private class Visitor : RazorIRNodeWalker
|
||||
{
|
||||
public NamespaceDeclarationIRNode Namespace { get; private set; }
|
||||
|
||||
public ClassDeclarationIRNode Class { get; private set; }
|
||||
|
||||
public RazorMethodDeclarationIRNode Method { get; private set; }
|
||||
|
||||
public override void VisitRazorMethodDeclaration(RazorMethodDeclarationIRNode node)
|
||||
{
|
||||
Method = node;
|
||||
}
|
||||
|
||||
public override void VisitNamespace(NamespaceDeclarationIRNode node)
|
||||
{
|
||||
Namespace = node;
|
||||
base.VisitNamespace(node);
|
||||
}
|
||||
|
||||
public override void VisitClass(ClassDeclarationIRNode node)
|
||||
{
|
||||
Class = node;
|
||||
base.VisitClass(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue