aspnetcore/test/Microsoft.AspNet.Mvc.Razor..../Compilation/CompilerCacheTest.cs

309 lines
12 KiB
C#

// 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.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using Microsoft.AspNet.Mvc.Razor.Precompilation;
using Microsoft.Dnx.Runtime;
using Moq;
using Xunit;
namespace Microsoft.AspNet.Mvc.Razor.Compilation
{
public class CompilerCacheTest
{
private const string ViewPath = "Views/Home/Index.cshtml";
private const string PrecompiledViewsPath = "Views/Home/Precompiled.cshtml";
private readonly IAssemblyLoadContext TestLoadContext = Mock.Of<IAssemblyLoadContext>();
public static TheoryData ViewImportsPaths =>
new TheoryData<string>
{
Path.Combine("Views", "Home", "_ViewImports.cshtml"),
Path.Combine("Views", "_ViewImports.cshtml"),
"_ViewImports.cshtml",
};
[Fact]
public void GetOrAdd_ReturnsFileNotFoundResult_IfFileIsNotFoundInFileSystem()
{
// Arrange
var fileProvider = new TestFileProvider();
var cache = new CompilerCache(Enumerable.Empty<RazorFileInfoCollection>(), TestLoadContext, fileProvider);
// Act
var result = cache.GetOrAdd("/some/path", ThrowsIfCalled);
// Assert
Assert.Same(CompilerCacheResult.FileNotFound, result);
Assert.Null(result.CompilationResult);
}
[Fact]
public void GetOrAdd_ReturnsCompilationResultFromFactory()
{
// Arrange
var fileProvider = new TestFileProvider();
fileProvider.AddFile(ViewPath, "some content");
var cache = new CompilerCache(Enumerable.Empty<RazorFileInfoCollection>(), TestLoadContext, fileProvider);
var type = typeof(TestView);
var expected = UncachedCompilationResult.Successful(type, "hello world");
// Act
var result = cache.GetOrAdd(ViewPath, _ => expected);
// Assert
Assert.NotSame(CompilerCacheResult.FileNotFound, result);
var actual = Assert.IsType<UncachedCompilationResult>(result.CompilationResult);
Assert.NotNull(actual);
Assert.Same(expected, actual);
Assert.Equal("hello world", actual.CompiledContent);
Assert.Same(type, actual.CompiledType);
}
[Fact]
public void GetOrAdd_ReturnsFileNotFoundIfFileWasDeleted()
{
// Arrange
var fileProvider = new TestFileProvider();
fileProvider.AddFile(ViewPath, "some content");
var cache = new CompilerCache(Enumerable.Empty<RazorFileInfoCollection>(), TestLoadContext, fileProvider);
var type = typeof(TestView);
var expected = UncachedCompilationResult.Successful(type, "hello world");
// Act 1
var result1 = cache.GetOrAdd(ViewPath, _ => expected);
// Assert 1
Assert.NotSame(CompilerCacheResult.FileNotFound, result1);
Assert.Same(expected, result1.CompilationResult);
// Act 2
// Delete the file from the file system and set it's expiration trigger.
fileProvider.DeleteFile(ViewPath);
fileProvider.GetTrigger(ViewPath).IsExpired = true;
var result2 = cache.GetOrAdd(ViewPath, ThrowsIfCalled);
// Assert 2
Assert.Same(CompilerCacheResult.FileNotFound, result2);
Assert.Null(result2.CompilationResult);
}
[Fact]
public void GetOrAdd_ReturnsNewResultIfFileWasModified()
{
// Arrange
var fileProvider = new TestFileProvider();
fileProvider.AddFile(ViewPath, "some content");
var cache = new CompilerCache(Enumerable.Empty<RazorFileInfoCollection>(), TestLoadContext, fileProvider);
var expected1 = UncachedCompilationResult.Successful(typeof(TestView), "hello world");
var expected2 = UncachedCompilationResult.Successful(typeof(DifferentView), "different content");
// Act 1
var result1 = cache.GetOrAdd(ViewPath, _ => expected1);
// Assert 1
Assert.NotSame(CompilerCacheResult.FileNotFound, result1);
Assert.Same(expected1, result1.CompilationResult);
// Act 2
// Verify we're getting cached results.
var result2 = cache.GetOrAdd(ViewPath, ThrowsIfCalled);
// Assert 2
Assert.NotSame(CompilerCacheResult.FileNotFound, result2);
Assert.Same(expected1.CompiledType, result2.CompilationResult.CompiledType);
// Act 3
fileProvider.GetTrigger(ViewPath).IsExpired = true;
var result3 = cache.GetOrAdd(ViewPath, _ => expected2);
// Assert 3
Assert.NotSame(CompilerCacheResult.FileNotFound, result3);
Assert.Same(expected2, result3.CompilationResult);
}
[Theory]
[MemberData(nameof(ViewImportsPaths))]
public void GetOrAdd_ReturnsNewResult_IfAncestorViewImportsWereModified(string globalImportPath)
{
// Arrange
var fileProvider = new TestFileProvider();
fileProvider.AddFile(ViewPath, "some content");
var cache = new CompilerCache(Enumerable.Empty<RazorFileInfoCollection>(), TestLoadContext, fileProvider);
var expected1 = UncachedCompilationResult.Successful(typeof(TestView), "hello world");
var expected2 = UncachedCompilationResult.Successful(typeof(DifferentView), "different content");
// Act 1
var result1 = cache.GetOrAdd(ViewPath, _ => expected1);
// Assert 1
Assert.NotSame(CompilerCacheResult.FileNotFound, result1);
Assert.Same(expected1, result1.CompilationResult);
// Act 2
// Verify we're getting cached results.
var result2 = cache.GetOrAdd(ViewPath, ThrowsIfCalled);
// Assert 2
Assert.NotSame(CompilerCacheResult.FileNotFound, result2);
Assert.Same(expected1.CompiledType, result2.CompilationResult.CompiledType);
// Act 3
fileProvider.GetTrigger(globalImportPath).IsExpired = true;
var result3 = cache.GetOrAdd(ViewPath, _ => expected2);
// Assert 2
Assert.NotSame(CompilerCacheResult.FileNotFound, result3);
Assert.Same(expected2, result3.CompilationResult);
}
[Fact]
public void GetOrAdd_DoesNotQueryFileSystem_IfCachedFileTriggerWasNotSet()
{
// Arrange
var mockFileProvider = new Mock<TestFileProvider> { CallBase = true };
var fileProvider = mockFileProvider.Object;
fileProvider.AddFile(ViewPath, "some content");
var cache = new CompilerCache(Enumerable.Empty<RazorFileInfoCollection>(), TestLoadContext, fileProvider);
var type = typeof(TestView);
var expected = UncachedCompilationResult.Successful(type, "hello world");
// Act 1
var result1 = cache.GetOrAdd(ViewPath, _ => expected);
// Assert 1
Assert.NotSame(CompilerCacheResult.FileNotFound, result1);
Assert.Same(expected, result1.CompilationResult);
// Act 2
var result2 = cache.GetOrAdd(ViewPath, ThrowsIfCalled);
// Assert 2
Assert.NotSame(CompilerCacheResult.FileNotFound, result2);
Assert.IsType<CompilationResult>(result2.CompilationResult);
Assert.Same(type, result2.CompilationResult.CompiledType);
mockFileProvider.Verify(v => v.GetFileInfo(ViewPath), Times.Once());
}
[Fact]
public void GetOrAdd_UsesViewsSpecifiedFromRazorFileInfoCollection()
{
// Arrange
var fileProvider = new TestFileProvider();
var cache = new CompilerCache(new[] { new TestViewCollection() }, TestLoadContext, fileProvider);
// Act
var result = cache.GetOrAdd(PrecompiledViewsPath, ThrowsIfCalled);
// Assert
Assert.NotSame(CompilerCacheResult.FileNotFound, result);
Assert.Same(typeof(PreCompile), result.CompilationResult.CompiledType);
}
[Fact]
public void GetOrAdd_DoesNotRecompile_IfFileTriggerWasSetForPrecompiledFile()
{
// Arrange
var fileProvider = new TestFileProvider();
var cache = new CompilerCache(new[] { new TestViewCollection() }, TestLoadContext, fileProvider);
// Act
fileProvider.Watch(PrecompiledViewsPath);
fileProvider.GetTrigger(PrecompiledViewsPath).IsExpired = true;
var result = cache.GetOrAdd(PrecompiledViewsPath, ThrowsIfCalled);
// Assert
Assert.NotSame(CompilerCacheResult.FileNotFound, result);
Assert.Same(typeof(PreCompile), result.CompilationResult.CompiledType);
}
[Theory]
[MemberData(nameof(ViewImportsPaths))]
public void GetOrAdd_DoesNotRecompile_IfFileTriggerWasSetForViewImports(string globalImportPath)
{
// Arrange
var fileProvider = new TestFileProvider();
var cache = new CompilerCache(new[] { new TestViewCollection() }, TestLoadContext, fileProvider);
// Act
fileProvider.Watch(globalImportPath);
fileProvider.GetTrigger(globalImportPath).IsExpired = true;
var result = cache.GetOrAdd(PrecompiledViewsPath, ThrowsIfCalled);
// Assert
Assert.NotSame(CompilerCacheResult.FileNotFound, result);
Assert.Same(typeof(PreCompile), result.CompilationResult.CompiledType);
}
[Fact]
public void GetOrAdd_ReturnsRuntimeCompiledAndPrecompiledViews()
{
// Arrange
var fileProvider = new TestFileProvider();
fileProvider.AddFile(ViewPath, "some content");
var cache = new CompilerCache(new[] { new TestViewCollection() }, TestLoadContext, fileProvider);
var expected = CompilationResult.Successful(typeof(TestView));
// Act 1
var result1 = cache.GetOrAdd(ViewPath, _ => expected);
// Assert 1
Assert.Same(expected, result1.CompilationResult);
// Act 2
var result2 = cache.GetOrAdd(ViewPath, ThrowsIfCalled);
// Assert 2
Assert.NotSame(CompilerCacheResult.FileNotFound, result2);
Assert.Same(typeof(TestView), result2.CompilationResult.CompiledType);
// Act 3
var result3 = cache.GetOrAdd(PrecompiledViewsPath, ThrowsIfCalled);
// Assert 3
Assert.NotSame(CompilerCacheResult.FileNotFound, result2);
Assert.Same(typeof(PreCompile), result3.CompilationResult.CompiledType);
}
private class TestView
{
}
private class PreCompile
{
}
public class DifferentView
{
}
private CompilationResult ThrowsIfCalled(RelativeFileInfo file)
{
throw new Exception("Shouldn't be called");
}
private class TestViewCollection : RazorFileInfoCollection
{
public TestViewCollection()
{
FileInfos = new List<RazorFileInfo>
{
new RazorFileInfo
{
FullTypeName = typeof(PreCompile).FullName,
RelativePath = PrecompiledViewsPath,
}
};
}
public override Assembly LoadAssembly(IAssemblyLoadContext loadContext)
{
return typeof(TestViewCollection).Assembly;
}
}
}
}