Add test to validate tooling path normalization.
- Tooling passes in rooted paths when asking for a RazorParser for a file. This was problematic when resolving inherited code trees and ultimately this commit tests that. #2213
This commit is contained in:
parent
570b1e583a
commit
9ac346529c
|
|
@ -47,7 +47,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Directives
|
||||||
/// <param name="pagePath">The path of the page to locate inherited chunks for.</param>
|
/// <param name="pagePath">The path of the page to locate inherited chunks for.</param>
|
||||||
/// <returns>A <see cref="IReadOnlyList{CodeTree}"/> of parsed <c>_GlobalImport</c>
|
/// <returns>A <see cref="IReadOnlyList{CodeTree}"/> of parsed <c>_GlobalImport</c>
|
||||||
/// <see cref="CodeTree"/>s.</returns>
|
/// <see cref="CodeTree"/>s.</returns>
|
||||||
public IReadOnlyList<CodeTree> GetInheritedCodeTrees([NotNull] string pagePath)
|
public virtual IReadOnlyList<CodeTree> GetInheritedCodeTrees([NotNull] string pagePath)
|
||||||
{
|
{
|
||||||
var inheritedCodeTrees = new List<CodeTree>();
|
var inheritedCodeTrees = new List<CodeTree>();
|
||||||
var templateEngine = new RazorTemplateEngine(_razorHost);
|
var templateEngine = new RazorTemplateEngine(_razorHost);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using Microsoft.Framework.Internal;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc.Razor.Internal
|
||||||
|
{
|
||||||
|
public class DesignTimeRazorPathNormalizer : RazorPathNormalizer
|
||||||
|
{
|
||||||
|
private readonly string _applicationRoot;
|
||||||
|
|
||||||
|
public DesignTimeRazorPathNormalizer([NotNull] string applicationRoot)
|
||||||
|
{
|
||||||
|
_applicationRoot = applicationRoot;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string NormalizePath([NotNull] string path)
|
||||||
|
{
|
||||||
|
// Need to convert path to application relative (rooted paths are passed in during design time).
|
||||||
|
if (Path.IsPathRooted(path) && path.StartsWith(_applicationRoot, StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
path = path.Substring(_applicationRoot.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using Microsoft.Framework.Internal;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc.Razor.Internal
|
||||||
|
{
|
||||||
|
public class RazorPathNormalizer
|
||||||
|
{
|
||||||
|
public virtual string NormalizePath([NotNull] string path)
|
||||||
|
{
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -5,6 +5,7 @@ using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using Microsoft.AspNet.FileProviders;
|
using Microsoft.AspNet.FileProviders;
|
||||||
using Microsoft.AspNet.Mvc.Razor.Directives;
|
using Microsoft.AspNet.Mvc.Razor.Directives;
|
||||||
|
using Microsoft.AspNet.Mvc.Razor.Internal;
|
||||||
using Microsoft.AspNet.Razor;
|
using Microsoft.AspNet.Razor;
|
||||||
using Microsoft.AspNet.Razor.Generator;
|
using Microsoft.AspNet.Razor.Generator;
|
||||||
using Microsoft.AspNet.Razor.Generator.Compiler;
|
using Microsoft.AspNet.Razor.Generator.Compiler;
|
||||||
|
|
@ -36,31 +37,13 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
// This field holds the type name without the generic decoration (MyBaseType)
|
// This field holds the type name without the generic decoration (MyBaseType)
|
||||||
private readonly string _baseType;
|
private readonly string _baseType;
|
||||||
private readonly ICodeTreeCache _codeTreeCache;
|
private readonly ICodeTreeCache _codeTreeCache;
|
||||||
|
private readonly RazorPathNormalizer _pathNormalizer;
|
||||||
private ChunkInheritanceUtility _chunkInheritanceUtility;
|
private ChunkInheritanceUtility _chunkInheritanceUtility;
|
||||||
|
|
||||||
#if NET45
|
internal MvcRazorHost(ICodeTreeCache codeTreeCache, RazorPathNormalizer pathNormalizer)
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of <see cref="MvcRazorHost"/> with the specified
|
|
||||||
/// <param name="root"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="root">The path to the application base.</param>
|
|
||||||
// Note: This constructor is used by tooling and is created once for each
|
|
||||||
// Razor page that is loaded. Consequently, each loaded page has its own copy of
|
|
||||||
// the CodeTreeCache, but this ok - having a shared CodeTreeCache per application in tooling
|
|
||||||
// is problematic to manage.
|
|
||||||
public MvcRazorHost(string root) :
|
|
||||||
this(new DefaultCodeTreeCache(new PhysicalFileProvider(root)))
|
|
||||||
{
|
|
||||||
ApplicationRoot = root;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of <see cref="MvcRazorHost"/> using the specified <paramref name="fileProvider"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="fileProvider">A <see cref="IFileProvider"/> rooted at the application base path.</param>
|
|
||||||
public MvcRazorHost(ICodeTreeCache codeTreeCache)
|
|
||||||
: base(new CSharpRazorCodeLanguage())
|
: base(new CSharpRazorCodeLanguage())
|
||||||
{
|
{
|
||||||
|
_pathNormalizer = pathNormalizer;
|
||||||
_baseType = BaseType;
|
_baseType = BaseType;
|
||||||
_codeTreeCache = codeTreeCache;
|
_codeTreeCache = codeTreeCache;
|
||||||
|
|
||||||
|
|
@ -115,10 +98,26 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
|
|
||||||
#if NET45
|
#if NET45
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The path to the application root.
|
/// Initializes a new instance of <see cref="MvcRazorHost"/> with the specified <paramref name="root"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string ApplicationRoot { get; }
|
/// <param name="root">The path to the application base.</param>
|
||||||
|
// Note: This constructor is used by tooling and is created once for each
|
||||||
|
// Razor page that is loaded. Consequently, each loaded page has its own copy of
|
||||||
|
// the CodeTreeCache, but this ok - having a shared CodeTreeCache per application in tooling
|
||||||
|
// is problematic to manage.
|
||||||
|
public MvcRazorHost(string root)
|
||||||
|
: this(new DefaultCodeTreeCache(new PhysicalFileProvider(root)), new DesignTimeRazorPathNormalizer(root))
|
||||||
|
{
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of <see cref="MvcRazorHost"/> using the specified <paramref name="codeTreeCache"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="codeTreeCache">An <see cref="ICodeTreeCache"/> rooted at the application base path.</param>
|
||||||
|
public MvcRazorHost(ICodeTreeCache codeTreeCache)
|
||||||
|
: this(codeTreeCache, new RazorPathNormalizer())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the model type used by default when no model is specified.
|
/// Gets the model type used by default when no model is specified.
|
||||||
|
|
@ -168,7 +167,8 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
get { return "CreateModelExpression"; }
|
get { return "CreateModelExpression"; }
|
||||||
}
|
}
|
||||||
|
|
||||||
private ChunkInheritanceUtility ChunkInheritanceUtility
|
// Internal for testing
|
||||||
|
internal ChunkInheritanceUtility ChunkInheritanceUtility
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
|
|
@ -180,6 +180,10 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
|
|
||||||
return _chunkInheritanceUtility;
|
return _chunkInheritanceUtility;
|
||||||
}
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_chunkInheritanceUtility = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|
@ -194,13 +198,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override RazorParser DecorateRazorParser([NotNull] RazorParser razorParser, string sourceFileName)
|
public override RazorParser DecorateRazorParser([NotNull] RazorParser razorParser, string sourceFileName)
|
||||||
{
|
{
|
||||||
#if NET45
|
sourceFileName = _pathNormalizer.NormalizePath(sourceFileName);
|
||||||
// Need to convert sourceFileName to application relative (rooted paths are passed in by tooling).
|
|
||||||
if (Path.IsPathRooted(sourceFileName))
|
|
||||||
{
|
|
||||||
sourceFileName = sourceFileName.Substring(ApplicationRoot.Length);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
var inheritedCodeTrees = ChunkInheritanceUtility.GetInheritedCodeTrees(sourceFileName);
|
var inheritedCodeTrees = ChunkInheritanceUtility.GetInheritedCodeTrees(sourceFileName);
|
||||||
return new MvcRazorParser(razorParser, inheritedCodeTrees, DefaultInheritedChunks);
|
return new MvcRazorParser(razorParser, inheritedCodeTrees, DefaultInheritedChunks);
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,52 @@
|
||||||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using Microsoft.AspNet.Mvc.Razor.Directives;
|
using Microsoft.AspNet.Mvc.Razor.Directives;
|
||||||
|
using Microsoft.AspNet.Mvc.Razor.Internal;
|
||||||
using Microsoft.AspNet.Razor;
|
using Microsoft.AspNet.Razor;
|
||||||
using Microsoft.AspNet.Razor.Generator;
|
using Microsoft.AspNet.Razor.Generator;
|
||||||
using Microsoft.AspNet.Razor.Generator.Compiler;
|
using Microsoft.AspNet.Razor.Generator.Compiler;
|
||||||
using Microsoft.AspNet.Razor.Generator.Compiler.CSharp;
|
using Microsoft.AspNet.Razor.Generator.Compiler.CSharp;
|
||||||
|
using Microsoft.AspNet.Razor.Parser;
|
||||||
using Microsoft.AspNet.Razor.Text;
|
using Microsoft.AspNet.Razor.Text;
|
||||||
|
using Microsoft.Framework.Internal;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.Razor
|
namespace Microsoft.AspNet.Mvc.Razor
|
||||||
{
|
{
|
||||||
public class MvcRazorHostTest
|
public class MvcRazorHostTest
|
||||||
{
|
{
|
||||||
|
[Theory]
|
||||||
|
[InlineData("//")]
|
||||||
|
[InlineData("C:/")]
|
||||||
|
[InlineData(@"\\")]
|
||||||
|
[InlineData(@"C:\")]
|
||||||
|
public void DecorateRazorParser_DesignTimeRazorPathNormalizer_NormalizesChunkInheritanceUtilityPaths(
|
||||||
|
string rootPrefix)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var rootedAppPath = $"{rootPrefix}SomeComputer/Location/Project/";
|
||||||
|
var rootedFilePath = $"{rootPrefix}SomeComputer/Location/Project/src/file.cshtml";
|
||||||
|
var host = new MvcRazorHost(
|
||||||
|
codeTreeCache: null,
|
||||||
|
pathNormalizer: new DesignTimeRazorPathNormalizer(rootedAppPath));
|
||||||
|
var parser = new RazorParser(
|
||||||
|
host.CodeLanguage.CreateCodeParser(),
|
||||||
|
host.CreateMarkupParser(),
|
||||||
|
tagHelperDescriptorResolver: null);
|
||||||
|
var chunkInheritanceUtility = new PathValidatingChunkInheritanceUtility(host);
|
||||||
|
host.ChunkInheritanceUtility = chunkInheritanceUtility;
|
||||||
|
|
||||||
|
// Act
|
||||||
|
host.DecorateRazorParser(parser, rootedFilePath);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal("src/file.cshtml", chunkInheritanceUtility.InheritedCodeTreePagePath, StringComparer.Ordinal);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void MvcRazorHost_EnablesInstrumentationByDefault()
|
public void MvcRazorHost_EnablesInstrumentationByDefault()
|
||||||
{
|
{
|
||||||
|
|
@ -254,6 +286,23 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
generatedLocation: new MappingLocation(generatedLocation, contentLength));
|
generatedLocation: new MappingLocation(generatedLocation, contentLength));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class PathValidatingChunkInheritanceUtility : ChunkInheritanceUtility
|
||||||
|
{
|
||||||
|
public PathValidatingChunkInheritanceUtility(MvcRazorHost razorHost)
|
||||||
|
: base(razorHost, codeTreeCache: null, defaultInheritedChunks: new Chunk[0])
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public string InheritedCodeTreePagePath { get; private set; }
|
||||||
|
|
||||||
|
public override IReadOnlyList<CodeTree> GetInheritedCodeTrees([NotNull] string pagePath)
|
||||||
|
{
|
||||||
|
InheritedCodeTreePagePath = pagePath;
|
||||||
|
|
||||||
|
return new CodeTree[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Used when testing Tag Helpers, it disables the unique ID generation feature.
|
/// Used when testing Tag Helpers, it disables the unique ID generation feature.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue