656 lines
24 KiB
C#
656 lines
24 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.Linq;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using Microsoft.AspNetCore.Diagnostics;
|
|
using Microsoft.AspNetCore.Mvc.Razor.Compilation;
|
|
using Microsoft.AspNetCore.Razor.Language;
|
|
using Microsoft.Extensions.FileProviders;
|
|
using Moq;
|
|
using Xunit;
|
|
|
|
namespace Microsoft.AspNetCore.Mvc.Razor.Internal
|
|
{
|
|
public class CompilerCacheTest
|
|
{
|
|
private const string ViewPath = "/Views/Home/Index.cshtml";
|
|
private const string PrecompiledViewsPath = "/Views/Home/Precompiled.cshtml";
|
|
private static readonly string[] _viewImportsPath = new[]
|
|
{
|
|
"/Views/Home/_ViewImports.cshtml",
|
|
"/Views/_ViewImports.cshtml",
|
|
"/_ViewImports.cshtml",
|
|
};
|
|
private readonly IDictionary<string, Type> _precompiledViews = new Dictionary<string, Type>
|
|
{
|
|
{ PrecompiledViewsPath, typeof(PreCompile) }
|
|
};
|
|
|
|
public static TheoryData ViewImportsPaths
|
|
{
|
|
get
|
|
{
|
|
var theoryData = new TheoryData<string>();
|
|
foreach (var path in _viewImportsPath)
|
|
{
|
|
theoryData.Add(path);
|
|
}
|
|
|
|
return theoryData;
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void GetOrAdd_ReturnsFileNotFoundResult_IfFileIsNotFoundInFileSystem()
|
|
{
|
|
// Arrange
|
|
var item = new Mock<RazorProjectItem>();
|
|
item
|
|
.SetupGet(i => i.Path)
|
|
.Returns("/path");
|
|
item
|
|
.SetupGet(i => i.Exists)
|
|
.Returns(false);
|
|
|
|
var fileProvider = new TestFileProvider();
|
|
var cache = new CompilerCache(fileProvider);
|
|
var compilerCacheContext = new CompilerCacheContext(
|
|
item.Object,
|
|
Enumerable.Empty<RazorProjectItem>(),
|
|
_ => throw new Exception("Shouldn't be called."));
|
|
|
|
// Act
|
|
var result = cache.GetOrAdd("/some/path", _ => compilerCacheContext);
|
|
|
|
// Assert
|
|
Assert.False(result.Success);
|
|
}
|
|
|
|
[Fact]
|
|
public void GetOrAdd_ReturnsCompilationResultFromFactory()
|
|
{
|
|
// Arrange
|
|
var fileProvider = new TestFileProvider();
|
|
fileProvider.AddFile(ViewPath, "some content");
|
|
var cache = new CompilerCache(fileProvider);
|
|
var expected = new CompilationResult(typeof(TestView));
|
|
|
|
// Act
|
|
var result = cache.GetOrAdd(ViewPath, CreateContextFactory(expected));
|
|
|
|
// Assert
|
|
Assert.True(result.Success);
|
|
Assert.Equal(typeof(TestView), result.CompiledType);
|
|
Assert.Equal(ViewPath, result.RelativePath);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData("/Areas/Finances/Views/Home/Index.cshtml")]
|
|
[InlineData(@"Areas\Finances\Views\Home\Index.cshtml")]
|
|
[InlineData(@"\Areas\Finances\Views\Home\Index.cshtml")]
|
|
[InlineData(@"\Areas\Finances\Views/Home\Index.cshtml")]
|
|
public void GetOrAdd_NormalizesPathSepartorForPaths(string relativePath)
|
|
{
|
|
// Arrange
|
|
var viewPath = "/Areas/Finances/Views/Home/Index.cshtml";
|
|
var fileProvider = new TestFileProvider();
|
|
fileProvider.AddFile(viewPath, "some content");
|
|
var cache = new CompilerCache(fileProvider);
|
|
var expected = new CompilationResult(typeof(TestView));
|
|
|
|
// Act - 1
|
|
var result1 = cache.GetOrAdd(@"Areas\Finances\Views\Home\Index.cshtml", CreateContextFactory(expected));
|
|
|
|
// Assert - 1
|
|
Assert.Equal(typeof(TestView), result1.CompiledType);
|
|
|
|
// Act - 2
|
|
var result2 = cache.GetOrAdd(relativePath, ThrowsIfCalled);
|
|
|
|
// Assert - 2
|
|
Assert.Equal(typeof(TestView), result2.CompiledType);
|
|
}
|
|
|
|
[Fact]
|
|
public void GetOrAdd_ReturnsFailedCompilationResult_IfFileWasRemovedFromFileSystem()
|
|
{
|
|
// Arrange
|
|
var fileProvider = new TestFileProvider();
|
|
var fileInfo = fileProvider.AddFile(ViewPath, "some content");
|
|
|
|
var foundItem = new FileProviderRazorProjectItem(fileInfo, "", ViewPath);
|
|
|
|
var notFoundItem = new Mock<RazorProjectItem>();
|
|
notFoundItem
|
|
.SetupGet(i => i.Path)
|
|
.Returns(ViewPath);
|
|
notFoundItem
|
|
.SetupGet(i => i.Exists)
|
|
.Returns(false);
|
|
|
|
var cache = new CompilerCache(fileProvider);
|
|
var expected = new CompilationResult(typeof(TestView));
|
|
var cacheContext = new CompilerCacheContext(foundItem, Enumerable.Empty<RazorProjectItem>(), _ => expected);
|
|
|
|
// Act 1
|
|
var result1 = cache.GetOrAdd(ViewPath, _ => cacheContext);
|
|
|
|
// Assert 1
|
|
Assert.True(result1.Success);
|
|
Assert.Equal(typeof(TestView), result1.CompiledType);
|
|
|
|
// Act 2
|
|
// Delete the file from the file system and set it's expiration token.
|
|
cacheContext = new CompilerCacheContext(
|
|
new NotFoundProjectItem("", ViewPath),
|
|
Enumerable.Empty<RazorProjectItem>(),
|
|
_ => throw new Exception("Shouldn't be called."));
|
|
fileProvider.GetChangeToken(ViewPath).HasChanged = true;
|
|
var result2 = cache.GetOrAdd(ViewPath, _ => cacheContext);
|
|
|
|
// Assert 2
|
|
Assert.False(result2.Success);
|
|
}
|
|
|
|
[Fact]
|
|
public void GetOrAdd_ReturnsNewResultIfFileWasModified()
|
|
{
|
|
// Arrange
|
|
var fileProvider = new TestFileProvider();
|
|
fileProvider.AddFile(ViewPath, "some content");
|
|
var cache = new CompilerCache(fileProvider);
|
|
var expected1 = new CompilationResult(typeof(TestView));
|
|
var expected2 = new CompilationResult(typeof(DifferentView));
|
|
|
|
// Act 1
|
|
var result1 = cache.GetOrAdd(ViewPath, CreateContextFactory(expected1));
|
|
|
|
// Assert 1
|
|
Assert.True(result1.Success);
|
|
Assert.Equal(typeof(TestView), result1.CompiledType);
|
|
|
|
// Act 2
|
|
// Verify we're getting cached results.
|
|
var result2 = cache.GetOrAdd(ViewPath, ThrowsIfCalled);
|
|
|
|
// Assert 2
|
|
Assert.True(result2.Success);
|
|
Assert.Equal(typeof(TestView), result1.CompiledType);
|
|
|
|
// Act 3
|
|
fileProvider.GetChangeToken(ViewPath).HasChanged = true;
|
|
var result3 = cache.GetOrAdd(ViewPath, CreateContextFactory(expected2));
|
|
|
|
// Assert 3
|
|
Assert.True(result3.Success);
|
|
Assert.Equal(typeof(DifferentView), result3.CompiledType);
|
|
}
|
|
|
|
[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(fileProvider);
|
|
var expected1 = new CompilationResult(typeof(TestView));
|
|
var expected2 = new CompilationResult(typeof(DifferentView));
|
|
|
|
// Act 1
|
|
var result1 = cache.GetOrAdd(ViewPath, CreateContextFactory(expected1));
|
|
|
|
// Assert 1
|
|
Assert.True(result1.Success);
|
|
Assert.Equal(typeof(TestView), result1.CompiledType);
|
|
|
|
// Act 2
|
|
// Verify we're getting cached results.
|
|
var result2 = cache.GetOrAdd(ViewPath, ThrowsIfCalled);
|
|
|
|
// Assert 2
|
|
Assert.True(result2.Success);
|
|
Assert.Equal(typeof(TestView), result1.CompiledType);
|
|
|
|
// Act 3
|
|
fileProvider.GetChangeToken(globalImportPath).HasChanged = true;
|
|
var result3 = cache.GetOrAdd(ViewPath, CreateContextFactory(expected2));
|
|
|
|
// Assert 2
|
|
Assert.True(result3.Success);
|
|
Assert.Equal(typeof(DifferentView), result3.CompiledType);
|
|
}
|
|
|
|
[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(fileProvider);
|
|
var expected = new CompilationResult(typeof(TestView));
|
|
|
|
// Act 1
|
|
var result1 = cache.GetOrAdd(ViewPath, CreateContextFactory(expected));
|
|
|
|
// Assert 1
|
|
Assert.True(result1.Success);
|
|
Assert.Equal(typeof(TestView), result1.CompiledType);
|
|
|
|
// Act 2
|
|
var result2 = cache.GetOrAdd(ViewPath, ThrowsIfCalled);
|
|
|
|
// Assert 2
|
|
Assert.True(result2.Success);
|
|
}
|
|
|
|
[Fact]
|
|
public void GetOrAdd_UsesViewsSpecifiedFromRazorFileInfoCollection()
|
|
{
|
|
// Arrange
|
|
var fileProvider = new TestFileProvider();
|
|
var cache = new CompilerCache(fileProvider, _precompiledViews);
|
|
|
|
// Act
|
|
var result = cache.GetOrAdd(PrecompiledViewsPath, ThrowsIfCalled);
|
|
|
|
// Assert
|
|
Assert.True(result.Success);
|
|
Assert.Equal(typeof(PreCompile), result.CompiledType);
|
|
Assert.Same(PrecompiledViewsPath, result.RelativePath);
|
|
}
|
|
|
|
[Fact]
|
|
public void GetOrAdd_DoesNotRecompile_IfFileTriggerWasSetForPrecompiledFile()
|
|
{
|
|
// Arrange
|
|
var fileProvider = new TestFileProvider();
|
|
var cache = new CompilerCache(fileProvider, _precompiledViews);
|
|
|
|
// Act
|
|
fileProvider.Watch(PrecompiledViewsPath);
|
|
fileProvider.GetChangeToken(PrecompiledViewsPath).HasChanged = true;
|
|
var result = cache.GetOrAdd(PrecompiledViewsPath, ThrowsIfCalled);
|
|
|
|
// Assert
|
|
Assert.True(result.Success);
|
|
Assert.True(result.IsPrecompiled);
|
|
Assert.Equal(typeof(PreCompile), result.CompiledType);
|
|
}
|
|
|
|
[Theory]
|
|
[MemberData(nameof(ViewImportsPaths))]
|
|
public void GetOrAdd_DoesNotRecompile_IfFileTriggerWasSetForViewImports(string globalImportPath)
|
|
{
|
|
// Arrange
|
|
var fileProvider = new TestFileProvider();
|
|
var cache = new CompilerCache(fileProvider, _precompiledViews);
|
|
|
|
// Act
|
|
fileProvider.Watch(globalImportPath);
|
|
fileProvider.GetChangeToken(globalImportPath).HasChanged = true;
|
|
var result = cache.GetOrAdd(PrecompiledViewsPath, ThrowsIfCalled);
|
|
|
|
// Assert
|
|
Assert.True(result.Success);
|
|
Assert.Equal(typeof(PreCompile), result.CompiledType);
|
|
}
|
|
|
|
[Fact]
|
|
public void GetOrAdd_ReturnsRuntimeCompiled()
|
|
{
|
|
// Arrange
|
|
var fileProvider = new TestFileProvider();
|
|
fileProvider.AddFile(ViewPath, "some content");
|
|
var cache = new CompilerCache(fileProvider, _precompiledViews);
|
|
var expected = new CompilationResult(typeof(TestView));
|
|
|
|
// Act 1
|
|
var result1 = cache.GetOrAdd(ViewPath, CreateContextFactory(expected));
|
|
|
|
// Assert 1
|
|
Assert.Equal(typeof(TestView), result1.CompiledType);
|
|
|
|
// Act 2
|
|
var result2 = cache.GetOrAdd(ViewPath, ThrowsIfCalled);
|
|
|
|
// Assert 2
|
|
Assert.True(result2.Success);
|
|
Assert.Equal(typeof(TestView), result2.CompiledType);
|
|
}
|
|
|
|
[Fact]
|
|
public void GetOrAdd_ReturnsPrecompiledViews()
|
|
{
|
|
// Arrange
|
|
var fileProvider = new TestFileProvider();
|
|
var cache = new CompilerCache(fileProvider, _precompiledViews);
|
|
var expected = new CompilationResult(typeof(TestView));
|
|
|
|
// Act
|
|
var result1 = cache.GetOrAdd(PrecompiledViewsPath, ThrowsIfCalled);
|
|
|
|
// Assert
|
|
Assert.Equal(typeof(PreCompile), result1.CompiledType);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData("/Areas/Finances/Views/Home/Index.cshtml")]
|
|
[InlineData(@"Areas\Finances\Views\Home\Index.cshtml")]
|
|
[InlineData(@"\Areas\Finances\Views\Home\Index.cshtml")]
|
|
[InlineData(@"\Areas\Finances\Views/Home\Index.cshtml")]
|
|
public void GetOrAdd_NormalizesPathSepartorForPathsThatArePrecompiled(string relativePath)
|
|
{
|
|
// Arrange
|
|
var expected = typeof(PreCompile);
|
|
var viewPath = "/Areas/Finances/Views/Home/Index.cshtml";
|
|
var cache = new CompilerCache(
|
|
new TestFileProvider(),
|
|
new Dictionary<string, Type>
|
|
{
|
|
{ viewPath, expected }
|
|
});
|
|
|
|
// Act
|
|
var result = cache.GetOrAdd(relativePath, ThrowsIfCalled);
|
|
|
|
// Assert
|
|
Assert.Equal(typeof(PreCompile), result.CompiledType);
|
|
Assert.Equal(viewPath, result.RelativePath);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(@"Areas\Finances\Views\Home\Index.cshtml")]
|
|
[InlineData(@"\Areas\Finances\Views\Home\Index.cshtml")]
|
|
[InlineData(@"\Areas\Finances\Views/Home\Index.cshtml")]
|
|
public void ConstructorNormalizesPrecompiledViewPath(string viewPath)
|
|
{
|
|
// Arrange
|
|
var expected = typeof(PreCompile);
|
|
var cache = new CompilerCache(
|
|
new TestFileProvider(),
|
|
new Dictionary<string, Type>
|
|
{
|
|
{ viewPath, expected }
|
|
});
|
|
|
|
// Act
|
|
var result = cache.GetOrAdd("/Areas/Finances/Views/Home/Index.cshtml", ThrowsIfCalled);
|
|
|
|
// Assert
|
|
Assert.Equal(typeof(PreCompile), result.CompiledType);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task GetOrAdd_AllowsConcurrentCompilationOfMultipleRazorPages()
|
|
{
|
|
// Arrange
|
|
var waitDuration = TimeSpan.FromSeconds(20);
|
|
var fileProvider = new TestFileProvider();
|
|
fileProvider.AddFile("/Views/Home/Index.cshtml", "Index content");
|
|
fileProvider.AddFile("/Views/Home/About.cshtml", "About content");
|
|
var resetEvent1 = new AutoResetEvent(initialState: false);
|
|
var resetEvent2 = new ManualResetEvent(initialState: false);
|
|
var cache = new CompilerCache(fileProvider);
|
|
var compilingOne = false;
|
|
var compilingTwo = false;
|
|
|
|
Func<CompilerCacheContext, CompilationResult> compile1 = _ =>
|
|
{
|
|
compilingOne = true;
|
|
|
|
// Event 2
|
|
Assert.True(resetEvent1.WaitOne(waitDuration));
|
|
|
|
// Event 3
|
|
Assert.True(resetEvent2.Set());
|
|
|
|
// Event 6
|
|
Assert.True(resetEvent1.WaitOne(waitDuration));
|
|
|
|
Assert.True(compilingTwo);
|
|
return new CompilationResult(typeof(TestView));
|
|
};
|
|
|
|
Func<CompilerCacheContext, CompilationResult> compile2 = _ =>
|
|
{
|
|
compilingTwo = true;
|
|
|
|
// Event 4
|
|
Assert.True(resetEvent2.WaitOne(waitDuration));
|
|
|
|
// Event 5
|
|
Assert.True(resetEvent1.Set());
|
|
|
|
Assert.True(compilingOne);
|
|
return new CompilationResult(typeof(DifferentView));
|
|
};
|
|
|
|
|
|
// Act
|
|
var task1 = Task.Run(() =>
|
|
{
|
|
return cache.GetOrAdd("/Views/Home/Index.cshtml", path =>
|
|
{
|
|
var projectItem = new FileProviderRazorProjectItem(new TestFileInfo(), "", path);
|
|
return new CompilerCacheContext(projectItem, Enumerable.Empty<RazorProjectItem>(), compile1);
|
|
});
|
|
});
|
|
|
|
var task2 = Task.Run(() =>
|
|
{
|
|
// Event 4
|
|
return cache.GetOrAdd("/Views/Home/About.cshtml", path =>
|
|
{
|
|
var projectItem = new FileProviderRazorProjectItem(new TestFileInfo(), "", path);
|
|
return new CompilerCacheContext(projectItem, Enumerable.Empty<RazorProjectItem>(), compile2);
|
|
});
|
|
});
|
|
|
|
// Event 1
|
|
resetEvent1.Set();
|
|
|
|
await Task.WhenAll(task1, task2);
|
|
|
|
// Assert
|
|
var result1 = task1.Result;
|
|
var result2 = task2.Result;
|
|
Assert.True(compilingOne);
|
|
Assert.True(compilingTwo);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task GetOrAdd_DoesNotCreateMultipleCompilationResults_ForConcurrentInvocations()
|
|
{
|
|
// Arrange
|
|
var waitDuration = TimeSpan.FromSeconds(20);
|
|
var fileProvider = new TestFileProvider();
|
|
fileProvider.AddFile(ViewPath, "some content");
|
|
var resetEvent1 = new ManualResetEvent(initialState: false);
|
|
var resetEvent2 = new ManualResetEvent(initialState: false);
|
|
var cache = new CompilerCache(fileProvider);
|
|
|
|
Func<CompilerCacheContext, CompilationResult> compile = _ =>
|
|
{
|
|
// Event 2
|
|
resetEvent1.WaitOne(waitDuration);
|
|
|
|
// Event 3
|
|
resetEvent2.Set();
|
|
return new CompilationResult(typeof(TestView));
|
|
};
|
|
|
|
// Act
|
|
var task1 = Task.Run(() =>
|
|
{
|
|
return cache.GetOrAdd(ViewPath, path =>
|
|
{
|
|
var projectItem = new FileProviderRazorProjectItem(new TestFileInfo(), "", path);
|
|
return new CompilerCacheContext(projectItem, Enumerable.Empty<RazorProjectItem>(), compile);
|
|
});
|
|
});
|
|
|
|
var task2 = Task.Run(() =>
|
|
{
|
|
// Event 4
|
|
Assert.True(resetEvent2.WaitOne(waitDuration));
|
|
return cache.GetOrAdd(ViewPath, ThrowsIfCalled);
|
|
});
|
|
|
|
// Event 1
|
|
resetEvent1.Set();
|
|
await Task.WhenAll(task1, task2);
|
|
|
|
// Assert
|
|
var result1 = task1.Result;
|
|
var result2 = task2.Result;
|
|
Assert.Same(result1.CompiledType, result2.CompiledType);
|
|
}
|
|
|
|
[Fact]
|
|
public void GetOrAdd_ThrowsIfNullFileProvider()
|
|
{
|
|
// Arrange
|
|
var expected =
|
|
$"'{typeof(RazorViewEngineOptions).FullName}.{nameof(RazorViewEngineOptions.FileProviders)}' must " +
|
|
$"not be empty. At least one '{typeof(IFileProvider).FullName}' is required to locate a view for " +
|
|
"rendering.";
|
|
var fileProvider = new NullFileProvider();
|
|
var cache = new CompilerCache(fileProvider);
|
|
|
|
// Act & Assert
|
|
var exception = Assert.Throws<InvalidOperationException>(
|
|
() => cache.GetOrAdd(ViewPath, _ => { throw new InvalidTimeZoneException(); }));
|
|
Assert.Equal(expected, exception.Message);
|
|
}
|
|
|
|
[Fact]
|
|
public void GetOrAdd_CachesCompilationExceptions()
|
|
{
|
|
// Arrange
|
|
var fileProvider = new TestFileProvider();
|
|
fileProvider.AddFile(ViewPath, "some content");
|
|
var cache = new CompilerCache(fileProvider);
|
|
var exception = new InvalidTimeZoneException();
|
|
|
|
// Act and Assert - 1
|
|
var actual = Assert.Throws<InvalidTimeZoneException>(() =>
|
|
cache.GetOrAdd(ViewPath, _ => ThrowsIfCalled(ViewPath, exception)));
|
|
Assert.Same(exception, actual);
|
|
|
|
// Act and Assert - 2
|
|
actual = Assert.Throws<InvalidTimeZoneException>(() => cache.GetOrAdd(ViewPath, ThrowsIfCalled));
|
|
Assert.Same(exception, actual);
|
|
}
|
|
|
|
[Fact]
|
|
public void GetOrAdd_ReturnsSuccessfulCompilationResultIfTriggerExpires()
|
|
{
|
|
// Arrange
|
|
var fileProvider = new TestFileProvider();
|
|
fileProvider.AddFile(ViewPath, "some content");
|
|
var changeToken = fileProvider.AddChangeToken(ViewPath);
|
|
var cache = new CompilerCache(fileProvider);
|
|
|
|
// Act and Assert - 1
|
|
Assert.Throws<InvalidTimeZoneException>(() =>
|
|
cache.GetOrAdd(ViewPath, _ => { throw new InvalidTimeZoneException(); }));
|
|
|
|
// Act - 2
|
|
changeToken.HasChanged = true;
|
|
var result = cache.GetOrAdd(ViewPath, CreateContextFactory(new CompilationResult(typeof(TestView))));
|
|
|
|
// Assert - 2
|
|
Assert.Same(typeof(TestView), result.CompiledType);
|
|
}
|
|
|
|
[Fact]
|
|
public void GetOrAdd_CachesExceptionsInCompilationResult()
|
|
{
|
|
// Arrange
|
|
var fileProvider = new TestFileProvider();
|
|
fileProvider.AddFile(ViewPath, "some content");
|
|
var cache = new CompilerCache(fileProvider);
|
|
var diagnosticMessages = new[]
|
|
{
|
|
new DiagnosticMessage("message", "message", ViewPath, 1, 1, 1, 1)
|
|
};
|
|
var compilationResult = new CompilationResult(new[]
|
|
{
|
|
new CompilationFailure(ViewPath, "some content", "compiled content", diagnosticMessages)
|
|
});
|
|
var context = CreateContextFactory(compilationResult);
|
|
|
|
// Act and Assert - 1
|
|
var ex = Assert.Throws<CompilationFailedException>(() => cache.GetOrAdd(ViewPath, context));
|
|
Assert.Same(compilationResult.CompilationFailures, ex.CompilationFailures);
|
|
|
|
// Act and Assert - 2
|
|
ex = Assert.Throws<CompilationFailedException>(() => cache.GetOrAdd(ViewPath, ThrowsIfCalled));
|
|
Assert.Same(compilationResult.CompilationFailures, ex.CompilationFailures);
|
|
}
|
|
|
|
private class TestView : RazorPage
|
|
{
|
|
public override Task ExecuteAsync()
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
}
|
|
|
|
private class PreCompile : RazorPage
|
|
{
|
|
public override Task ExecuteAsync()
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
}
|
|
|
|
public class DifferentView : RazorPage
|
|
{
|
|
public override Task ExecuteAsync()
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
}
|
|
|
|
private CompilerCacheContext ThrowsIfCalled(string path) =>
|
|
ThrowsIfCalled(path, new Exception("Shouldn't be called"));
|
|
|
|
private CompilerCacheContext ThrowsIfCalled(string path, Exception exception)
|
|
{
|
|
exception = exception ?? new Exception("Shouldn't be called");
|
|
var projectItem = new FileProviderRazorProjectItem(new TestFileInfo(), "", path);
|
|
|
|
return new CompilerCacheContext(
|
|
projectItem,
|
|
Enumerable.Empty<RazorProjectItem>(),
|
|
_ => throw exception);
|
|
}
|
|
|
|
private Func<string, CompilerCacheContext> CreateContextFactory(CompilationResult compile)
|
|
{
|
|
return path => CreateCacheContext(compile, path);
|
|
}
|
|
|
|
private CompilerCacheContext CreateCacheContext(CompilationResult compile, string path = ViewPath)
|
|
{
|
|
var projectItem = new FileProviderRazorProjectItem(new TestFileInfo(), "", path);
|
|
|
|
var imports = new List<RazorProjectItem>();
|
|
foreach (var importFilePath in _viewImportsPath)
|
|
{
|
|
var importProjectItem = new FileProviderRazorProjectItem(new TestFileInfo(), "", importFilePath);
|
|
|
|
imports.Add(importProjectItem);
|
|
}
|
|
|
|
return new CompilerCacheContext(projectItem, imports, _ => compile);
|
|
}
|
|
}
|
|
} |