From df0b33a3782b2fc28258fcc1442cfb1075d067aa Mon Sep 17 00:00:00 2001 From: Pranav K Date: Tue, 26 Aug 2014 20:29:37 -0700 Subject: [PATCH] Updating ViewStartUtility to use IFileSystem.TryGetParentPath --- .../Directives/ChunkInheritanceUtility.cs | 4 +- .../MvcRazorHost.cs | 18 +--- .../ViewStartUtility.cs | 52 +++------ .../ViewStartProvider.cs | 8 +- .../Directives/ChunkInheritanceUtilityTest.cs | 12 +-- .../InjectChunkVisitorTest.cs | 8 +- .../ModelChunkVisitorTest.cs | 6 +- .../TestFileSystem.cs | 3 +- .../Areas/MyArea/Sub/Views/Admin/Test.cshtml | 1 + .../Views/Home/MyView.cshtml | 1 + .../ViewStartUtilityTest.cs | 102 +++++++++--------- 11 files changed, 85 insertions(+), 130 deletions(-) create mode 100644 test/Microsoft.AspNet.Mvc.Razor.Host.Test/TestFiles/ViewStartUtilityFiles/Areas/MyArea/Sub/Views/Admin/Test.cshtml create mode 100644 test/Microsoft.AspNet.Mvc.Razor.Host.Test/TestFiles/ViewStartUtilityFiles/Views/Home/MyView.cshtml diff --git a/src/Microsoft.AspNet.Mvc.Razor.Host/Directives/ChunkInheritanceUtility.cs b/src/Microsoft.AspNet.Mvc.Razor.Host/Directives/ChunkInheritanceUtility.cs index 20c24d57c5..96f7e40c7c 100644 --- a/src/Microsoft.AspNet.Mvc.Razor.Host/Directives/ChunkInheritanceUtility.cs +++ b/src/Microsoft.AspNet.Mvc.Razor.Host/Directives/ChunkInheritanceUtility.cs @@ -52,18 +52,16 @@ namespace Microsoft.AspNet.Mvc.Razor.Directives /// /// The used to parse _ViewStart pages. /// The filesystem that represents the application. - /// The root of the application. /// The path of the page to locate inherited chunks for. /// A list of chunks that are applicable to the given page. public List GetInheritedChunks([NotNull] MvcRazorHost razorHost, [NotNull] IFileSystem fileSystem, - [NotNull] string appRoot, [NotNull] string pagePath) { var inheritedChunks = new List(); 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)) diff --git a/src/Microsoft.AspNet.Mvc.Razor.Host/MvcRazorHost.cs b/src/Microsoft.AspNet.Mvc.Razor.Host/MvcRazorHost.cs index 522b4b687c..6f3b436ea4 100644 --- a/src/Microsoft.AspNet.Mvc.Razor.Host/MvcRazorHost.cs +++ b/src/Microsoft.AspNet.Mvc.Razor.Host/MvcRazorHost.cs @@ -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. // This field holds the type name without the generic decoration (MyBaseType) @@ -43,24 +42,17 @@ namespace Microsoft.AspNet.Mvc.Razor /// /// Contains information about the executing application. public MvcRazorHost(IApplicationEnvironment appEnvironment) - : this(appEnvironment.ApplicationBasePath, - new PhysicalFileSystem(appEnvironment.ApplicationBasePath)) + : this(new PhysicalFileSystem(appEnvironment.ApplicationBasePath)) { } /// - /// Initializes a new instance of at the specified application root - /// and . + /// Initializes a new instance of using the specified . /// - /// The base path of the application. - /// - /// A rooted at the . - /// - protected internal MvcRazorHost(string applicationBasePath, - IFileSystem fileSystem) + /// A rooted at the application base path. + 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); } } diff --git a/src/Microsoft.AspNet.Mvc.Razor.Host/ViewStartUtility.cs b/src/Microsoft.AspNet.Mvc.Razor.Host/ViewStartUtility.cs index 4e2dda0294..fd71c096d1 100644 --- a/src/Microsoft.AspNet.Mvc.Razor.Host/ViewStartUtility.cs +++ b/src/Microsoft.AspNet.Mvc.Razor.Host/ViewStartUtility.cs @@ -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 ] /// - public static IEnumerable GetViewStartLocations(string applicationBase, string path) + public static IEnumerable GetViewStartLocations(IFileSystem fileSystem, string path) { if (string.IsNullOrEmpty(path)) { return Enumerable.Empty(); } - - applicationBase = TrimTrailingSlash(applicationBase); - var viewStartLocations = new List(); - 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(); + + 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; - } } } \ No newline at end of file diff --git a/src/Microsoft.AspNet.Mvc.Razor/ViewStartProvider.cs b/src/Microsoft.AspNet.Mvc.Razor/ViewStartProvider.cs index 215cce468e..1c56ea4909 100644 --- a/src/Microsoft.AspNet.Mvc.Razor/ViewStartProvider.cs +++ b/src/Microsoft.AspNet.Mvc.Razor/ViewStartProvider.cs @@ -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 /// 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; } + /// public IEnumerable 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(); diff --git a/test/Microsoft.AspNet.Mvc.Razor.Host.Test/Directives/ChunkInheritanceUtilityTest.cs b/test/Microsoft.AspNet.Mvc.Razor.Host.Test/Directives/ChunkInheritanceUtilityTest.cs index 38f7e19829..1cf55f8b28 100644 --- a/test/Microsoft.AspNet.Mvc.Razor.Host.Test/Directives/ChunkInheritanceUtilityTest.cs +++ b/test/Microsoft.AspNet.Mvc.Razor.Host.Test/Directives/ChunkInheritanceUtilityTest.cs @@ -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 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 diff --git a/test/Microsoft.AspNet.Mvc.Razor.Host.Test/InjectChunkVisitorTest.cs b/test/Microsoft.AspNet.Mvc.Razor.Host.Test/InjectChunkVisitorTest.cs index 69632a5b58..fa6bd07212 100644 --- a/test/Microsoft.AspNet.Mvc.Razor.Host.Test/InjectChunkVisitorTest.cs +++ b/test/Microsoft.AspNet.Mvc.Razor.Host.Test/InjectChunkVisitorTest.cs @@ -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()) + 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()) + 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()), + return CodeGeneratorContext.Create(new MvcRazorHost(new TestFileSystem()), "MyClass", "MyNamespace", string.Empty, diff --git a/test/Microsoft.AspNet.Mvc.Razor.Host.Test/ModelChunkVisitorTest.cs b/test/Microsoft.AspNet.Mvc.Razor.Host.Test/ModelChunkVisitorTest.cs index 02b8f1b646..5d20588236 100644 --- a/test/Microsoft.AspNet.Mvc.Razor.Host.Test/ModelChunkVisitorTest.cs +++ b/test/Microsoft.AspNet.Mvc.Razor.Host.Test/ModelChunkVisitorTest.cs @@ -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()) + 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()), + return CodeGeneratorContext.Create(new MvcRazorHost(new TestFileSystem()), "MyClass", "MyNamespace", string.Empty, diff --git a/test/Microsoft.AspNet.Mvc.Razor.Host.Test/TestFileSystem.cs b/test/Microsoft.AspNet.Mvc.Razor.Host.Test/TestFileSystem.cs index ffdc97b3a1..99fea29910 100644 --- a/test/Microsoft.AspNet.Mvc.Razor.Host.Test/TestFileSystem.cs +++ b/test/Microsoft.AspNet.Mvc.Razor.Host.Test/TestFileSystem.cs @@ -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); } } } \ No newline at end of file diff --git a/test/Microsoft.AspNet.Mvc.Razor.Host.Test/TestFiles/ViewStartUtilityFiles/Areas/MyArea/Sub/Views/Admin/Test.cshtml b/test/Microsoft.AspNet.Mvc.Razor.Host.Test/TestFiles/ViewStartUtilityFiles/Areas/MyArea/Sub/Views/Admin/Test.cshtml new file mode 100644 index 0000000000..5f282702bb --- /dev/null +++ b/test/Microsoft.AspNet.Mvc.Razor.Host.Test/TestFiles/ViewStartUtilityFiles/Areas/MyArea/Sub/Views/Admin/Test.cshtml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/test/Microsoft.AspNet.Mvc.Razor.Host.Test/TestFiles/ViewStartUtilityFiles/Views/Home/MyView.cshtml b/test/Microsoft.AspNet.Mvc.Razor.Host.Test/TestFiles/ViewStartUtilityFiles/Views/Home/MyView.cshtml new file mode 100644 index 0000000000..5f282702bb --- /dev/null +++ b/test/Microsoft.AspNet.Mvc.Razor.Host.Test/TestFiles/ViewStartUtilityFiles/Views/Home/MyView.cshtml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/test/Microsoft.AspNet.Mvc.Razor.Host.Test/ViewStartUtilityTest.cs b/test/Microsoft.AspNet.Mvc.Razor.Host.Test/ViewStartUtilityTest.cs index cd596202d6..f8231c847b 100644 --- a/test/Microsoft.AspNet.Mvc.Razor.Host.Test/ViewStartUtilityTest.cs +++ b/test/Microsoft.AspNet.Mvc.Razor.Host.Test/ViewStartUtilityTest.cs @@ -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 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 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"); + } } } \ No newline at end of file