Updating ViewStartUtility to use IFileSystem.TryGetParentPath

This commit is contained in:
Pranav K 2014-08-26 20:29:37 -07:00
parent 103693b61c
commit df0b33a378
11 changed files with 85 additions and 130 deletions

View File

@ -52,18 +52,16 @@ namespace Microsoft.AspNet.Mvc.Razor.Directives
/// </summary>
/// <param name="razorHost">The <see cref="MvcRazorHost"/> used to parse _ViewStart pages.</param>
/// <param name="fileSystem">The filesystem that represents the application.</param>
/// <param name="appRoot">The root of the application.</param>
/// <param name="pagePath">The path of the page to locate inherited chunks for.</param>
/// <returns>A list of chunks that are applicable to the given page.</returns>
public List<Chunk> GetInheritedChunks([NotNull] MvcRazorHost razorHost,
[NotNull] IFileSystem fileSystem,
[NotNull] string appRoot,
[NotNull] string pagePath)
{
var inheritedChunks = new List<Chunk>();
var templateEngine = new RazorTemplateEngine(razorHost);
foreach (var viewStart in ViewStartUtility.GetViewStartLocations(appRoot, pagePath))
foreach (var viewStart in ViewStartUtility.GetViewStartLocations(fileSystem, pagePath))
{
IFileInfo fileInfo;
if (fileSystem.TryGetFileInfo(viewStart, out fileInfo))

View File

@ -31,7 +31,6 @@ namespace Microsoft.AspNet.Mvc.Razor
new InjectChunk("Microsoft.AspNet.Mvc.IUrlHelper", "Url"),
};
private readonly string _appRoot;
private readonly IFileSystem _fileSystem;
// CodeGenerationContext.DefaultBaseClass is set to MyBaseType<dynamic>.
// This field holds the type name without the generic decoration (MyBaseType)
@ -43,24 +42,17 @@ namespace Microsoft.AspNet.Mvc.Razor
/// </summary>
/// <param name="appEnvironment">Contains information about the executing application.</param>
public MvcRazorHost(IApplicationEnvironment appEnvironment)
: this(appEnvironment.ApplicationBasePath,
new PhysicalFileSystem(appEnvironment.ApplicationBasePath))
: this(new PhysicalFileSystem(appEnvironment.ApplicationBasePath))
{
}
/// <summary>
/// Initializes a new instance of <see cref="MvcRazorHost"/> at the specified application root
/// and <paramref name="fileSystem"/>.
/// Initializes a new instance of <see cref="MvcRazorHost"/> using the specified <paramref name="fileSystem"/>.
/// </summary>
/// <param name="applicationBasePath">The base path of the application.</param>
/// <param name="fileSystem">
/// A <see cref="IFileSystem"/> rooted at the <paramref name="applicationBasePath"/>.
/// </param>
protected internal MvcRazorHost(string applicationBasePath,
IFileSystem fileSystem)
/// <param name="fileSystem">A <see cref="IFileSystem"/> rooted at the application base path.</param>
protected internal MvcRazorHost([NotNull] IFileSystem fileSystem)
: base(new CSharpRazorCodeLanguage())
{
_appRoot = applicationBasePath;
_fileSystem = fileSystem;
_baseType = BaseType;
@ -140,7 +132,7 @@ namespace Microsoft.AspNet.Mvc.Razor
var chunkUtility = new ChunkInheritanceUtility(context.CodeTreeBuilder.CodeTree,
DefaultInheritedChunks,
DefaultModel);
var inheritedChunks = chunkUtility.GetInheritedChunks(this, _fileSystem, _appRoot, context.SourceFile);
var inheritedChunks = chunkUtility.GetInheritedChunks(this, _fileSystem, context.SourceFile);
chunkUtility.MergeInheritedChunks(inheritedChunks);
}
}

View File

