From 3062eea7d08541a3d2c5beaa67b932d7f5083a16 Mon Sep 17 00:00:00 2001 From: Brennan Date: Mon, 30 Nov 2015 15:59:16 -0800 Subject: [PATCH] Dispose FileWatcher, MvcRazorHost, and ChunkTree --- .../Directives/DefaultChunkTreeCache.cs | 5 + .../Directives/IChunkTreeCache.cs | 2 +- .../IMvcRazorHost.cs | 3 +- .../MvcRazorHost.cs | 5 + .../Precompilation/RazorPreCompileModule.cs | 19 +- .../Precompilation/RazorPreCompiler.cs | 48 ++-- .../VirtualFileResultTest.cs | 40 +-- .../Directives/ChunkInheritanceUtilityTest.cs | 198 ++++++++------- .../Directives/DefaultCodeTreeCacheTest.cs | 154 ++++++------ .../MvcRazorHostTest.cs | 238 ++++++++++-------- 10 files changed, 385 insertions(+), 327 deletions(-) diff --git a/src/Microsoft.AspNet.Mvc.Razor.Host/Directives/DefaultChunkTreeCache.cs b/src/Microsoft.AspNet.Mvc.Razor.Host/Directives/DefaultChunkTreeCache.cs index 6987fc7b0a..a4e45ce105 100644 --- a/src/Microsoft.AspNet.Mvc.Razor.Host/Directives/DefaultChunkTreeCache.cs +++ b/src/Microsoft.AspNet.Mvc.Razor.Host/Directives/DefaultChunkTreeCache.cs @@ -73,5 +73,10 @@ namespace Microsoft.AspNet.Mvc.Razor.Directives return chunkTree; } + + public void Dispose() + { + _chunkTreeCache.Dispose(); + } } } \ No newline at end of file diff --git a/src/Microsoft.AspNet.Mvc.Razor.Host/Directives/IChunkTreeCache.cs b/src/Microsoft.AspNet.Mvc.Razor.Host/Directives/IChunkTreeCache.cs index c4f624870d..ad58c8752f 100644 --- a/src/Microsoft.AspNet.Mvc.Razor.Host/Directives/IChunkTreeCache.cs +++ b/src/Microsoft.AspNet.Mvc.Razor.Host/Directives/IChunkTreeCache.cs @@ -10,7 +10,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Directives /// /// A cache for parsed s. /// - public interface IChunkTreeCache + public interface IChunkTreeCache : IDisposable { /// /// Get an existing , or create and add a new one if it is diff --git a/src/Microsoft.AspNet.Mvc.Razor.Host/IMvcRazorHost.cs b/src/Microsoft.AspNet.Mvc.Razor.Host/IMvcRazorHost.cs index ad2b7ef855..f3be68042c 100644 --- a/src/Microsoft.AspNet.Mvc.Razor.Host/IMvcRazorHost.cs +++ b/src/Microsoft.AspNet.Mvc.Razor.Host/IMvcRazorHost.cs @@ -1,6 +1,7 @@ // 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 System.IO; using Microsoft.AspNet.Razor.CodeGenerators; @@ -9,7 +10,7 @@ namespace Microsoft.AspNet.Mvc.Razor /// /// Specifies the contracts for a Razor host that parses Razor files and generates C# code. /// - public interface IMvcRazorHost + public interface IMvcRazorHost : IDisposable { /// /// Parses and generates the contents of a Razor file represented by . diff --git a/src/Microsoft.AspNet.Mvc.Razor.Host/MvcRazorHost.cs b/src/Microsoft.AspNet.Mvc.Razor.Host/MvcRazorHost.cs index a4ad2047bc..c07d9a4c18 100644 --- a/src/Microsoft.AspNet.Mvc.Razor.Host/MvcRazorHost.cs +++ b/src/Microsoft.AspNet.Mvc.Razor.Host/MvcRazorHost.cs @@ -326,6 +326,11 @@ namespace Microsoft.AspNet.Mvc.Razor }); } + public void Dispose() + { + _chunkTreeCache.Dispose(); + } + private IReadOnlyList GetInheritedChunkTrees(string sourceFileName) { var inheritedChunkTrees = GetInheritedChunkTreeResults(sourceFileName) diff --git a/src/Microsoft.AspNet.Mvc.Razor/Precompilation/RazorPreCompileModule.cs b/src/Microsoft.AspNet.Mvc.Razor/Precompilation/RazorPreCompileModule.cs index 519406994e..2213581598 100644 --- a/src/Microsoft.AspNet.Mvc.Razor/Precompilation/RazorPreCompileModule.cs +++ b/src/Microsoft.AspNet.Mvc.Razor/Precompilation/RazorPreCompileModule.cs @@ -35,8 +35,6 @@ namespace Microsoft.AspNet.Mvc.Razor.Precompilation return; } - var fileProvider = new PhysicalFileProvider(context.ProjectContext.ProjectDirectory); - MemoryCache memoryCache; lock (_memoryCacheLookupLock) { @@ -57,15 +55,18 @@ namespace Microsoft.AspNet.Mvc.Razor.Precompilation } } - var viewCompiler = new RazorPreCompiler( - context, - fileProvider, - memoryCache) + using (var fileProvider = new PhysicalFileProvider(context.ProjectContext.ProjectDirectory)) { - GenerateSymbols = GenerateSymbols - }; + var viewCompiler = new RazorPreCompiler( + context, + fileProvider, + memoryCache) + { + GenerateSymbols = GenerateSymbols + }; - viewCompiler.CompileViews(); + viewCompiler.CompileViews(); + } } /// diff --git a/src/Microsoft.AspNet.Mvc.Razor/Precompilation/RazorPreCompiler.cs b/src/Microsoft.AspNet.Mvc.Razor/Precompilation/RazorPreCompiler.cs index 64d78d3443..ceed8602d6 100644 --- a/src/Microsoft.AspNet.Mvc.Razor/Precompilation/RazorPreCompiler.cs +++ b/src/Microsoft.AspNet.Mvc.Razor/Precompilation/RazorPreCompiler.cs @@ -277,36 +277,38 @@ namespace Microsoft.AspNet.Mvc.Razor.Precompilation using (var stream = fileInfo.FileInfo.CreateReadStream()) { - var host = GetRazorHost(); - var results = host.GenerateCode(fileInfo.RelativePath, stream); - - if (results.Success) + using (var host = GetRazorHost()) { - var syntaxTree = SyntaxTreeGenerator.Generate( - results.GeneratedCode, - fileInfo.FileInfo.PhysicalPath, - CompilationSettings); - var fullTypeName = results.GetMainClassName(host, syntaxTree); + var results = host.GenerateCode(fileInfo.RelativePath, stream); - if (fullTypeName != null) + if (results.Success) { - var razorFileInfo = new RazorFileInfo + var syntaxTree = SyntaxTreeGenerator.Generate( + results.GeneratedCode, + fileInfo.FileInfo.PhysicalPath, + CompilationSettings); + var fullTypeName = results.GetMainClassName(host, syntaxTree); + + if (fullTypeName != null) { - RelativePath = fileInfo.RelativePath, - FullTypeName = fullTypeName - }; + var razorFileInfo = new RazorFileInfo + { + RelativePath = fileInfo.RelativePath, + FullTypeName = fullTypeName + }; - return new PrecompilationCacheEntry(razorFileInfo, syntaxTree); + return new PrecompilationCacheEntry(razorFileInfo, syntaxTree); + } } - } - else - { - var diagnostics = results - .ParserErrors - .Select(error => error.ToDiagnostics(fileInfo.FileInfo.PhysicalPath)) - .ToList(); + else + { + var diagnostics = results + .ParserErrors + .Select(error => error.ToDiagnostics(fileInfo.FileInfo.PhysicalPath)) + .ToList(); - return new PrecompilationCacheEntry(diagnostics); + return new PrecompilationCacheEntry(diagnostics); + } } } diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/VirtualFileResultTest.cs b/test/Microsoft.AspNet.Mvc.Core.Test/VirtualFileResultTest.cs index 557f1e95ef..3d6c5e3a4c 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/VirtualFileResultTest.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/VirtualFileResultTest.cs @@ -262,21 +262,23 @@ namespace Microsoft.AspNet.Mvc { // Arrange // Point the IFileProvider root to a different subfolder - var fileProvider = new PhysicalFileProvider(Path.GetFullPath("./Properties")); - var filePathResult = new VirtualFileResult(path, "text/plain") + using (var fileProvider = new PhysicalFileProvider(Path.GetFullPath("./Properties"))) { - FileProvider = fileProvider, - }; + var filePathResult = new VirtualFileResult(path, "text/plain") + { + FileProvider = fileProvider, + }; - var expectedMessage = "Could not find file: " + path; - var context = new ActionContext(GetHttpContext(), new RouteData(), new ActionDescriptor()); + var expectedMessage = "Could not find file: " + path; + var context = new ActionContext(GetHttpContext(), new RouteData(), new ActionDescriptor()); - // Act - var ex = await Assert.ThrowsAsync(() => filePathResult.ExecuteResultAsync(context)); + // Act + var ex = await Assert.ThrowsAsync(() => filePathResult.ExecuteResultAsync(context)); - // Assert - Assert.Equal(expectedMessage, ex.Message); - Assert.Equal(path, ex.FileName); + // Assert + Assert.Equal(expectedMessage, ex.Message); + Assert.Equal(path, ex.FileName); + } } [Theory] @@ -294,16 +296,18 @@ namespace Microsoft.AspNet.Mvc { // Arrange // Point the IFileProvider root to a different subfolder - var fileProvider = new PhysicalFileProvider(Path.GetFullPath("./Properties")); - var filePathResult = new VirtualFileResult(path, "text/plain") + using (var fileProvider = new PhysicalFileProvider(Path.GetFullPath("./Properties"))) { - FileProvider = fileProvider, - }; + var filePathResult = new VirtualFileResult(path, "text/plain") + { + FileProvider = fileProvider, + }; - var context = new ActionContext(new DefaultHttpContext(), new RouteData(), new ActionDescriptor()); + var context = new ActionContext(new DefaultHttpContext(), new RouteData(), new ActionDescriptor()); - // Act & Assert - Assert.ThrowsAsync(() => filePathResult.ExecuteResultAsync(context)); + // Act & Assert + Assert.ThrowsAsync(() => filePathResult.ExecuteResultAsync(context)); + } } private static IServiceCollection CreateServices() 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 987fa03083..e339ab768b 100644 --- a/test/Microsoft.AspNet.Mvc.Razor.Host.Test/Directives/ChunkInheritanceUtilityTest.cs +++ b/test/Microsoft.AspNet.Mvc.Razor.Host.Test/Directives/ChunkInheritanceUtilityTest.cs @@ -31,81 +31,83 @@ namespace Microsoft.AspNet.Mvc.Razor.Directives new UsingChunk { Namespace = "AppNamespace.Model" }, }; var cache = new DefaultChunkTreeCache(fileProvider); - var host = new MvcRazorHost(cache); - var utility = new ChunkInheritanceUtility(host, cache, defaultChunks); + using (var host = new MvcRazorHost(cache)) + { + var utility = new ChunkInheritanceUtility(host, cache, defaultChunks); - // Act - var chunkTreeResults = utility.GetInheritedChunkTreeResults( - PlatformNormalizer.NormalizePath(@"Views\home\Index.cshtml")); + // Act + var chunkTreeResults = utility.GetInheritedChunkTreeResults( + PlatformNormalizer.NormalizePath(@"Views\home\Index.cshtml")); - // Assert - Assert.Collection(chunkTreeResults, - chunkTreeResult => - { - var viewImportsPath = @"/Views/_ViewImports.cshtml"; - Assert.Collection(chunkTreeResult.ChunkTree.Children, - chunk => - { - Assert.IsType(chunk); - Assert.Equal(viewImportsPath, chunk.Start.FilePath); - }, - chunk => - { - var injectChunk = Assert.IsType(chunk); - Assert.Equal("MyHelper", injectChunk.TypeName); - Assert.Equal("Helper", injectChunk.MemberName); - Assert.Equal(viewImportsPath, chunk.Start.FilePath); - }, - chunk => - { - Assert.IsType(chunk); - Assert.Equal(viewImportsPath, chunk.Start.FilePath); - }, - chunk => - { - var setBaseTypeChunk = Assert.IsType(chunk); - Assert.Equal("MyBaseType", setBaseTypeChunk.TypeName); - Assert.Equal(viewImportsPath, chunk.Start.FilePath); - }, - chunk => - { - Assert.IsType(chunk); - Assert.Equal(viewImportsPath, chunk.Start.FilePath); - }, - chunk => - { - Assert.IsType(chunk); - Assert.Equal(viewImportsPath, chunk.Start.FilePath); - }, - chunk => - { - Assert.IsType(chunk); - Assert.Equal(viewImportsPath, chunk.Start.FilePath); - }); - Assert.Equal(viewImportsPath, chunkTreeResult.FilePath); - }, - chunkTreeResult => - { - var viewImportsPath = "/Views/home/_ViewImports.cshtml"; - Assert.Collection(chunkTreeResult.ChunkTree.Children, - chunk => - { - Assert.IsType(chunk); - Assert.Equal(viewImportsPath, chunk.Start.FilePath); - }, - chunk => - { - var usingChunk = Assert.IsType(chunk); - Assert.Equal("MyNamespace", usingChunk.Namespace); - Assert.Equal(viewImportsPath, chunk.Start.FilePath); - }, - chunk => - { - Assert.IsType(chunk); - Assert.Equal(viewImportsPath, chunk.Start.FilePath); - }); - Assert.Equal(viewImportsPath, chunkTreeResult.FilePath); - }); + // Assert + Assert.Collection(chunkTreeResults, + chunkTreeResult => + { + var viewImportsPath = @"/Views/_ViewImports.cshtml"; + Assert.Collection(chunkTreeResult.ChunkTree.Children, + chunk => + { + Assert.IsType(chunk); + Assert.Equal(viewImportsPath, chunk.Start.FilePath); + }, + chunk => + { + var injectChunk = Assert.IsType(chunk); + Assert.Equal("MyHelper", injectChunk.TypeName); + Assert.Equal("Helper", injectChunk.MemberName); + Assert.Equal(viewImportsPath, chunk.Start.FilePath); + }, + chunk => + { + Assert.IsType(chunk); + Assert.Equal(viewImportsPath, chunk.Start.FilePath); + }, + chunk => + { + var setBaseTypeChunk = Assert.IsType(chunk); + Assert.Equal("MyBaseType", setBaseTypeChunk.TypeName); + Assert.Equal(viewImportsPath, chunk.Start.FilePath); + }, + chunk => + { + Assert.IsType(chunk); + Assert.Equal(viewImportsPath, chunk.Start.FilePath); + }, + chunk => + { + Assert.IsType(chunk); + Assert.Equal(viewImportsPath, chunk.Start.FilePath); + }, + chunk => + { + Assert.IsType(chunk); + Assert.Equal(viewImportsPath, chunk.Start.FilePath); + }); + Assert.Equal(viewImportsPath, chunkTreeResult.FilePath); + }, + chunkTreeResult => + { + var viewImportsPath = "/Views/home/_ViewImports.cshtml"; + Assert.Collection(chunkTreeResult.ChunkTree.Children, + chunk => + { + Assert.IsType(chunk); + Assert.Equal(viewImportsPath, chunk.Start.FilePath); + }, + chunk => + { + var usingChunk = Assert.IsType(chunk); + Assert.Equal("MyNamespace", usingChunk.Namespace); + Assert.Equal(viewImportsPath, chunk.Start.FilePath); + }, + chunk => + { + Assert.IsType(chunk); + Assert.Equal(viewImportsPath, chunk.Start.FilePath); + }); + Assert.Equal(viewImportsPath, chunkTreeResult.FilePath); + }); + } } [Fact] @@ -117,19 +119,21 @@ namespace Microsoft.AspNet.Mvc.Razor.Directives fileProvider.AddFile(@"/Views/_Layout.cshtml", string.Empty); fileProvider.AddFile(@"/Views/home/_not-viewimports.cshtml", string.Empty); var cache = new DefaultChunkTreeCache(fileProvider); - var host = new MvcRazorHost(cache); - var defaultChunks = new Chunk[] + using (var host = new MvcRazorHost(cache)) { + var defaultChunks = new Chunk[] + { new InjectChunk("MyTestHtmlHelper", "Html"), new UsingChunk { Namespace = "AppNamespace.Model" }, - }; - var utility = new ChunkInheritanceUtility(host, cache, defaultChunks); + }; + var utility = new ChunkInheritanceUtility(host, cache, defaultChunks); - // Act - var chunkTrees = utility.GetInheritedChunkTreeResults(PlatformNormalizer.NormalizePath(@"Views\home\Index.cshtml")); + // Act + var chunkTrees = utility.GetInheritedChunkTreeResults(PlatformNormalizer.NormalizePath(@"Views\home\Index.cshtml")); - // Assert - Assert.Empty(chunkTrees); + // Assert + Assert.Empty(chunkTrees); + } } [Fact] @@ -140,14 +144,15 @@ namespace Microsoft.AspNet.Mvc.Razor.Directives fileProvider.AddFile(@"/Views/_ViewImports.cshtml", "@inject DifferentHelper Html"); var cache = new DefaultChunkTreeCache(fileProvider); - var host = new MvcRazorHost(cache); - var defaultChunks = new Chunk[] + using (var host = new MvcRazorHost(cache)) { + var defaultChunks = new Chunk[] + { new InjectChunk("MyTestHtmlHelper", "Html"), new UsingChunk { Namespace = "AppNamespace.Model" }, - }; - var inheritedChunkTrees = new ChunkTree[] - { + }; + var inheritedChunkTrees = new ChunkTree[] + { new ChunkTree { Children = new Chunk[] @@ -163,19 +168,20 @@ namespace Microsoft.AspNet.Mvc.Razor.Directives new UsingChunk { Namespace = "AppNamespace.Model" }, } } - }; + }; - var utility = new ChunkInheritanceUtility(host, cache, defaultChunks); - var chunkTree = new ChunkTree(); + var utility = new ChunkInheritanceUtility(host, cache, defaultChunks); + var chunkTree = new ChunkTree(); - // Act - utility.MergeInheritedChunkTrees(chunkTree, inheritedChunkTrees, "dynamic"); + // Act + utility.MergeInheritedChunkTrees(chunkTree, inheritedChunkTrees, "dynamic"); - // Assert - Assert.Collection(chunkTree.Children, - chunk => Assert.Same(defaultChunks[1], chunk), - chunk => Assert.Same(inheritedChunkTrees[0].Children[0], chunk), - chunk => Assert.Same(defaultChunks[0], chunk)); + // Assert + Assert.Collection(chunkTree.Children, + chunk => Assert.Same(defaultChunks[1], chunk), + chunk => Assert.Same(inheritedChunkTrees[0].Children[0], chunk), + chunk => Assert.Same(defaultChunks[0], chunk)); + } } } } \ No newline at end of file diff --git a/test/Microsoft.AspNet.Mvc.Razor.Host.Test/Directives/DefaultCodeTreeCacheTest.cs b/test/Microsoft.AspNet.Mvc.Razor.Host.Test/Directives/DefaultCodeTreeCacheTest.cs index 1c08762628..154a2f3be3 100644 --- a/test/Microsoft.AspNet.Mvc.Razor.Host.Test/Directives/DefaultCodeTreeCacheTest.cs +++ b/test/Microsoft.AspNet.Mvc.Razor.Host.Test/Directives/DefaultCodeTreeCacheTest.cs @@ -21,17 +21,19 @@ namespace Microsoft.AspNet.Mvc.Razor.Host.Directives var mockFileProvider = new Mock { CallBase = true }; var fileProvider = mockFileProvider.Object; fileProvider.AddFile(path, "test content"); - var chunkTreeCache = new DefaultChunkTreeCache(fileProvider); - var expected = new ChunkTree(); + using (var chunkTreeCache = new DefaultChunkTreeCache(fileProvider)) + { + var expected = new ChunkTree(); - // Act - var result1 = chunkTreeCache.GetOrAdd(path, fileInfo => expected); - var result2 = chunkTreeCache.GetOrAdd(path, fileInfo => { throw new Exception("Shouldn't be called."); }); + // Act + var result1 = chunkTreeCache.GetOrAdd(path, fileInfo => expected); + var result2 = chunkTreeCache.GetOrAdd(path, fileInfo => { throw new Exception("Shouldn't be called."); }); - // Assert - Assert.Same(expected, result1); - Assert.Same(expected, result2); - mockFileProvider.Verify(f => f.GetFileInfo(It.IsAny()), Times.Once()); + // Assert + Assert.Same(expected, result1); + Assert.Same(expected, result2); + mockFileProvider.Verify(f => f.GetFileInfo(It.IsAny()), Times.Once()); + } } [Fact] @@ -41,17 +43,19 @@ namespace Microsoft.AspNet.Mvc.Razor.Host.Directives var path = @"Views\_ViewStart.cshtml"; var mockFileProvider = new Mock { CallBase = true }; var fileProvider = mockFileProvider.Object; - var chunkTreeCache = new DefaultChunkTreeCache(fileProvider); - var expected = new ChunkTree(); + using (var chunkTreeCache = new DefaultChunkTreeCache(fileProvider)) + { + var expected = new ChunkTree(); - // Act - var result1 = chunkTreeCache.GetOrAdd(path, fileInfo => expected); - var result2 = chunkTreeCache.GetOrAdd(path, fileInfo => { throw new Exception("Shouldn't be called."); }); + // Act + var result1 = chunkTreeCache.GetOrAdd(path, fileInfo => expected); + var result2 = chunkTreeCache.GetOrAdd(path, fileInfo => { throw new Exception("Shouldn't be called."); }); - // Assert - Assert.Null(result1); - Assert.Null(result2); - mockFileProvider.Verify(f => f.GetFileInfo(It.IsAny()), Times.Once()); + // Assert + Assert.Null(result1); + Assert.Null(result2); + mockFileProvider.Verify(f => f.GetFileInfo(It.IsAny()), Times.Once()); + } } [Fact] @@ -61,22 +65,24 @@ namespace Microsoft.AspNet.Mvc.Razor.Host.Directives var path = @"Views\Home\_ViewStart.cshtml"; var fileProvider = new TestFileProvider(); fileProvider.AddFile(path, "test content"); - var chunkTreeCache = new DefaultChunkTreeCache(fileProvider); - var expected1 = new ChunkTree(); - var expected2 = new ChunkTree(); + using (var chunkTreeCache = new DefaultChunkTreeCache(fileProvider)) + { + var expected1 = new ChunkTree(); + var expected2 = new ChunkTree(); - // Act 1 - var result1 = chunkTreeCache.GetOrAdd(path, fileInfo => expected1); + // Act 1 + var result1 = chunkTreeCache.GetOrAdd(path, fileInfo => expected1); - // Assert 1 - Assert.Same(expected1, result1); + // Assert 1 + Assert.Same(expected1, result1); - // Act 2 - fileProvider.GetChangeToken(path).HasChanged = true; - var result2 = chunkTreeCache.GetOrAdd(path, fileInfo => expected2); + // Act 2 + fileProvider.GetChangeToken(path).HasChanged = true; + var result2 = chunkTreeCache.GetOrAdd(path, fileInfo => expected2); - // Assert 2 - Assert.Same(expected2, result2); + // Assert 2 + Assert.Same(expected2, result2); + } } [Fact] @@ -86,22 +92,24 @@ namespace Microsoft.AspNet.Mvc.Razor.Host.Directives var path = @"Views\Home\_ViewStart.cshtml"; var fileProvider = new TestFileProvider(); fileProvider.AddFile(path, "test content"); - var chunkTreeCache = new DefaultChunkTreeCache(fileProvider); - var expected1 = new ChunkTree(); + using (var chunkTreeCache = new DefaultChunkTreeCache(fileProvider)) + { + var expected1 = new ChunkTree(); - // Act 1 - var result1 = chunkTreeCache.GetOrAdd(path, fileInfo => expected1); + // Act 1 + var result1 = chunkTreeCache.GetOrAdd(path, fileInfo => expected1); - // Assert 1 - Assert.Same(expected1, result1); + // Assert 1 + Assert.Same(expected1, result1); - // Act 2 - fileProvider.DeleteFile(path); - fileProvider.GetChangeToken(path).HasChanged = true; - var result2 = chunkTreeCache.GetOrAdd(path, fileInfo => { throw new Exception("Shouldn't be called."); }); + // Act 2 + fileProvider.DeleteFile(path); + fileProvider.GetChangeToken(path).HasChanged = true; + var result2 = chunkTreeCache.GetOrAdd(path, fileInfo => { throw new Exception("Shouldn't be called."); }); - // Assert 2 - Assert.Null(result2); + // Assert 2 + Assert.Null(result2); + } } [Fact] @@ -110,22 +118,24 @@ namespace Microsoft.AspNet.Mvc.Razor.Host.Directives // Arrange var path = @"Views\Home\_ViewStart.cshtml"; var fileProvider = new TestFileProvider(); - var chunkTreeCache = new DefaultChunkTreeCache(fileProvider); - var expected = new ChunkTree(); + using (var chunkTreeCache = new DefaultChunkTreeCache(fileProvider)) + { + var expected = new ChunkTree(); - // Act 1 - var result1 = chunkTreeCache.GetOrAdd(path, fileInfo => { throw new Exception("Shouldn't be called."); }); + // Act 1 + var result1 = chunkTreeCache.GetOrAdd(path, fileInfo => { throw new Exception("Shouldn't be called."); }); - // Assert 1 - Assert.Null(result1); + // Assert 1 + Assert.Null(result1); - // Act 2 - fileProvider.AddFile(path, "test content"); - fileProvider.GetChangeToken(path).HasChanged = true; - var result2 = chunkTreeCache.GetOrAdd(path, fileInfo => expected); + // Act 2 + fileProvider.AddFile(path, "test content"); + fileProvider.GetChangeToken(path).HasChanged = true; + var result2 = chunkTreeCache.GetOrAdd(path, fileInfo => expected); - // Assert 2 - Assert.Same(expected, result2); + // Assert 2 + Assert.Same(expected, result2); + } } [Fact] @@ -140,29 +150,31 @@ namespace Microsoft.AspNet.Mvc.Razor.Host.Directives clock.SetupGet(c => c.UtcNow) .Returns(() => utcNow); var options = new MemoryCacheOptions { Clock = clock.Object }; - var chunkTreeCache = new DefaultChunkTreeCache(fileProvider, options); - var chunkTree1 = new ChunkTree(); - var chunkTree2 = new ChunkTree(); + using (var chunkTreeCache = new DefaultChunkTreeCache(fileProvider, options)) + { + var chunkTree1 = new ChunkTree(); + var chunkTree2 = new ChunkTree(); - // Act 1 - var result1 = chunkTreeCache.GetOrAdd(path, fileInfo => chunkTree1); + // Act 1 + var result1 = chunkTreeCache.GetOrAdd(path, fileInfo => chunkTree1); - // Assert 1 - Assert.Same(chunkTree1, result1); + // Assert 1 + Assert.Same(chunkTree1, result1); - // Act 2 - utcNow = utcNow.AddSeconds(59); - var result2 = chunkTreeCache.GetOrAdd(path, fileInfo => { throw new Exception("Shouldn't be called."); }); + // Act 2 + utcNow = utcNow.AddSeconds(59); + var result2 = chunkTreeCache.GetOrAdd(path, fileInfo => { throw new Exception("Shouldn't be called."); }); - // Assert 2 - Assert.Same(chunkTree1, result2); + // Assert 2 + Assert.Same(chunkTree1, result2); - // Act 3 - utcNow = utcNow.AddSeconds(65); - var result3 = chunkTreeCache.GetOrAdd(path, fileInfo => chunkTree2); + // Act 3 + utcNow = utcNow.AddSeconds(65); + var result3 = chunkTreeCache.GetOrAdd(path, fileInfo => chunkTree2); - // Assert 3 - Assert.Same(chunkTree2, result3); + // Assert 3 + Assert.Same(chunkTree2, result3); + } } } } \ No newline at end of file diff --git a/test/Microsoft.AspNet.Mvc.Razor.Host.Test/MvcRazorHostTest.cs b/test/Microsoft.AspNet.Mvc.Razor.Host.Test/MvcRazorHostTest.cs index e3d963a49b..dce89dab64 100644 --- a/test/Microsoft.AspNet.Mvc.Razor.Host.Test/MvcRazorHostTest.cs +++ b/test/Microsoft.AspNet.Mvc.Razor.Host.Test/MvcRazorHostTest.cs @@ -55,21 +55,23 @@ namespace Microsoft.AspNet.Mvc.Razor var rootedAppPath = $"{rootPrefix}SomeComputer/Location/Project/"; var rootedFilePath = $"{rootPrefix}SomeComputer/Location/Project/src/file.cshtml"; var chunkTreeCache = new DefaultChunkTreeCache(new TestFileProvider()); - var host = new MvcRazorHost( + using (var host = new MvcRazorHost( chunkTreeCache, - pathNormalizer: new DesignTimeRazorPathNormalizer(rootedAppPath)); - var parser = new RazorParser( - host.CodeLanguage.CreateCodeParser(), - host.CreateMarkupParser(), - tagHelperDescriptorResolver: null); - var chunkInheritanceUtility = new PathValidatingChunkInheritanceUtility(host, chunkTreeCache); - host.ChunkInheritanceUtility = chunkInheritanceUtility; + pathNormalizer: new DesignTimeRazorPathNormalizer(rootedAppPath))) + { + var parser = new RazorParser( + host.CodeLanguage.CreateCodeParser(), + host.CreateMarkupParser(), + tagHelperDescriptorResolver: null); + var chunkInheritanceUtility = new PathValidatingChunkInheritanceUtility(host, chunkTreeCache); + host.ChunkInheritanceUtility = chunkInheritanceUtility; - // Act - host.DecorateRazorParser(parser, rootedFilePath); + // Act + host.DecorateRazorParser(parser, rootedFilePath); - // Assert - Assert.Equal("src/file.cshtml", chunkInheritanceUtility.InheritedChunkTreePagePath, StringComparer.Ordinal); + // Assert + Assert.Equal("src/file.cshtml", chunkInheritanceUtility.InheritedChunkTreePagePath, StringComparer.Ordinal); + } } [Theory] @@ -81,26 +83,28 @@ namespace Microsoft.AspNet.Mvc.Razor var rootedAppPath = $"{rootPrefix}SomeComputer/Location/Project/"; var rootedFilePath = $"{rootPrefix}SomeComputer/Location/Project/src/file.cshtml"; var chunkTreeCache = new DefaultChunkTreeCache(new TestFileProvider()); - var host = new MvcRazorHost( + using (var host = new MvcRazorHost( chunkTreeCache, - pathNormalizer: new DesignTimeRazorPathNormalizer(rootedAppPath)); - var chunkInheritanceUtility = new PathValidatingChunkInheritanceUtility(host, chunkTreeCache); - var codeGeneratorContext = new CodeGeneratorContext( - new ChunkGeneratorContext( - host, - host.DefaultClassName, - host.DefaultNamespace, - rootedFilePath, - shouldGenerateLinePragmas: true), - new ErrorSink()); - var codeGenerator = new CSharpCodeGenerator(codeGeneratorContext); - host.ChunkInheritanceUtility = chunkInheritanceUtility; + pathNormalizer: new DesignTimeRazorPathNormalizer(rootedAppPath))) + { + var chunkInheritanceUtility = new PathValidatingChunkInheritanceUtility(host, chunkTreeCache); + var codeGeneratorContext = new CodeGeneratorContext( + new ChunkGeneratorContext( + host, + host.DefaultClassName, + host.DefaultNamespace, + rootedFilePath, + shouldGenerateLinePragmas: true), + new ErrorSink()); + var codeGenerator = new CSharpCodeGenerator(codeGeneratorContext); + host.ChunkInheritanceUtility = chunkInheritanceUtility; - // Act - host.DecorateCodeGenerator(codeGenerator, codeGeneratorContext); + // Act + host.DecorateCodeGenerator(codeGenerator, codeGeneratorContext); - // Assert - Assert.Equal("src/file.cshtml", chunkInheritanceUtility.InheritedChunkTreePagePath, StringComparer.Ordinal); + // Assert + Assert.Equal("src/file.cshtml", chunkInheritanceUtility.InheritedChunkTreePagePath, StringComparer.Ordinal); + } } [Fact] @@ -108,13 +112,14 @@ namespace Microsoft.AspNet.Mvc.Razor { // Arrange var fileProvider = new TestFileProvider(); - var host = new MvcRazorHost(new DefaultChunkTreeCache(fileProvider)); + using (var host = new MvcRazorHost(new DefaultChunkTreeCache(fileProvider))) + { + // Act + var instrumented = host.EnableInstrumentation; - // Act - var instrumented = host.EnableInstrumentation; - - // Assert - Assert.True(instrumented); + // Assert + Assert.True(instrumented); + } } [Fact] @@ -122,12 +127,13 @@ namespace Microsoft.AspNet.Mvc.Razor { // Arrange var fileProvider = new TestFileProvider(); - var host = new MvcRazorHostWithNormalizedNewLine(new DefaultChunkTreeCache(fileProvider)) + using (var host = new MvcRazorHostWithNormalizedNewLine(new DefaultChunkTreeCache(fileProvider)) { DesignTimeMode = true - }; - var expectedLineMappings = new[] + }) { + var expectedLineMappings = new[] + { BuildLineMapping( documentAbsoluteIndex: 33, documentLineIndex: 2, @@ -160,13 +166,14 @@ namespace Microsoft.AspNet.Mvc.Razor generatedLineIndex: 53, generatedCharacterIndex: 87, contentLength: 5), - }; + }; - // Act and Assert - RunDesignTimeTest( - host, - testName: "ModelExpressionTagHelper", - expectedLineMappings: expectedLineMappings); + // Act and Assert + RunDesignTimeTest( + host, + testName: "ModelExpressionTagHelper", + expectedLineMappings: expectedLineMappings); + } } [Theory] @@ -181,10 +188,11 @@ namespace Microsoft.AspNet.Mvc.Razor { // Arrange var fileProvider = new TestFileProvider(); - var host = new TestMvcRazorHost(new DefaultChunkTreeCache(fileProvider)); - - // Act and Assert - RunRuntimeTest(host, scenarioName); + using (var host = new TestMvcRazorHost(new DefaultChunkTreeCache(fileProvider))) + { + // Act and Assert + RunRuntimeTest(host, scenarioName); + } } [Fact] @@ -192,13 +200,14 @@ namespace Microsoft.AspNet.Mvc.Razor { // Arrange var fileProvider = new TestFileProvider(); - var host = new MvcRazorHostWithNormalizedNewLine(new DefaultChunkTreeCache(fileProvider)) + using (var host = new MvcRazorHostWithNormalizedNewLine(new DefaultChunkTreeCache(fileProvider)) { DesignTimeMode = true - }; - host.NamespaceImports.Clear(); - var expectedLineMappings = new[] + }) { + host.NamespaceImports.Clear(); + var expectedLineMappings = new[] + { BuildLineMapping( documentAbsoluteIndex: 13, documentLineIndex: 0, @@ -215,10 +224,11 @@ namespace Microsoft.AspNet.Mvc.Razor generatedLineIndex: 37, generatedCharacterIndex: 6, contentLength: 21), - }; + }; - // Act and Assert - RunDesignTimeTest(host, "Basic", expectedLineMappings); + // Act and Assert + RunDesignTimeTest(host, "Basic", expectedLineMappings); + } } [Fact] @@ -226,13 +236,14 @@ namespace Microsoft.AspNet.Mvc.Razor { // Arrange var fileProvider = new TestFileProvider(); - var host = new MvcRazorHostWithNormalizedNewLine(new DefaultChunkTreeCache(fileProvider)) + using (var host = new MvcRazorHostWithNormalizedNewLine(new DefaultChunkTreeCache(fileProvider)) { DesignTimeMode = true - }; - host.NamespaceImports.Clear(); - var expectedLineMappings = new[] + }) { + host.NamespaceImports.Clear(); + var expectedLineMappings = new[] + { BuildLineMapping( documentAbsoluteIndex: 8, documentLineIndex: 0, @@ -241,10 +252,11 @@ namespace Microsoft.AspNet.Mvc.Razor generatedLineIndex: 21, generatedCharacterIndex: 8, contentLength: 26), - }; + }; - // Act and Assert - RunDesignTimeTest(host, "_ViewImports", expectedLineMappings); + // Act and Assert + RunDesignTimeTest(host, "_ViewImports", expectedLineMappings); + } } [Fact] @@ -252,13 +264,14 @@ namespace Microsoft.AspNet.Mvc.Razor { // Arrange var fileProvider = new TestFileProvider(); - var host = new MvcRazorHostWithNormalizedNewLine(new DefaultChunkTreeCache(fileProvider)) + using (var host = new MvcRazorHostWithNormalizedNewLine(new DefaultChunkTreeCache(fileProvider)) { DesignTimeMode = true - }; - host.NamespaceImports.Clear(); - var expectedLineMappings = new[] + }) { + host.NamespaceImports.Clear(); + var expectedLineMappings = new[] + { BuildLineMapping( documentAbsoluteIndex: 1, documentLineIndex: 0, @@ -275,10 +288,11 @@ namespace Microsoft.AspNet.Mvc.Razor generatedLineIndex: 26, generatedCharacterIndex: 8, contentLength: 20), - }; + }; - // Act and Assert - RunDesignTimeTest(host, "Inject", expectedLineMappings); + // Act and Assert + RunDesignTimeTest(host, "Inject", expectedLineMappings); + } } [Fact] @@ -286,13 +300,14 @@ namespace Microsoft.AspNet.Mvc.Razor { // Arrange var fileProvider = new TestFileProvider(); - var host = new MvcRazorHostWithNormalizedNewLine(new DefaultChunkTreeCache(fileProvider)) + using (var host = new MvcRazorHostWithNormalizedNewLine(new DefaultChunkTreeCache(fileProvider)) { DesignTimeMode = true - }; - host.NamespaceImports.Clear(); - var expectedLineMappings = new[] + }) { + host.NamespaceImports.Clear(); + var expectedLineMappings = new[] + { BuildLineMapping( documentAbsoluteIndex: 7, documentLineIndex: 0, @@ -317,10 +332,11 @@ namespace Microsoft.AspNet.Mvc.Razor generatedLineIndex: 33, generatedCharacterIndex: 8, contentLength: 23), - }; + }; - // Act and Assert - RunDesignTimeTest(host, "InjectWithModel", expectedLineMappings); + // Act and Assert + RunDesignTimeTest(host, "InjectWithModel", expectedLineMappings); + } } [Fact] @@ -328,13 +344,14 @@ namespace Microsoft.AspNet.Mvc.Razor { // Arrange var fileProvider = new TestFileProvider(); - var host = new MvcRazorHostWithNormalizedNewLine(new DefaultChunkTreeCache(fileProvider)) + using (var host = new MvcRazorHostWithNormalizedNewLine(new DefaultChunkTreeCache(fileProvider)) { DesignTimeMode = true - }; - host.NamespaceImports.Clear(); - var expectedLineMappings = new[] + }) { + host.NamespaceImports.Clear(); + var expectedLineMappings = new[] + { BuildLineMapping( documentAbsoluteIndex: 7, documentLineIndex: 0, @@ -375,10 +392,11 @@ namespace Microsoft.AspNet.Mvc.Razor generatedLineIndex: 49, generatedCharacterIndex: 8, contentLength: 24), - }; + }; - // Act and Assert - RunDesignTimeTest(host, "InjectWithSemicolon", expectedLineMappings); + // Act and Assert + RunDesignTimeTest(host, "InjectWithSemicolon", expectedLineMappings); + } } [Fact] @@ -386,13 +404,14 @@ namespace Microsoft.AspNet.Mvc.Razor { // Arrange var fileProvider = new TestFileProvider(); - var host = new MvcRazorHostWithNormalizedNewLine(new DefaultChunkTreeCache(fileProvider)) + using (var host = new MvcRazorHostWithNormalizedNewLine(new DefaultChunkTreeCache(fileProvider)) { DesignTimeMode = true - }; - host.NamespaceImports.Clear(); - var expectedLineMappings = new[] + }) { + host.NamespaceImports.Clear(); + var expectedLineMappings = new[] + { BuildLineMapping( documentAbsoluteIndex: 7, documentLineIndex: 0, @@ -401,10 +420,11 @@ namespace Microsoft.AspNet.Mvc.Razor generatedLineIndex: 11, generatedCharacterIndex: 28, contentLength: 30), - }; + }; - // Act and Assert - RunDesignTimeTest(host, "Model", expectedLineMappings); + // Act and Assert + RunDesignTimeTest(host, "Model", expectedLineMappings); + } } [Fact] @@ -412,31 +432,33 @@ namespace Microsoft.AspNet.Mvc.Razor { // Arrange var fileProvider = new TestFileProvider(); - var host = new MvcRazorHostWithNormalizedNewLine(new DefaultChunkTreeCache(fileProvider)) + using (var host = new MvcRazorHostWithNormalizedNewLine(new DefaultChunkTreeCache(fileProvider)) { DesignTimeMode = true - }; - host.NamespaceImports.Clear(); - var inputFile = "TestFiles/Input/MultipleModels.cshtml"; - var outputFile = "TestFiles/Output/DesignTime/MultipleModels.cs"; - var expectedCode = ResourceFile.ReadResource(_assembly, outputFile, sourceFile: false); - - // Act - GeneratorResults results; - using (var stream = ResourceFile.GetResourceStream(_assembly, inputFile, sourceFile: true)) + }) { - results = host.GenerateCode(inputFile, stream); - } + host.NamespaceImports.Clear(); + var inputFile = "TestFiles/Input/MultipleModels.cshtml"; + var outputFile = "TestFiles/Output/DesignTime/MultipleModels.cs"; + var expectedCode = ResourceFile.ReadResource(_assembly, outputFile, sourceFile: false); - // Assert - Assert.False(results.Success); - var parserError = Assert.Single(results.ParserErrors); - Assert.Equal("Only one 'model' statement is allowed in a file.", parserError.Message); + // Act + GeneratorResults results; + using (var stream = ResourceFile.GetResourceStream(_assembly, inputFile, sourceFile: true)) + { + results = host.GenerateCode(inputFile, stream); + } + + // Assert + Assert.False(results.Success); + var parserError = Assert.Single(results.ParserErrors); + Assert.Equal("Only one 'model' statement is allowed in a file.", parserError.Message); #if GENERATE_BASELINES - ResourceFile.UpdateFile(_assembly, outputFile, expectedCode, results.GeneratedCode); + ResourceFile.UpdateFile(_assembly, outputFile, expectedCode, results.GeneratedCode); #else - Assert.Equal(expectedCode, results.GeneratedCode, ignoreLineEndingDifferences: true); + Assert.Equal(expectedCode, results.GeneratedCode, ignoreLineEndingDifferences: true); #endif + } } private static void RunRuntimeTest(