@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.AspNet.FileSystems;
namespace Microsoft.AspNet.Mvc.Razor
{
@ -35,55 +36,26 @@ namespace Microsoft.AspNet.Mvc.Razor
/// e.g.
/// /Views/Home/View.cshtml -> [ /Views/Home/_ViewStart.cshtml, /Views/_ViewStart.cshtml, /_ViewStart.cshtml ]
/// </remarks>
public static IEnumerable<string> GetViewStartLocations(string applicationBase, string path)
public static IEnumerable<string> GetViewStartLocations(IFileSystem fileSystem, string path)
{
if (string.IsNullOrEmpty(path))
{
return Enumerable.Empty<string>();
}
applicationBase = TrimTrailingSlash(applicationBase);
var viewStartLocations = new List<string>();
var currentDir = GetViewDirectory(applicationBase, path);
while (IsSubDirectory(applicationBase, currentDir))
if (path.StartsWith("~/", StringComparison.Ordinal))
{
viewStartLocations.Add(Path.Combine(currentDir, ViewStartFileName));
currentDir = Path.GetDirectoryName(currentDir);
path = path.Substring(1);
}
var viewStartLocations = new List<string>();
while (fileSystem.TryGetParentPath(path, out path))
{
var viewStartPath = Path.Combine(path, ViewStartFileName);
viewStartLocations.Add(viewStartPath);
}
return viewStartLocations;
}
private static bool IsSubDirectory(string appRoot, string currentDir)
{
return currentDir.StartsWith(appRoot, StringComparison.OrdinalIgnoreCase);
}
private static string GetViewDirectory(string appRoot, string viewPath)
{
if (viewPath.StartsWith("~/"))
{
viewPath = viewPath.Substring(2);
}
else if (viewPath[0] == Path.DirectorySeparatorChar ||
viewPath[0] == Path.AltDirectorySeparatorChar)
{
viewPath = viewPath.Substring(1);
}
var viewDir = Path.GetDirectoryName(viewPath);
return Path.GetFullPath(Path.Combine(appRoot, viewDir));
}
private static string TrimTrailingSlash(string path)
{
if (path.Length > 0 &&
path[path.Length - 1] == Path.DirectorySeparatorChar)
{
return path.Substring(0, path.Length - 1);
}
return path;
}
}
}

View File

@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNet.FileSystems;
using Microsoft.Framework.Runtime;
namespace Microsoft.AspNet.Mvc.Razor
@ -11,20 +12,21 @@ namespace Microsoft.AspNet.Mvc.Razor
/// <inheritdoc />
public class ViewStartProvider : IViewStartProvider
{
private readonly string _appRoot;
private readonly IFileSystem _fileSystem;
private readonly IRazorPageFactory _pageFactory;
public ViewStartProvider(IApplicationEnvironment appEnv,
IRazorPageFactory pageFactory)
{
_appRoot = appEnv.ApplicationBasePath;
_fileSystem = new PhysicalFileSystem(appEnv.ApplicationBasePath);
_pageFactory = pageFactory;
}
/// <inheritdoc />
public IEnumerable<IRazorPage> GetViewStartPages([NotNull] string path)
{
var viewStartLocations = ViewStartUtility.GetViewStartLocations(_appRoot, path);
var viewStartLocations = ViewStartUtility.GetViewStartLocations(_fileSystem, path);
var viewStarts = viewStartLocations.Select(_pageFactory.CreateInstance)
.Where(p => p != null)
.ToArray();

View File

@ -15,7 +15,6 @@ namespace Microsoft.AspNet.Mvc.Razor.Directives
public void GetInheritedChunks_ReadsChunksFromViewStartsInPath()
{
// Arrange
var appRoot = @"x:\myapproot";
var fileSystem = new TestFileSystem();
fileSystem.AddFile(@"x:\myapproot\views\accounts\_viewstart.cshtml", "@using AccountModels");
fileSystem.AddFile(@"x:\myapproot\views\Shared\_viewstart.cshtml", "@inject SharedHelper Shared");
@ -29,13 +28,12 @@ namespace Microsoft.AspNet.Mvc.Razor.Directives
}
");
var host = new MvcRazorHost(appRoot, fileSystem);
var host = new MvcRazorHost(fileSystem);
var utility = new ChunkInheritanceUtility(new CodeTree(), new Chunk[0], "dynamic");
// Act
var chunks = utility.GetInheritedChunks(host,
fileSystem,
appRoot,
@"x:\myapproot\views\home\Index.cshtml");
// Assert
@ -55,18 +53,16 @@ namespace Microsoft.AspNet.Mvc.Razor.Directives
public void GetInheritedChunks_ReturnsEmptySequenceIfNoViewStartsArePresent()
{
// Arrange
var appRoot = @"x:\myapproot";
var fileSystem = new TestFileSystem();
fileSystem.AddFile(@"x:\myapproot\_viewstart.cs", string.Empty);
fileSystem.AddFile(@"x:\myapproot\views\_Layout.cshtml", string.Empty);
fileSystem.AddFile(@"x:\myapproot\views\home\_not-viewstart.cshtml", string.Empty);
var host = new MvcRazorHost(appRoot, fileSystem);
var host = new MvcRazorHost(fileSystem);
var utility = new ChunkInheritanceUtility(new CodeTree(), new Chunk[0], "dynamic");
// Act
var chunks = utility.GetInheritedChunks(host,
fileSystem,
appRoot,
@"x:\myapproot\views\home\Index.cshtml");
// Assert
@ -77,7 +73,6 @@ namespace Microsoft.AspNet.Mvc.Razor.Directives
public void GetInheritedChunks_ReturnsDefaultInheritedChunks()
{
// Arrange
var appRoot = @"x:\myapproot";
var fileSystem = new TestFileSystem();
fileSystem.AddFile(@"x:\myapproot\views\_viewstart.cshtml",
@"@inject DifferentHelper<TModel> Html
@ -87,7 +82,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Directives
}
");
var host = new MvcRazorHost(appRoot, fileSystem);
var host = new MvcRazorHost(fileSystem);
var defaultChunks = new Chunk[]
{
new InjectChunk("MyTestHtmlHelper", "Html"),
@ -98,7 +93,6 @@ namespace Microsoft.AspNet.Mvc.Razor.Directives
// Act
var chunks = utility.GetInheritedChunks(host,
fileSystem,
appRoot,
@"x:\myapproot\views\home\Index.cshtml");
// Assert

View File

@ -3,14 +3,12 @@
using System.Collections.Generic;
using System.IO;
using Microsoft.AspNet.FileSystems;
using Microsoft.AspNet.Razor;
using Microsoft.AspNet.Razor.Generator;
using Microsoft.AspNet.Razor.Generator.Compiler;
using Microsoft.AspNet.Razor.Generator.Compiler.CSharp;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Text;
using Moq;
using Xunit;
namespace Microsoft.AspNet.Mvc.Razor
@ -116,7 +114,7 @@ MyType2 @MyPropertyName2
public void InjectVisitor_GeneratesCorrectLineMappings()
{
// Arrange
var host = new MvcRazorHost("appRoot", Mock.Of<IFileSystem>())
var host = new MvcRazorHost(new TestFileSystem())
{
DesignTimeMode = true
};
@ -148,7 +146,7 @@ MyType2 @MyPropertyName2
public void InjectVisitorWithModel_GeneratesCorrectLineMappings()
{
// Arrange
var host = new MvcRazorHost("appRoot", Mock.Of<IFileSystem>())
var host = new MvcRazorHost(new TestFileSystem())
{
DesignTimeMode = true
};
@ -190,7 +188,7 @@ MyType2 @MyPropertyName2
private static CodeGeneratorContext CreateContext()
{
return CodeGeneratorContext.Create(new MvcRazorHost("appRoot", Mock.Of<IFileSystem>()),
return CodeGeneratorContext.Create(new MvcRazorHost(new TestFileSystem()),
"MyClass",
"MyNamespace",
string.Empty,

View File

@ -4,14 +4,12 @@
using System;
using System.Collections.Generic;
using System.IO;
using Microsoft.AspNet.FileSystems;
using Microsoft.AspNet.Razor;
using Microsoft.AspNet.Razor.Generator;
using Microsoft.AspNet.Razor.Generator.Compiler;
using Microsoft.AspNet.Razor.Generator.Compiler.CSharp;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Text;
using Moq;
using Xunit;
namespace Microsoft.AspNet.Mvc.Razor
@ -108,7 +106,7 @@ Environment.NewLine +
public void ModelVisitor_GeneratesCorrectLineMappings()
{
// Arrange
var host = new MvcRazorHost("appRoot", Mock.Of<IFileSystem>())
var host = new MvcRazorHost(new TestFileSystem())
{
DesignTimeMode = true
};
@ -148,7 +146,7 @@ Environment.NewLine +
private static CodeGeneratorContext CreateContext()
{
return CodeGeneratorContext.Create(new MvcRazorHost("appRoot", Mock.Of<IFileSystem>()),
return CodeGeneratorContext.Create(new MvcRazorHost(new TestFileSystem()),
"MyClass",
"MyNamespace",
string.Empty,

View File

@ -44,7 +44,8 @@ namespace Microsoft.AspNet.Mvc.Razor
public bool TryGetParentPath(string subpath, out string parentPath)
{
throw new NotImplementedException();
parentPath = Path.GetDirectoryName(subpath);
return !string.IsNullOrEmpty(parentPath);
}
}
}

View File

@ -1,7 +1,10 @@
// 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.Collections.Generic;
using System.IO;
using Microsoft.AspNet.FileSystems;
using Microsoft.Framework.Runtime;
using Microsoft.Framework.Runtime.Infrastructure;
using Xunit;
namespace Microsoft.AspNet.Mvc.Razor
@ -13,69 +16,64 @@ namespace Microsoft.AspNet.Mvc.Razor
[InlineData("")]
public void GetViewStartLocations_ReturnsEmptySequenceIfViewPathIsEmpty(string viewPath)
{
// Arrange
var appPath = @"x:\test";
// Act
var result = ViewStartUtility.GetViewStartLocations(appPath, viewPath);
var result = ViewStartUtility.GetViewStartLocations(new TestFileSystem(), viewPath);
// Assert
Assert.Empty(result);
}
public static IEnumerable<object[]> GetViewStartLocations_ReturnsPotentialViewStartLocationsData
{
get
{
yield return new object[]
{
@"x:\test\myapp",
"/Views/Home/View.cshtml",
new[]
{
@"x:\test\myapp\Views\Home\_viewstart.cshtml",
@"x:\test\myapp\Views\_viewstart.cshtml",
@"x:\test\myapp\_viewstart.cshtml",
}
};
yield return new object[]
{
@"x:\test\myapp",
"Views/Home/View.cshtml",
new[]
{
@"x:\test\myapp\Views\Home\_viewstart.cshtml",
@"x:\test\myapp\Views\_viewstart.cshtml",
@"x:\test\myapp\_viewstart.cshtml",
}
};
yield return new object[]
{
@"x:\test\myapp\",
"Views/Home/View.cshtml",
new[]
{
@"x:\test\myapp\Views\Home\_viewstart.cshtml",
@"x:\test\myapp\Views\_viewstart.cshtml",
@"x:\test\myapp\_viewstart.cshtml",
}
};
}
}
[Theory]
[MemberData(nameof(GetViewStartLocations_ReturnsPotentialViewStartLocationsData))]
public void GetViewStartLocations_ReturnsPotentialViewStartLocations(string appPath,
string viewPath,
IEnumerable<string> expected)
[InlineData("/views/Home/MyView.cshtml")]
[InlineData("~/views/Home/MyView.cshtml")]
[InlineData("views/Home/MyView.cshtml")]
public void GetViewStartLocations_ReturnsPotentialViewStartLocations(string inputPath)
{
// Arrange
var expected = new[]
{
@"views\Home\_viewstart.cshtml",
@"views\_viewstart.cshtml",
@"_viewstart.cshtml"
};
var fileSystem = new PhysicalFileSystem(GetTestFileSystemBase());
// Act
var result = ViewStartUtility.GetViewStartLocations(appPath, viewPath);
var result = ViewStartUtility.GetViewStartLocations(fileSystem, inputPath);
// Assert
Assert.Equal(expected, result);
}
[Fact]
public void GetViewStartLocations_ReturnsPotentialViewStartLocations_IfPathIsAbsolute()
{
// Arrange
var expected = new[]
{
@"Areas\MyArea\Sub\Views\Admin\_viewstart.cshtml",
@"Areas\MyArea\Sub\Views\_viewstart.cshtml",
@"Areas\MyArea\Sub\_viewstart.cshtml",
@"Areas\MyArea\_viewstart.cshtml",
@"Areas\_viewstart.cshtml",
@"_viewstart.cshtml",
};
var appBase = GetTestFileSystemBase();
var viewPath = Path.Combine(appBase, "Areas", "MyArea", "Sub", "Views", "Admin", "Test.cshtml");
var fileSystem = new PhysicalFileSystem(appBase);
// Act
var result = ViewStartUtility.GetViewStartLocations(fileSystem, viewPath);
// Assert
Assert.Equal(expected, result);
}
private static string GetTestFileSystemBase()
{
var serviceProvider = CallContextServiceLocator.Locator.ServiceProvider;
var appEnv = (IApplicationEnvironment)serviceProvider.GetService(typeof(IApplicationEnvironment));
return Path.Combine(appEnv.ApplicationBasePath, "TestFiles", "ViewStartUtilityFiles");
}
}
}