public void GetInheritedChunks_ReadsChunksFromGlobalFilesInPath()
        {
            // Arrange
            var fileProvider = new TestFileProvider();
            fileProvider.AddFile(@"Views\accounts\_GlobalImport.cshtml", "@using AccountModels");
            fileProvider.AddFile(@"Views\Shared\_GlobalImport.cshtml", "@inject SharedHelper Shared");
            fileProvider.AddFile(@"Views\home\_GlobalImport.cshtml", "@using MyNamespace");
            fileProvider.AddFile(@"Views\_GlobalImport.cshtml",
@"@inject MyHelper<TModel> Helper
@inherits MyBaseType

@{
    Layout = ""test.cshtml"";
}

");
            var defaultChunks = new Chunk[]
            {
                new InjectChunk("MyTestHtmlHelper", "Html"),
                new UsingChunk { Namespace = "AppNamespace.Model" },
            };
            var cache = new DefaultCodeTreeCache(fileProvider);
            var host = new MvcRazorHost(cache);
            var utility = new ChunkInheritanceUtility(host, cache, defaultChunks);

            // Act
            var codeTrees = utility.GetInheritedCodeTrees(@"Views\home\Index.cshtml");

            // Assert
            Assert.Equal(2, codeTrees.Count);
            var viewStartChunks = codeTrees[0].Chunks;
            Assert.Equal(3, viewStartChunks.Count);

            Assert.IsType<LiteralChunk>(viewStartChunks[0]);
            var usingChunk = Assert.IsType<UsingChunk>(viewStartChunks[1]);
            Assert.Equal("MyNamespace", usingChunk.Namespace);
            Assert.IsType<LiteralChunk>(viewStartChunks[2]);

            viewStartChunks = codeTrees[1].Chunks;
            Assert.Equal(5, viewStartChunks.Count);

            Assert.IsType<LiteralChunk>(viewStartChunks[0]);

            var injectChunk = Assert.IsType<InjectChunk>(viewStartChunks[1]);
            Assert.Equal("MyHelper<TModel>", injectChunk.TypeName);
            Assert.Equal("Helper", injectChunk.MemberName);

            var setBaseTypeChunk = Assert.IsType<SetBaseTypeChunk>(viewStartChunks[2]);
            Assert.Equal("MyBaseType", setBaseTypeChunk.TypeName);

            Assert.IsType<StatementChunk>(viewStartChunks[3]);
            Assert.IsType<LiteralChunk>(viewStartChunks[4]);
        }
        public void Compile_ReturnsCompilationFailureWithPathsFromLinePragmas()
        {
            // Arrange
            var viewPath = "some-relative-path";
            var fileContent = "test file content";
            var content = $@"
#line 1 ""{viewPath}""
this should fail";
            var fileProvider = new TestFileProvider();
            var fileInfo = fileProvider.AddFile(viewPath, fileContent);

            var compilationService = new DefaultRoslynCompilationService(
                GetDependencyContext(),
                GetOptions(),
                GetFileProviderAccessor(fileProvider),
                NullLoggerFactory.Instance);
            var relativeFileInfo = new RelativeFileInfo(fileInfo, "some-relative-path");

            // Act
            var result = compilationService.Compile(relativeFileInfo, content);

            // Assert
            Assert.IsType<CompilationResult>(result);
            Assert.Null(result.CompiledType);
            var compilationFailure = Assert.Single(result.CompilationFailures);
            Assert.Equal(relativeFileInfo.RelativePath, compilationFailure.SourceFilePath);
            Assert.Equal(fileContent, compilationFailure.SourceFileContent);
        }
        public void Compile_ReturnsCompilationFailureWithPathsFromLinePragmas()
        {
            // Arrange
            var viewPath = "some-relative-path";
            var fileContent = "test file content";
            var content = $@"
#line 1 ""{viewPath}""
this should fail";
            var applicationEnvironment = PlatformServices.Default.Application;
            var libraryExporter = CompilationServices.Default.LibraryExporter;
            var mvcRazorHost = Mock.Of<IMvcRazorHost>();
            var fileProvider = new TestFileProvider();
            var fileInfo = fileProvider.AddFile(viewPath, fileContent);

            var compilationService = new RoslynCompilationService(
                applicationEnvironment,
                libraryExporter,
                mvcRazorHost,
                GetOptions(),
                GetFileProviderAccessor(fileProvider),
                NullLoggerFactory.Instance);
            var relativeFileInfo = new RelativeFileInfo(fileInfo, "some-relative-path");

            // Act
            var result = compilationService.Compile(relativeFileInfo, content);

            // Assert
            Assert.IsType<CompilationResult>(result);
            Assert.Null(result.CompiledType);
            var compilationFailure = Assert.Single(result.CompilationFailures);
            Assert.Equal(relativeFileInfo.RelativePath, compilationFailure.SourceFilePath);
            Assert.Equal(fileContent, compilationFailure.SourceFileContent);
        }
        public void GetOrAdd_UpdatesCache_IfFileExpirationTriggerExpires()
        {
            // Arrange
            var path = @"Views\Home\_ViewStart.cshtml";
            var fileProvider = new TestFileProvider();
            fileProvider.AddFile(path, "test content");
            using (var chunkTreeCache = new DefaultChunkTreeCache(fileProvider))
            {
                var expected1 = new ChunkTree();
                var expected2 = new ChunkTree();

                // Act 1
                var result1 = chunkTreeCache.GetOrAdd(path, fileInfo => expected1);

                // Assert 1
                Assert.Same(expected1, result1);

                // Act 2
                fileProvider.GetChangeToken(path).HasChanged = true;
                var result2 = chunkTreeCache.GetOrAdd(path, fileInfo => expected2);

                // Assert 2
                Assert.Same(expected2, result2);
            }
        }
        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);
        }
        public void GetInheritedChunks_ReturnsEmptySequenceIfNoGlobalsArePresent()
        {
            // Arrange
            var fileProvider = new TestFileProvider();
            fileProvider.AddFile(@"_GlobalImport.cs", string.Empty);
            fileProvider.AddFile(@"Views\_Layout.cshtml", string.Empty);
            fileProvider.AddFile(@"Views\home\_not-globalimport.cshtml", string.Empty);
            var cache = new DefaultCodeTreeCache(fileProvider);
            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);

            // Act
            var codeTrees = utility.GetInheritedCodeTrees(@"Views\home\Index.cshtml");

            // Assert
            Assert.Empty(codeTrees);
        }
Beispiel #7
0
        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, _ => expected);

            // Assert
            Assert.True(result.Success);
            Assert.IsType<TestView>(result.PageFactory());
            Assert.Same(ViewPath, result.PageFactory().Path);
        }
Beispiel #8
0
        public void GetOrAdd_ReturnsCompilationResultFromFactory()
        {
            // Arrange
            var fileProvider = new TestFileProvider();
            fileProvider.AddFile(ViewPath, "some content");
            var cache = new CompilerCache(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);
        }
        public async Task CompileAsync_AddsChangeTokensForViewStartsIfFileExists()
        {
            // Arrange
            var path         = "/file/exists/FilePath.cshtml";
            var fileProvider = new TestFileProvider();

            fileProvider.AddFile(path, "Content");
            var viewCompiler = GetViewCompiler(fileProvider);

            // Act
            var result = await viewCompiler.CompileAsync(path);

            // Assert
            Assert.NotNull(result.ViewAttribute);
            Assert.Collection(
                result.ExpirationTokens,
                token => Assert.Same(fileProvider.GetChangeToken(path), token),
                token => Assert.Same(fileProvider.GetChangeToken("/file/exists/_ViewImports.cshtml"), token),
                token => Assert.Same(fileProvider.GetChangeToken("/file/_ViewImports.cshtml"), token),
                token => Assert.Same(fileProvider.GetChangeToken("/_ViewImports.cshtml"), token));
        }
Beispiel #10
0
        public async Task CompileAsync_ReturnsPrecompiledViews()
        {
            // Arrange
            var path            = "/Views/Home/Index.cshtml";
            var fileProvider    = new TestFileProvider();
            var fileInfo        = fileProvider.AddFile(path, "some content");
            var precompiledView = new CompiledViewDescriptor
            {
                RelativePath = path,
            };
            var viewCompiler = GetViewCompiler(fileProvider, precompiledViews: new[] { precompiledView });

            // Act
            var result = await viewCompiler.CompileAsync(path);

            // Assert
            Assert.Same(precompiledView, result);

            // This view doesn't have checksums so it can't be recompiled.
            Assert.Null(precompiledView.ExpirationTokens);
        }
Beispiel #11
0
            private IFileProvider GetFileProvider()
            {
                TestFileProvider fileProvider = new TestFileProvider();

                fileProvider.AddDirectory("/");
                fileProvider.AddDirectory("/a");
                fileProvider.AddDirectory("/b");

                fileProvider.AddFile("/a/1.md", @"File a1");
                fileProvider.AddFile("/a/1.md.meta", @"data: a1");
                fileProvider.AddFile("/a/1.md.other", @"data: other");
                fileProvider.AddFile("/a/2.md", @"File a2");
                fileProvider.AddFile("/a/2.md.meta", @"data: a2");

                fileProvider.AddFile("/b/1.md", @"File b1");
                fileProvider.AddFile("/b/1.md.meta", @"data: b1");

                return(fileProvider);
            }
Beispiel #12
0
        private IFileProvider GetFileProvider()
        {
            TestFileProvider fileProvider = new TestFileProvider();

            fileProvider.AddDirectory("/");
            fileProvider.AddDirectory("/TestFiles");
            fileProvider.AddDirectory("/TestFiles/Input");
            fileProvider.AddDirectory("/TestFiles/Input/Subfolder");

            fileProvider.AddFile("/TestFiles/test-above-input.txt", "test");
            fileProvider.AddFile("/TestFiles/Input/markdown-x.md", "xxx");
            fileProvider.AddFile("/TestFiles/Input/test-a.txt", "aaa");
            fileProvider.AddFile("/TestFiles/Input/test-b.txt", "bbb");
            fileProvider.AddFile("/TestFiles/Input/Subfolder/markdown-y.md", "yyy");
            fileProvider.AddFile("/TestFiles/Input/Subfolder/test-c.txt", "ccc");
            fileProvider.AddFile("/TestFiles/Input/.dotfile", "dotfile");

            return(fileProvider);
        }
Beispiel #13
0
        public void Compile_DoesNotThrow_IfFileCannotBeRead()
        {
            // Arrange
            var path    = "some-relative-path";
            var content = $@"
#line 1 ""{path}""
this should fail";
            var applicationEnvironment = PlatformServices.Default.Application;
            var libraryExporter        = CompilationServices.Default.LibraryExporter;
            var mvcRazorHost           = Mock.Of <IMvcRazorHost>();

            var mockFileInfo = new Mock <IFileInfo>();

            mockFileInfo.Setup(f => f.CreateReadStream())
            .Throws(new Exception());
            var fileProvider = new TestFileProvider();

            fileProvider.AddFile(path, mockFileInfo.Object);

            var compilationService = new RoslynCompilationService(
                applicationEnvironment,
                libraryExporter,
                mvcRazorHost,
                GetOptions(),
                GetFileProviderAccessor(fileProvider),
                NullLoggerFactory.Instance);

            var relativeFileInfo = new RelativeFileInfo(mockFileInfo.Object, path);

            // Act
            var result = compilationService.Compile(relativeFileInfo, content);

            // Assert
            Assert.IsType <CompilationResult>(result);
            Assert.Null(result.CompiledType);
            var compilationFailure = Assert.Single(result.CompilationFailures);

            Assert.Equal(path, compilationFailure.SourceFilePath);
            Assert.Null(compilationFailure.SourceFileContent);
        }
Beispiel #14
0
        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", _ => expected);

            // Assert - 1
            Assert.IsType<TestView>(result1.PageFactory());

            // Act - 2
            var result2 = cache.GetOrAdd(relativePath, ThrowsIfCalled);

            // Assert - 2
            Assert.IsType<TestView>(result2.PageFactory());
            Assert.Same(result1.PageFactory, result2.PageFactory);
        }
        public void OnProvidersExecuting_ThrowsIfRouteTemplateHasOverridePattern()
        {
            // Arrange
            var fileProvider = new TestFileProvider();
            var file         = fileProvider.AddFile("/Index.cshtml", "@page \"/custom-route\"");

            fileProvider.AddDirectoryContent("/", new[] { file });

            var project = new TestRazorProject(fileProvider);

            var optionsManager = Options.Create(new RazorPagesOptions());

            optionsManager.Value.RootDirectory = "/";
            var provider = new RazorProjectPageRouteModelProvider(project, optionsManager, NullLoggerFactory.Instance);
            var context  = new PageRouteModelProviderContext();

            // Act & Assert
            var ex = Assert.Throws <InvalidOperationException>(() => provider.OnProvidersExecuting(context));

            Assert.Equal("The route for the page at '/Index.cshtml' cannot start with / or ~/. Pages do not support overriding the file path of the page.",
                         ex.Message);
        }
Beispiel #16
0
        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);
        }
Beispiel #17
0
        public void GetOrAdd_UpdatesCacheWithValue_IfFileWasAdded()
        {
            // Arrange
            var path           = @"Views\Home\_ViewStart.cshtml";
            var fileProvider   = new TestFileProvider();
            var chunkTreeCache = new DefaultChunkTreeCache(fileProvider);
            var expected       = new ChunkTree();

            // Act 1
            var result1 = chunkTreeCache.GetOrAdd(path, fileInfo => { throw new Exception("Shouldn't be called."); });

            // Assert 1
            Assert.Null(result1);

            // Act 2
            fileProvider.AddFile(path, "test content");
            fileProvider.GetTrigger(path).IsExpired = true;
            var result2 = chunkTreeCache.GetOrAdd(path, fileInfo => expected);

            // Assert 2
            Assert.Same(expected, result2);
        }
        public void Compile_ReturnsCompilationFailureWithPathsFromLinePragmas()
        {
            // Arrange
            var viewPath = "some-relative-path";
            var fileContent = "test file content";
            var content = $@"
#line 1 ""{viewPath}""
this should fail";
            var applicationEnvironment = GetApplicationEnvironment();
            var accessor = GetLoadContextAccessor();
            var libraryExporter = GetLibraryExporter();

            var compilerOptionsProvider = new Mock<ICompilerOptionsProvider>();
            compilerOptionsProvider.Setup(p => p.GetCompilerOptions(applicationEnvironment.ApplicationName,
                                                                    applicationEnvironment.RuntimeFramework,
                                                                    applicationEnvironment.Configuration))
                                   .Returns(new CompilerOptions());
            var mvcRazorHost = Mock.Of<IMvcRazorHost>();
            var fileProvider = new TestFileProvider();
            var fileInfo = fileProvider.AddFile(viewPath, fileContent);

            var compilationService = new RoslynCompilationService(applicationEnvironment,
                                                                  accessor,
                                                                  libraryExporter,
                                                                  compilerOptionsProvider.Object,
                                                                  mvcRazorHost,
                                                                  GetOptions(fileProvider));
            var relativeFileInfo = new RelativeFileInfo(fileInfo, "some-relative-path");

            // Act
            var result = compilationService.Compile(relativeFileInfo, content);

            // Assert
            Assert.IsType<CompilationResult>(result);
            Assert.Null(result.CompiledType);
            var compilationFailure = Assert.Single(result.CompilationFailures);
            Assert.Equal(relativeFileInfo.RelativePath, compilationFailure.SourceFilePath);
            Assert.Equal(fileContent, compilationFailure.SourceFileContent);
        }
Beispiel #19
0
            public void ShouldReturnExistingFiles(string directory, string[] patterns, string[] expected)
            {
                TestContext.Out.WriteLine($"Patterns: {string.Join(",", patterns)}");

                // Given
                FileSystem fileSystem = new FileSystem();

                fileSystem.FileProviders.Add(string.Empty, GetFileProvider());
                TestFileProvider alternateProvider = new TestFileProvider();

                alternateProvider.AddDirectory("/");
                alternateProvider.AddDirectory("/q");
                alternateProvider.AddFile("/q/werty.txt");
                fileSystem.FileProviders.Add("qwerty", alternateProvider);
                IDirectory dir = fileSystem.GetDirectory(directory);

                // When
                IEnumerable <IFile> results = fileSystem.GetFiles(dir, patterns);

                // Then
                CollectionAssert.AreEquivalent(expected, results.Select(x => x.Path.FullPath));
            }
Beispiel #20
0
        public async Task CompileAsync_PrecompiledViewWithChecksum_CanRecompile()
        {
            // Arrange
            var path = "/Views/Home/Index.cshtml";

            var fileProvider = new TestFileProvider();
            var fileInfo     = fileProvider.AddFile(path, "some content");

            var expected2 = new CompiledViewDescriptor();

            var precompiledView = new CompiledViewDescriptor
            {
                RelativePath = path,
                Item         = new TestRazorCompiledItem(typeof(string), "mvc.1.0.view", path, new object[]
                {
                    new RazorSourceChecksumAttribute("SHA1", GetChecksum("some content"), path),
                }),
            };

            var viewCompiler = GetViewCompiler(fileProvider, precompiledViews: new[] { precompiledView });

            viewCompiler.AllowRecompilingViewsOnFileChange = true;

            // Act - 1
            var result = await viewCompiler.CompileAsync(path);

            // Assert - 1
            Assert.Same(precompiledView.Item, result.Item);
            Assert.NotEmpty(result.ExpirationTokens);

            // Act - 2
            fileInfo.Content = "some other content";
            fileProvider.GetChangeToken(path).HasChanged = true;
            viewCompiler.Compile = _ => expected2;
            result = await viewCompiler.CompileAsync(path);

            // Assert - 2
            Assert.Same(expected2, result);
        }
        public void LookupFileInfo_ReturnsTrue_IfFileExists()
        {
            // Arrange
            var options = new StaticFileOptions();
            var fileProvider = new TestFileProvider();
            fileProvider.AddFile("/foo.txt", new TestFileInfo
            {
                LastModified = new DateTimeOffset(2014, 1, 2, 3, 4, 5, TimeSpan.Zero)
            });
            options.FileProvider = fileProvider;
            var pathString = new PathString("/test");
            var httpContext = new DefaultHttpContext();
            httpContext.Request.Path = new PathString("/test/foo.txt");
            var context = new StaticFileContext(httpContext, options, pathString, NullLogger.Instance);

            // Act
            context.ValidatePath();
            var result = context.LookupFileInfo();

            // Assert
            Assert.True(result);
        }
Beispiel #22
0
        public void GetOrAdd_ExpiresEntriesAfterOneMinute()
        {
            // Arrange
            var path         = @"Views\Home\_ViewStart.cshtml";
            var fileProvider = new TestFileProvider();

            fileProvider.AddFile(path, "some content");
            var clock  = new Mock <ISystemClock>();
            var utcNow = DateTimeOffset.UtcNow;

            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();

            // Act 1
            var result1 = chunkTreeCache.GetOrAdd(path, fileInfo => chunkTree1);

            // 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."); });

            // Assert 2
            Assert.Same(chunkTree1, result2);

            // Act 3
            utcNow = utcNow.AddSeconds(65);
            var result3 = chunkTreeCache.GetOrAdd(path, fileInfo => chunkTree2);

            // Assert 3
            Assert.Same(chunkTree2, result3);
        }
        public void Compile_ReturnsCompilationFailureWithPathsFromLinePragmas()
        {
            // Arrange
            var viewPath               = "some-relative-path";
            var fileContent            = "test file content";
            var content                = $@"
#line 1 ""{viewPath}""
this should fail";
            var applicationEnvironment = GetApplicationEnvironment();
            var libraryExporter        = GetLibraryExporter();

            var compilerOptionsProvider = new Mock <ICompilerOptionsProvider>();

            compilerOptionsProvider.Setup(p => p.GetCompilerOptions(applicationEnvironment.ApplicationName,
                                                                    applicationEnvironment.RuntimeFramework,
                                                                    applicationEnvironment.Configuration))
            .Returns(new CompilerOptions());
            var mvcRazorHost = Mock.Of <IMvcRazorHost>();
            var fileProvider = new TestFileProvider();
            var fileInfo     = fileProvider.AddFile(viewPath, fileContent);

            var compilationService = new RoslynCompilationService(applicationEnvironment,
                                                                  libraryExporter,
                                                                  compilerOptionsProvider.Object,
                                                                  mvcRazorHost,
                                                                  GetOptions(fileProvider));
            var relativeFileInfo = new RelativeFileInfo(fileInfo, "some-relative-path");

            // Act
            var result = compilationService.Compile(relativeFileInfo, content);

            // Assert
            Assert.IsType <CompilationResult>(result);
            Assert.Null(result.CompiledType);
            var compilationFailure = Assert.Single(result.CompilationFailures);

            Assert.Equal(relativeFileInfo.RelativePath, compilationFailure.SourceFilePath);
            Assert.Equal(fileContent, compilationFailure.SourceFileContent);
        }
Beispiel #24
0
            private IFileProvider GetFileProvider()
            {
                TestFileProvider fileProvider = new TestFileProvider();

                fileProvider.AddDirectory("/");
                fileProvider.AddDirectory("/AlternateIgnorePrefix");
                fileProvider.AddDirectory("/AlternateViewStart");
                fileProvider.AddDirectory("/AlternateViewStartPath");
                fileProvider.AddDirectory("/IgnoreUnderscores");
                fileProvider.AddDirectory("/Layout");
                fileProvider.AddDirectory("/LayoutWithSection");
                fileProvider.AddDirectory("/SimpleTemplate");
                fileProvider.AddDirectory("/ViewStartAndLayout");

                fileProvider.AddFile("/Layout/_Layout.cshtml",
                                     @"LAYOUT
@RenderBody()");
                fileProvider.AddFile("/ViewStartAndLayout/_ViewStart.cshtml",
                                     @"@{
	Layout = ""_Layout.cshtml"";
}");
                fileProvider.AddFile("/ViewStartAndLayout/_Layout.cshtml",
                                     @"LAYOUT2
@RenderBody()");
                fileProvider.AddFile("/AlternateViewStart/_ViewStart.cshtml",
                                     @"@{
	Layout = @""AlternateViewStart\_Layout.cshtml"";
}");
                fileProvider.AddFile("/AlternateViewStart/_Layout.cshtml",
                                     @"LAYOUT3
@RenderBody()");
                fileProvider.AddFile("/IgnoreUnderscores/_Layout.cshtml",
                                     @"LAYOUT4
@RenderBody()");
                fileProvider.AddFile("/LayoutWithSection/_Layout.cshtml",
                                     @"LAYOUT5
@RenderSection(""MySection"", false)
@RenderBody()");

                return(fileProvider);
            }
Beispiel #25
0
            public void ConvertingBadSassFails()
            {
                // Given
                const string     input        = @"
$font-stack:    Helvetica, sans-serif
$primary-color: #333

body {
  font: 100% $font-stack;
  color: $primary-color;
}";
                TestFileProvider fileProvider = new TestFileProvider();

                fileProvider.AddDirectory("/");
                fileProvider.AddDirectory("/input");
                fileProvider.AddDirectory("/input/assets");
                fileProvider.AddFile("/input/assets/test.scss", input);
                TestFileSystem fileSystem = new TestFileSystem
                {
                    FileProvider = fileProvider
                };
                IExecutionContext context = new TestExecutionContext
                {
                    FileSystem = fileSystem
                };
                IDocument document = new TestDocument(input, new MetadataItems
                {
                    { Keys.RelativeFilePath, new FilePath("assets/test.scss") }
                });

                Sass sass = new Sass();

                // When, Then
                Assert.Catch <AggregateException>(() =>
                {
                    sass.Execute(new[] { document }, context).ToList(); // Make sure to materialize the result list
                });
            }
Beispiel #26
0
            public void IncludesFile()
            {
                // Given
                TestFileProvider fileProvider = new TestFileProvider();

                fileProvider.AddDirectory("/");
                fileProvider.AddDirectory("/A");
                fileProvider.AddDirectory("/A/B");
                fileProvider.AddFile("/A/B/c.txt", "foo");
                TestFileSystem fileSystem = new TestFileSystem
                {
                    FileProvider = fileProvider
                };

                fileSystem.InputPaths.Clear();
                fileSystem.InputPaths.Add("/A");

                TestExecutionContext context = new TestExecutionContext
                {
                    FileSystem = fileSystem
                };
                TestDocument document = new TestDocument();

                KeyValuePair <string, string>[] args = new KeyValuePair <string, string>[]
                {
                    new KeyValuePair <string, string>(null, "B/c.txt")
                };
                Include shortcode = new Include();

                // When
                IShortcodeResult result = shortcode.Execute(args, string.Empty, document, context);

                // Then
                using (TextReader reader = new StreamReader(result.Stream))
                {
                    reader.ReadToEnd().ShouldBe("foo");
                }
            }
Beispiel #27
0
            public void RecursiveWildcardTests(string directoryPath, string[] patterns, string[] resultPaths)
            {
                // Given
                TestFileProvider fileProvider = new TestFileProvider();

                fileProvider.AddDirectory("/a");
                fileProvider.AddDirectory("/a/b");
                fileProvider.AddDirectory("/a/b/c");
                fileProvider.AddDirectory("/a/b/c/d");
                fileProvider.AddDirectory("/a/b/c/d/e");
                fileProvider.AddDirectory("/a/b/c/d/e/1");
                fileProvider.AddDirectory("/a/b/c/d/e/1/2");
                fileProvider.AddFile("/a/b/c/d/e/1/2/3.txt");
                IDirectory directory = fileProvider.GetDirectory(directoryPath);

                // When
                IEnumerable <IFile> matches = Globber.GetFiles(directory, patterns);
                IEnumerable <IFile> matchesReversedSlash = Globber.GetFiles(directory, patterns.Select(x => x.Replace("/", "\\")));

                // Then
                CollectionAssert.AreEquivalent(resultPaths, matches.Select(x => x.Path.FullPath));
                CollectionAssert.AreEquivalent(resultPaths, matchesReversedSlash.Select(x => x.Path.FullPath));
            }
        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 type     = typeof(TestView);
            var expected = new CompilationResult(type);

            // Act - 1
            var result1 = cache.GetOrAdd(@"Areas\Finances\Views\Home\Index.cshtml", _ => expected);

            // Assert - 1
            Assert.Same(type, result1.CompilationResult.CompiledType);

            // Act - 2
            var result2 = cache.GetOrAdd(relativePath, ThrowsIfCalled);

            // Assert - 2
            Assert.Same(type, result2.CompilationResult.CompiledType);
        }
Beispiel #29
0
        public void AddFileVersionToPath_UpdatesEntryWhenCacheExpires_ForNonExistingFile()
        {
            // Arrange
            var fileProvider        = new TestFileProvider();
            var fileVersionProvider = new FileVersionProvider(
                fileProvider,
                new MemoryCache(new MemoryCacheOptions()),
                GetRequestPathBase());

            // Act 1 - File does not exist
            var result = fileVersionProvider.AddFileVersionToPath("file.txt");

            // Assert 1
            Assert.Equal("file.txt", result);

            // Act 2 - File gets added
            fileProvider.AddFile("file.txt", "Hello World!");
            fileProvider.GetChangeToken("file.txt").HasChanged = true;
            result = fileVersionProvider.AddFileVersionToPath("file.txt");

            // Assert 2
            Assert.Equal("file.txt?v=f4OxZX_x_FO5LcGBSKHWXfwtSx-j1ncoSt3SABJtkGk", result);
        }
        public void LookupFileInfo_ReturnsTrue_IfFileExists()
        {
            // Arrange
            var options      = new StaticFileOptions();
            var fileProvider = new TestFileProvider();

            fileProvider.AddFile("/foo.txt", new TestFileInfo
            {
                LastModified = new DateTimeOffset(2014, 1, 2, 3, 4, 5, TimeSpan.Zero)
            });
            var pathString  = new PathString("/test");
            var httpContext = new DefaultHttpContext();

            httpContext.Request.Path = new PathString("/test/foo.txt");
            var context = new StaticFileContext(httpContext, options, pathString, NullLogger.Instance, fileProvider, new FileExtensionContentTypeProvider());

            // Act
            context.ValidatePath();
            var result = context.LookupFileInfo();

            // Assert
            Assert.True(result);
        }
        public void AddFileVersionToPath_DoesNotLockFileAfterReading()
        {
            // Arrange
            var stream   = new TestableMemoryStream(Encoding.UTF8.GetBytes("Hello World!"));
            var mockFile = new Mock <IFileInfo>();

            mockFile.SetupGet(f => f.Exists).Returns(true);
            mockFile
            .Setup(m => m.CreateReadStream())
            .Returns(stream);

            var fileProvider = new TestFileProvider();

            fileProvider.AddFile("/hello/world", mockFile.Object);
            var requestPath         = GetRequestPathBase();
            var fileVersionProvider = GetFileVersionProvider(fileProvider);

            // Act
            var result = fileVersionProvider.AddFileVersionToPath(requestPath, "/hello/world");

            // Assert
            Assert.True(stream.Disposed);
        }
        public void AddFileVersionToPath_UpdatesEntryWhenCacheExpires_ForExistingFile_WithRequestPathBase()
        {
            // Arrange
            var fileProvider        = new TestFileProvider();
            var requestPath         = GetRequestPathBase("/wwwroot/");
            var fileVersionProvider = GetFileVersionProvider(fileProvider);

            fileProvider.AddFile("file.txt", "Hello World!");

            // Act 1 - File exists
            var result = fileVersionProvider.AddFileVersionToPath(requestPath, "/wwwroot/file.txt");

            // Assert 1
            Assert.Equal("/wwwroot/file.txt?v=f4OxZX_x_FO5LcGBSKHWXfwtSx-j1ncoSt3SABJtkGk", result);

            // Act 2
            fileProvider.DeleteFile("file.txt");
            fileProvider.GetChangeToken("file.txt").HasChanged = true;
            result = fileVersionProvider.AddFileVersionToPath(requestPath, "/wwwroot/file.txt");

            // Assert 2
            Assert.Equal("/wwwroot/file.txt", result);
        }
Beispiel #33
0
        public async Task CompileAsync_PrecompiledViewWithChecksum_CanReusePrecompiledViewIfContentChangesToMatch()
        {
            // Arrange
            var path = "/Views/Home/Index.cshtml";

            var fileProvider = new TestFileProvider();
            var file         = fileProvider.AddFile(path, "different content");

            var expected1 = new CompiledViewDescriptor();

            var precompiledView = new CompiledViewDescriptor
            {
                RelativePath = path,
                Item         = new TestRazorCompiledItem(typeof(string), "mvc.1.0.view", path, new object[]
                {
                    new RazorSourceChecksumAttribute("SHA1", GetChecksum("some content"), path),
                }),
            };

            var viewCompiler = GetViewCompiler(fileProvider, precompiledViews: new[] { precompiledView });

            viewCompiler.Compile = _ => expected1;

            // Act - 1
            var result = await viewCompiler.CompileAsync(path);

            // Assert - 1
            Assert.Same(expected1, result);

            // Act - 2
            file.Content = "some content";
            fileProvider.GetChangeToken(path).HasChanged = true;
            result = await viewCompiler.CompileAsync(path);

            // Assert - 2
            Assert.Same(precompiledView.Item, result.Item);
        }
Beispiel #34
0
        public async Task CompileAsync_PrecompiledViewWithoutChecksumForMainSource_DoesNotSupportRecompilation()
        {
            // Arrange
            var path = "/Views/Home/Index.cshtml";

            var fileProvider = new TestFileProvider();

            fileProvider.AddFile(path, "some content");

            var precompiledView = new CompiledViewDescriptor
            {
                RelativePath = path,
                Item         = new TestRazorCompiledItem(typeof(string), "mvc.1.0.view", path, new object[]
                {
                    new RazorSourceChecksumAttribute("sha1", GetChecksum("some content"), "/Views/Some-Other-View"),
                }),
            };

            var viewCompiler = GetViewCompiler(fileProvider, precompiledViews: new[] { precompiledView });

            // Act - 1
            var result = await viewCompiler.CompileAsync(path);

            // Assert - 1
            Assert.Same(precompiledView.Item, result.Item);

            // Act - 2
            fileProvider.Watch(path);
            fileProvider.GetChangeToken(path).HasChanged = true;
            result = await viewCompiler.CompileAsync(path);

            // Assert - 2
            Assert.Same(precompiledView.Item, result.Item);

            // This view doesn't have checksums so it can't be recompiled.
            Assert.Null(result.ExpirationTokens);
        }
            public void EmptyResultIfFileDoesNotExist()
            {
                // Given
                TestFileProvider fileProvider = new TestFileProvider();

                fileProvider.AddDirectory("/");
                fileProvider.AddDirectory("/A");
                fileProvider.AddDirectory("/A/B");
                fileProvider.AddFile("/A/B/c.txt", "foo");
                TestFileSystem fileSystem = new TestFileSystem
                {
                    FileProvider = fileProvider
                };

                fileSystem.InputPaths.Clear();
                fileSystem.InputPaths.Add("/A");

                TestExecutionContext context = new TestExecutionContext
                {
                    FileSystem = fileSystem
                };

                context.TestLoggerProvider.ThrowLogLevel = LogLevel.Error;
                TestDocument document = new TestDocument();

                KeyValuePair <string, string>[] args = new KeyValuePair <string, string>[]
                {
                    new KeyValuePair <string, string>(null, "B/d.txt")
                };
                IncludeShortcode shortcode = new IncludeShortcode();

                // When
                IDocument result = shortcode.Execute(args, string.Empty, document, context);

                // Then
                result.ShouldBeOfType <TestDocument>().Content.ShouldBeEmpty();
            }
Beispiel #36
0
        public void GetOrAdd_ExpiresEntriesAfterOneMinute()
        {
            // Arrange
            var path = @"Views\Home\_ViewStart.cshtml";
            var fileProvider = new TestFileProvider();
            fileProvider.AddFile(path, "some content");
            var clock = new Mock<ISystemClock>();
            var utcNow = DateTimeOffset.UtcNow;
            clock.SetupGet(c => c.UtcNow)
                 .Returns(() => utcNow);
            var options = new MemoryCacheOptions { Clock = clock.Object };
            using (var chunkTreeCache = new DefaultChunkTreeCache(fileProvider, options))
            {
                var chunkTree1 = new ChunkTree();
                var chunkTree2 = new ChunkTree();

                // Act 1
                var result1 = chunkTreeCache.GetOrAdd(path, fileInfo => chunkTree1);

                // 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."); });

                // Assert 2
                Assert.Same(chunkTree1, result2);

                // Act 3
                utcNow = utcNow.AddSeconds(65);
                var result3 = chunkTreeCache.GetOrAdd(path, fileInfo => chunkTree2);

                // Assert 3
                Assert.Same(chunkTree2, result3);
            }
        }
Beispiel #37
0
        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 type = typeof(TestView);
            var expected = UncachedCompilationResult.Successful(type, "hello world");

            // Act - 1
            var result1 = cache.GetOrAdd(@"Areas\Finances\Views\Home\Index.cshtml", _ => expected);

            // Assert - 1
            var compilationResult = Assert.IsType<UncachedCompilationResult>(result1.CompilationResult);
            Assert.Same(expected, compilationResult);
            Assert.Same(type, compilationResult.CompiledType);

            // Act - 2
            var result2 = cache.GetOrAdd(relativePath, ThrowsIfCalled);

            // Assert - 2
            Assert.Same(type, result2.CompilationResult.CompiledType);
        }
        public void SkipsHttpsCompression_IfNotMatched()
        {
            var options      = new StaticFileOptions();
            var fileProvider = new TestFileProvider();

            fileProvider.AddFile("/foo.txt", new TestFileInfo
            {
                LastModified = new DateTimeOffset(2014, 1, 2, 3, 4, 5, TimeSpan.Zero)
            });
            var pathString              = new PathString("/test");
            var httpContext             = new DefaultHttpContext();
            var httpsCompressionFeature = new TestHttpsCompressionFeature();

            httpContext.Features.Set <IHttpsCompressionFeature>(httpsCompressionFeature);
            httpContext.Request.Path = new PathString("/test/bar.txt");
            var context = new StaticFileContext(httpContext, options, pathString, NullLogger.Instance, fileProvider, new FileExtensionContentTypeProvider());

            context.ValidatePath();
            var result = context.LookupFileInfo();

            Assert.False(result);

            Assert.Equal(HttpsCompressionMode.Default, httpsCompressionFeature.Mode);
        }
            public async Task IncludesFileRelativeToSource()
            {
                // Given
                TestFileProvider fileProvider = new TestFileProvider();

                fileProvider.AddDirectory("/");
                fileProvider.AddDirectory("/A");
                fileProvider.AddDirectory("/A/B");
                fileProvider.AddDirectory("/A/D");
                fileProvider.AddFile("/A/B/c.txt", "foo");
                TestFileSystem fileSystem = new TestFileSystem
                {
                    FileProvider = fileProvider
                };

                fileSystem.InputPaths.Clear();
                fileSystem.InputPaths.Add("/A");

                TestExecutionContext context = new TestExecutionContext
                {
                    FileSystem = fileSystem
                };
                TestDocument document = new TestDocument(new FilePath("/A/D/x.txt"), (FilePath)null);

                KeyValuePair <string, string>[] args = new KeyValuePair <string, string>[]
                {
                    new KeyValuePair <string, string>(null, "../B/c.txt")
                };
                IncludeShortcode shortcode = new IncludeShortcode();

                // When
                TestDocument result = (TestDocument)await shortcode.ExecuteAsync(args, string.Empty, document, context);

                // Then
                result.Content.ShouldBe("foo");
            }
        public void OnProvidersExecuting_ValidatesChecksum_RejectsPageWhenContentDoesntMatch()
        {
            // Arrange
            var descriptors = new[]
            {
                CreateVersion_2_1_Descriptor("/Pages/About.cshtml", metadata: new object[]
                {
                    new RazorSourceChecksumAttribute("SHA1", GetChecksum("some content"), "/Pages/About.cshtml"),
                }),
            };

            var fileProvider = new TestFileProvider();

            fileProvider.AddFile("/Pages/About.cshtml", "some other content");

            var provider = CreateProvider(descriptors: descriptors, fileProvider: fileProvider);
            var context  = new PageRouteModelProviderContext();

            // Act
            provider.OnProvidersExecuting(context);

            // Assert
            Assert.Empty(context.RouteModels);
        }
Beispiel #41
0
        public void GetOrAdd_UpdatesCache_IfFileExpirationTriggerExpires()
        {
            // Arrange
            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();

            // Act 1
            var result1 = chunkTreeCache.GetOrAdd(path, fileInfo => expected1);

            // Assert 1
            Assert.Same(expected1, result1);

            // Act 2
            fileProvider.GetTrigger(path).IsExpired = true;
            var result2 = chunkTreeCache.GetOrAdd(path, fileInfo => expected2);

            // Assert 2
            Assert.Same(expected2, result2);
        }
Beispiel #42
0
        public async Task CompileAsync_DoesNotInvalidCache_IfChangeTokenChanges()
        {
            // Arrange
            var path         = "/Views/Home/Index.cshtml";
            var fileProvider = new TestFileProvider();
            var fileInfo     = fileProvider.AddFile(path, "some content");
            var viewCompiler = GetViewCompiler(fileProvider);
            var changeToken  = fileProvider.Watch(path);

            // Act 1
            var result1 = await viewCompiler.CompileAsync(path);

            // Assert 1
            Assert.NotNull(result1.ViewAttribute);

            // Act 2
            fileProvider.DeleteFile(path);
            fileProvider.GetChangeToken(path).HasChanged = true;
            viewCompiler.Compile = _ => throw new Exception("Can't call me");
            var result2 = await viewCompiler.CompileAsync(path);

            // Assert 2
            Assert.Same(result1, result2);
        }
            public async Task EmptyResultIfFileDoesNotExist()
            {
                // Given
                TestFileProvider fileProvider = new TestFileProvider();

                fileProvider.AddDirectory("/");
                fileProvider.AddDirectory("/A");
                fileProvider.AddDirectory("/A/B");
                fileProvider.AddFile("/A/B/c.txt", "foo");
                TestFileSystem fileSystem = new TestFileSystem
                {
                    FileProvider = fileProvider
                };

                fileSystem.InputPaths.Clear();
                fileSystem.InputPaths.Add("/A");

                TestExecutionContext context = new TestExecutionContext
                {
                    FileSystem = fileSystem,
                    Logger     = new TestLogger(LogLevel.Error)
                };
                TestDocument document = new TestDocument();

                KeyValuePair <string, string>[] args = new KeyValuePair <string, string>[]
                {
                    new KeyValuePair <string, string>(null, "B/d.txt")
                };
                IncludeShortcode shortcode = new IncludeShortcode();

                // When
                TestDocument result = (TestDocument)await shortcode.ExecuteAsync(args, string.Empty, document, context);

                // Then
                result.Content.ShouldBeEmpty();
            }
Beispiel #44
0
        public void GetOrAdd_ReturnsRuntimeCompiledAndPrecompiledViews()
        {
            // Arrange
            var fileProvider = new TestFileProvider();
            fileProvider.AddFile(ViewPath, "some content");
            var cache = new CompilerCache(fileProvider, _precompiledViews);
            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);
        }
        public void GetInheritedChunks_ReadsChunksFromGlobalFilesInPath()
        {
            // Arrange
            var fileProvider = new TestFileProvider();
            fileProvider.AddFile(@"/Views/accounts/_ViewImports.cshtml", "@using AccountModels");
            fileProvider.AddFile(@"/Views/Shared/_ViewImports.cshtml", "@inject SharedHelper Shared");
            fileProvider.AddFile(@"/Views/home/_ViewImports.cshtml", "@using MyNamespace");
            fileProvider.AddFile(@"/Views/_ViewImports.cshtml",
@"@inject MyHelper<TModel> Helper
@inherits MyBaseType

@{
    Layout = ""test.cshtml"";
}

");
            var defaultChunks = new Chunk[]
            {
                new InjectChunk("MyTestHtmlHelper", "Html"),
                new UsingChunk { Namespace = "AppNamespace.Model" },
            };
            var cache = new DefaultChunkTreeCache(fileProvider);
            using (var host = new MvcRazorHost(cache, new TagHelperDescriptorResolver(designTime: false)))
            {
                var utility = new ChunkInheritanceUtility(host, cache, defaultChunks);

                // 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<LiteralChunk>(chunk);
                                Assert.Equal(viewImportsPath, chunk.Start.FilePath);
                            },
                            chunk =>
                            {
                                var injectChunk = Assert.IsType<InjectChunk>(chunk);
                                Assert.Equal("MyHelper<TModel>", injectChunk.TypeName);
                                Assert.Equal("Helper", injectChunk.MemberName);
                                Assert.Equal(viewImportsPath, chunk.Start.FilePath);
                            },
                            chunk =>
                            {
                                Assert.IsType<LiteralChunk>(chunk);
                                Assert.Equal(viewImportsPath, chunk.Start.FilePath);
                            },
                            chunk =>
                            {
                                var setBaseTypeChunk = Assert.IsType<SetBaseTypeChunk>(chunk);
                                Assert.Equal("MyBaseType", setBaseTypeChunk.TypeName);
                                Assert.Equal(viewImportsPath, chunk.Start.FilePath);
                            },
                            chunk =>
                            {
                                Assert.IsType<LiteralChunk>(chunk);
                                Assert.Equal(viewImportsPath, chunk.Start.FilePath);
                            },
                            chunk =>
                            {
                                Assert.IsType<StatementChunk>(chunk);
                                Assert.Equal(viewImportsPath, chunk.Start.FilePath);
                            },
                            chunk =>
                            {
                                Assert.IsType<LiteralChunk>(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<LiteralChunk>(chunk);
                                Assert.Equal(viewImportsPath, chunk.Start.FilePath);
                            },
                            chunk =>
                            {
                                var usingChunk = Assert.IsType<UsingChunk>(chunk);
                                Assert.Equal("MyNamespace", usingChunk.Namespace);
                                Assert.Equal(viewImportsPath, chunk.Start.FilePath);
                            },
                            chunk =>
                            {
                                Assert.IsType<LiteralChunk>(chunk);
                                Assert.Equal(viewImportsPath, chunk.Start.FilePath);
                            });
                        Assert.Equal(viewImportsPath, chunkTreeResult.FilePath);
                    });
            }
        }
        public void MergeInheritedChunks_MergesDefaultInheritedChunks()
        {
            // Arrange
            var fileProvider = new TestFileProvider();
            fileProvider.AddFile(@"/Views/_ViewImports.cshtml",
                               "@inject DifferentHelper<TModel> Html");
            var cache = new DefaultChunkTreeCache(fileProvider);
            using (var host = new MvcRazorHost(cache, new TagHelperDescriptorResolver(designTime: false)))
            {
                var defaultChunks = new Chunk[]
                {
                new InjectChunk("MyTestHtmlHelper", "Html"),
                new UsingChunk { Namespace = "AppNamespace.Model" },
                };
                var inheritedChunkTrees = new ChunkTree[]
                {
                new ChunkTree
                {
                    Children = new Chunk[]
                    {
                        new UsingChunk { Namespace = "InheritedNamespace" },
                        new LiteralChunk { Text = "some text" }
                    }
                },
                new ChunkTree
                {
                    Children = new Chunk[]
                    {
                        new UsingChunk { Namespace = "AppNamespace.Model" },
                    }
                }
                };

                var utility = new ChunkInheritanceUtility(host, cache, defaultChunks);
                var chunkTree = new ChunkTree();

                // 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));
            }
        }
        public void Compile_DoesNotThrow_IfFileCannotBeRead()
        {
            // Arrange
            var path = "some-relative-path";
            var content = $@"
#line 1 ""{path}""
this should fail";
            var applicationEnvironment = GetApplicationEnvironment();
            var accessor = GetLoadContextAccessor();
            var libraryExporter = GetLibraryExporter();

            var compilerOptionsProvider = new Mock<ICompilerOptionsProvider>();
            compilerOptionsProvider.Setup(p => p.GetCompilerOptions(applicationEnvironment.ApplicationName,
                                                                    applicationEnvironment.RuntimeFramework,
                                                                    applicationEnvironment.Configuration))
                                   .Returns(new CompilerOptions());
            var mvcRazorHost = Mock.Of<IMvcRazorHost>();

            var mockFileInfo = new Mock<IFileInfo>();
            mockFileInfo.Setup(f => f.CreateReadStream())
                        .Throws(new Exception());
            var fileProvider = new TestFileProvider();
            fileProvider.AddFile(path, mockFileInfo.Object);

            var compilationService = new RoslynCompilationService(applicationEnvironment,
                                                                  accessor,
                                                                  libraryExporter,
                                                                  compilerOptionsProvider.Object,
                                                                  mvcRazorHost,
                                                                  GetOptions(fileProvider));
            
            var relativeFileInfo = new RelativeFileInfo(mockFileInfo.Object, path);

            // Act
            var result = compilationService.Compile(relativeFileInfo, content);

            // Assert
            Assert.IsType<CompilationResult>(result);
            Assert.Null(result.CompiledType);
            var compilationFailure = Assert.Single(result.CompilationFailures);
            Assert.Equal(path, compilationFailure.SourceFilePath);
            Assert.Null(compilationFailure.SourceFileContent);
        }
Beispiel #48
0
        public void GetOrAdd_ReturnsFailedCompilationResult_IfFileWasRemovedFromFileSystem()
        {
            // Arrange
            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(ViewPath, _ => expected);

            // Assert 1
            Assert.True(result1.Success);
            Assert.IsType<TestView>(result1.PageFactory());

            // Act 2
            // Delete the file from the file system and set it's expiration token.
            fileProvider.DeleteFile(ViewPath);
            fileProvider.GetChangeToken(ViewPath).HasChanged = true;
            var result2 = cache.GetOrAdd(ViewPath, ThrowsIfCalled);

            // Assert 2
            Assert.False(result2.Success);
        }
        public void GetInheritedChunks_ReturnsEmptySequenceIfNoGlobalsArePresent()
        {
            // Arrange
            var fileProvider = new TestFileProvider();
            fileProvider.AddFile(@"/_ViewImports.cs", string.Empty);
            fileProvider.AddFile(@"/Views/_Layout.cshtml", string.Empty);
            fileProvider.AddFile(@"/Views/home/_not-viewimports.cshtml", string.Empty);
            var cache = new DefaultChunkTreeCache(fileProvider);
            using (var host = new MvcRazorHost(cache, new TagHelperDescriptorResolver(designTime: false)))
            {
                var defaultChunks = new Chunk[]
                {
                new InjectChunk("MyTestHtmlHelper", "Html"),
                new UsingChunk { Namespace = "AppNamespace.Model" },
                };
                var utility = new ChunkInheritanceUtility(host, cache, defaultChunks);

                // Act
                var chunkTrees = utility.GetInheritedChunkTreeResults(PlatformNormalizer.NormalizePath(@"Views\home\Index.cshtml"));

                // Assert
                Assert.Empty(chunkTrees);
            }
        }
        public void Compile_DoesNotThrow_IfFileCannotBeRead()
        {
            // Arrange
            var path = "some-relative-path";
            var content = $@"
#line 1 ""{path}""
this should fail";

            var mockFileInfo = new Mock<IFileInfo>();
            mockFileInfo.Setup(f => f.CreateReadStream())
                .Throws(new Exception());
            var fileProvider = new TestFileProvider();
            fileProvider.AddFile(path, mockFileInfo.Object);

            var compilationService = new DefaultRoslynCompilationService(
                GetDependencyContext(),
                GetOptions(),
                GetFileProviderAccessor(),
                NullLoggerFactory.Instance);
            var relativeFileInfo = new RelativeFileInfo(mockFileInfo.Object, path);

            // Act
            var result = compilationService.Compile(relativeFileInfo, content);

            // Assert
            Assert.IsType<CompilationResult>(result);
            Assert.Null(result.CompiledType);
            var compilationFailure = Assert.Single(result.CompilationFailures);
            Assert.Equal(path, compilationFailure.SourceFilePath);
            Assert.Null(compilationFailure.SourceFileContent);
        }
        public void GetCompilationFailedResult_ReturnsCompilationResult_WithGroupedMessages()
        {
            // Arrange
            var viewPath = "Views/Home/Index";
            var generatedCodeFileName = "Generated Code";
            var fileProvider = new TestFileProvider();
            fileProvider.AddFile(viewPath, "view-content");
            var options = new RazorViewEngineOptions();
            options.FileProviders.Add(fileProvider);

            var compilationService = new DefaultRoslynCompilationService(
                 GetDependencyContext(),
                 options,
                 GetFileProviderAccessor(fileProvider),
                 NullLoggerFactory.Instance);

            var assemblyName = "random-assembly-name";

            var diagnostics = new[]
            {
                Diagnostic.Create(
                    GetDiagnosticDescriptor("message-1"),
                    Location.Create(
                        viewPath,
                        new TextSpan(10, 5),
                        new LinePositionSpan(new LinePosition(10, 1), new LinePosition(10, 2)))),
                Diagnostic.Create(
                    GetDiagnosticDescriptor("message-2"),
                    Location.Create(
                        assemblyName,
                        new TextSpan(1, 6),
                        new LinePositionSpan(new LinePosition(1, 2), new LinePosition(3, 4)))),
                Diagnostic.Create(
                    GetDiagnosticDescriptor("message-3"),
                    Location.Create(
                        viewPath,
                        new TextSpan(40, 50),
                        new LinePositionSpan(new LinePosition(30, 5), new LinePosition(40, 12)))),
            };

            // Act
            var compilationResult = compilationService.GetCompilationFailedResult(
                viewPath,
                "compilation-content",
                assemblyName,
                diagnostics);

            // Assert
            Assert.Collection(compilationResult.CompilationFailures,
                failure =>
                {
                    Assert.Equal(viewPath, failure.SourceFilePath);
                    Assert.Equal("view-content", failure.SourceFileContent);
                    Assert.Collection(failure.Messages,
                        message =>
                        {
                            Assert.Equal("message-1", message.Message);
                            Assert.Equal(viewPath, message.SourceFilePath);
                            Assert.Equal(11, message.StartLine);
                            Assert.Equal(2, message.StartColumn);
                            Assert.Equal(11, message.EndLine);
                            Assert.Equal(3, message.EndColumn);
                        },
                        message =>
                        {
                            Assert.Equal("message-3", message.Message);
                            Assert.Equal(viewPath, message.SourceFilePath);
                            Assert.Equal(31, message.StartLine);
                            Assert.Equal(6, message.StartColumn);
                            Assert.Equal(41, message.EndLine);
                            Assert.Equal(13, message.EndColumn);
                        });
                },
                failure =>
                {
                    Assert.Equal(generatedCodeFileName, failure.SourceFilePath);
                    Assert.Equal("compilation-content", failure.SourceFileContent);
                    Assert.Collection(failure.Messages,
                        message =>
                        {
                            Assert.Equal("message-2", message.Message);
                            Assert.Equal(assemblyName, message.SourceFilePath);
                            Assert.Equal(2, message.StartLine);
                            Assert.Equal(3, message.StartColumn);
                            Assert.Equal(4, message.EndLine);
                            Assert.Equal(5, message.EndColumn);
                        });
                });
        }
Beispiel #52
0
        public void GetOrAdd_ReturnsNewResult_IfAncestorViewImportsWereModified(string globalImportPath)
        {
            // Arrange
            var fileProvider = new TestFileProvider();
            fileProvider.AddFile(ViewPath, "some content");
            var cache = new CompilerCache(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.GetChangeToken(globalImportPath).HasChanged = true;
            var result3 = cache.GetOrAdd(ViewPath, _ => expected2);

            // Assert 2
            Assert.NotSame(CompilerCacheResult.FileNotFound, result3);
            Assert.Same(expected2, result3.CompilationResult);
        }
Beispiel #53
0
        public void GetOrAdd_ReturnsSuccessfulCompilationResultIfTriggerExpires()
        {
            // Arrange
            var fileProvider = new TestFileProvider();
            fileProvider.AddFile(ViewPath, "some content");
            var cache = new CompilerCache(fileProvider);

            // Act and Assert - 1
            Assert.Throws<InvalidTimeZoneException>(() =>
                cache.GetOrAdd(ViewPath, _ => { throw new InvalidTimeZoneException(); }));

            // Act - 2
            fileProvider.GetChangeToken(ViewPath).HasChanged = true;
            var result = cache.GetOrAdd(ViewPath, _ => new CompilationResult(typeof(TestView)));

            // Assert - 2
            Assert.IsType<TestView>(result.PageFactory());
        }
        public void GetCompilationFailedResult_ReturnsCompilationResult_WithGroupedMessages()
        {
            // Arrange
            var viewPath = @"views/index.razor";
            var viewImportsPath = @"views/global.import.cshtml";
            var host = Mock.Of<IMvcRazorHost>();

            var fileProvider = new TestFileProvider();
            var file = fileProvider.AddFile(viewPath, "View Content");
            fileProvider.AddFile(viewImportsPath, "Global Import Content");
            var relativeFileInfo = new RelativeFileInfo(file, viewPath);
            var razorService = new RazorCompilationService(
                Mock.Of<ICompilationService>(),
                Mock.Of<IMvcRazorHost>(),
                GetOptions(fileProvider));
            var errors = new[]
            {
                new RazorError("message-1", new SourceLocation(1, 2, 17)),
                new RazorError("message-2", new SourceLocation(viewPath, 1, 4, 6), 7),
                new RazorError { Message = "message-3" },
                new RazorError("message-4", new SourceLocation(viewImportsPath, 1, 3, 8), 4),
            };

            // Act
            var result = razorService.GetCompilationFailedResult(relativeFileInfo, errors);

            // Assert
            Assert.NotNull(result.CompilationFailures);
            Assert.Collection(result.CompilationFailures,
                failure =>
                {
                    Assert.Equal(viewPath, failure.SourceFilePath);
                    Assert.Equal("View Content", failure.SourceFileContent);
                    Assert.Collection(failure.Messages,
                        message =>
                        {
                            Assert.Equal(errors[0].Message, message.Message);
                            Assert.Equal(viewPath, message.SourceFilePath);
                            Assert.Equal(3, message.StartLine);
                            Assert.Equal(17, message.StartColumn);
                            Assert.Equal(3, message.EndLine);
                            Assert.Equal(18, message.EndColumn);
                        },
                        message =>
                        {
                            Assert.Equal(errors[1].Message, message.Message);
                            Assert.Equal(viewPath, message.SourceFilePath);
                            Assert.Equal(5, message.StartLine);
                            Assert.Equal(6, message.StartColumn);
                            Assert.Equal(5, message.EndLine);
                            Assert.Equal(13, message.EndColumn);
                        },
                        message =>
                        {
                            Assert.Equal(errors[2].Message, message.Message);
                            Assert.Equal(viewPath, message.SourceFilePath);
                            Assert.Equal(0, message.StartLine);
                            Assert.Equal(-1, message.StartColumn);
                            Assert.Equal(0, message.EndLine);
                            Assert.Equal(0, message.EndColumn);
                        });
                },
                failure =>
                {
                    Assert.Equal(viewImportsPath, failure.SourceFilePath);
                    Assert.Equal("Global Import Content", failure.SourceFileContent);
                    Assert.Collection(failure.Messages,
                        message =>
                        {
                            Assert.Equal(errors[3].Message, message.Message);
                            Assert.Equal(viewImportsPath, message.SourceFilePath);
                            Assert.Equal(4, message.StartLine);
                            Assert.Equal(8, message.StartColumn);
                            Assert.Equal(4, message.EndLine);
                            Assert.Equal(12, message.EndColumn);
                        });
                });
        }
        public void GetOrAdd_UpdatesCacheWithValue_IfFileWasAdded()
        {
            // Arrange
            var path = @"Views\Home\_ViewStart.cshtml";
            var fileProvider = new TestFileProvider();
            var codeTreeCache = new DefaultCodeTreeCache(fileProvider);
            var expected = new CodeTree();

            // Act 1
            var result1 = codeTreeCache.GetOrAdd(path, fileInfo => { throw new Exception("Shouldn't be called."); });

            // Assert 1
            Assert.Null(result1);

            // Act 2
            fileProvider.AddFile(path, "test content");
            fileProvider.GetTrigger(path).IsExpired = true;
            var result2 = codeTreeCache.GetOrAdd(path, fileInfo => expected);

            // Assert 2
            Assert.Same(expected, result2);
        }
        public void MergeInheritedChunks_MergesDefaultInheritedChunks()
        {
            // Arrange
            var fileProvider = new TestFileProvider();
            fileProvider.AddFile(@"Views\_ViewImports.cshtml",
                               "@inject DifferentHelper<TModel> Html");
            var cache = new DefaultChunkTreeCache(fileProvider);
            var host = new MvcRazorHost(cache);
            var defaultChunks = new Chunk[]
            {
                new InjectChunk("MyTestHtmlHelper", "Html"),
                new UsingChunk { Namespace = "AppNamespace.Model" },
            };
            var inheritedChunkTrees = new ChunkTree[]
            {
                new ChunkTree
                {
                    Chunks = new Chunk[]
                    {
                        new UsingChunk { Namespace = "InheritedNamespace" },
                        new LiteralChunk { Text = "some text" }
                    }
                },
                new ChunkTree
                {
                    Chunks = new Chunk[]
                    {
                        new UsingChunk { Namespace = "AppNamespace.Model" },
                    }
                }
            };

            var utility = new ChunkInheritanceUtility(host, cache, defaultChunks);
            var chunkTree = new ChunkTree();

            // Act
            utility.MergeInheritedChunkTrees(chunkTree,
                                            inheritedChunkTrees,
                                            "dynamic");

            // Assert
            Assert.Equal(3, chunkTree.Chunks.Count);
            Assert.Same(inheritedChunkTrees[0].Chunks[0], chunkTree.Chunks[0]);
            Assert.Same(inheritedChunkTrees[1].Chunks[0], chunkTree.Chunks[1]);
            Assert.Same(defaultChunks[0], chunkTree.Chunks[2]);
        }
        public void GetOrAdd_UpdatesCacheWithNullValue_IfFileWasDeleted()
        {
            // Arrange
            var path = @"Views\Home\_ViewStart.cshtml";
            var fileProvider = new TestFileProvider();
            fileProvider.AddFile(path, "test content");
            using (var chunkTreeCache = new DefaultChunkTreeCache(fileProvider))
            {
                var expected1 = new ChunkTree();

                // Act 1
                var result1 = chunkTreeCache.GetOrAdd(path, fileInfo => expected1);

                // 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."); });

                // Assert 2
                Assert.Null(result2);
            }
        }
Beispiel #58
0
        public void GetOrAdd_ReturnsFileNotFoundIfFileWasDeleted()
        {
            // Arrange
            var fileProvider = new TestFileProvider();
            fileProvider.AddFile(ViewPath, "some content");
            var cache = new CompilerCache(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 token.
            fileProvider.DeleteFile(ViewPath);
            fileProvider.GetChangeToken(ViewPath).HasChanged = true;
            var result2 = cache.GetOrAdd(ViewPath, ThrowsIfCalled);

            // Assert 2
            Assert.Same(CompilerCacheResult.FileNotFound, result2);
            Assert.Null(result2.CompilationResult);
        }
        public void GetCompilationFailedResult_ReturnsCompilationResult_WithGroupedMessages()
        {
            // Arrange
            var viewPath = "Views/Home/Index";
            var generatedCodeFileName = "Generated Code";
            var fileProvider = new TestFileProvider();
            fileProvider.AddFile(viewPath, "view-content");
            var options = new Mock<IOptions<RazorViewEngineOptions>>();
            options.SetupGet(o => o.Options)
                .Returns(new RazorViewEngineOptions
                {
                    FileProvider = fileProvider
                });
            var compilationService = new RoslynCompilationService(
                GetApplicationEnvironment(),
                GetLoadContextAccessor(),
                GetLibraryExporter(),
                Mock.Of<ICompilerOptionsProvider>(),
                Mock.Of<IMvcRazorHost>(),
                options.Object);

            var assemblyName = "random-assembly-name";

            var diagnostics = new[]
            {
                Diagnostic.Create(
                    GetDiagnosticDescriptor("message-1"),
                    Location.Create(
                        viewPath,
                        new TextSpan(10, 5),
                        new LinePositionSpan(new LinePosition(10, 1), new LinePosition(10, 2)))),
                Diagnostic.Create(
                    GetDiagnosticDescriptor("message-2"),
                    Location.Create(
                        assemblyName,
                        new TextSpan(1, 6),
                        new LinePositionSpan(new LinePosition(1, 2), new LinePosition(3, 4)))),
                Diagnostic.Create(
                    GetDiagnosticDescriptor("message-3"),
                    Location.Create(
                        viewPath,
                        new TextSpan(40, 50),
                        new LinePositionSpan(new LinePosition(30, 5), new LinePosition(40, 12)))),
            };

            // Act
            var compilationResult = compilationService.GetCompilationFailedResult(
                viewPath,
                "compilation-content",
                assemblyName,
                diagnostics);

            // Assert
            Assert.Collection(compilationResult.CompilationFailures,
                failure =>
                {
                    Assert.Equal(viewPath, failure.SourceFilePath);
                    Assert.Equal("view-content", failure.SourceFileContent);
                    Assert.Collection(failure.Messages,
                        message =>
                        {
                            Assert.Equal("message-1", message.Message);
                            Assert.Equal(viewPath, message.SourceFilePath);
                            Assert.Equal(11, message.StartLine);
                            Assert.Equal(2, message.StartColumn);
                            Assert.Equal(11, message.EndLine);
                            Assert.Equal(3, message.EndColumn);
                        },
                        message =>
                        {
                            Assert.Equal("message-3", message.Message);
                            Assert.Equal(viewPath, message.SourceFilePath);
                            Assert.Equal(31, message.StartLine);
                            Assert.Equal(6, message.StartColumn);
                            Assert.Equal(41, message.EndLine);
                            Assert.Equal(13, message.EndColumn);
                        });
                },
                failure =>
                {
                    Assert.Equal(generatedCodeFileName, failure.SourceFilePath);
                    Assert.Equal("compilation-content", failure.SourceFileContent);
                    Assert.Collection(failure.Messages,
                        message =>
                        {
                            Assert.Equal("message-2", message.Message);
                            Assert.Equal(assemblyName, message.SourceFilePath);
                            Assert.Equal(2, message.StartLine);
                            Assert.Equal(3, message.StartColumn);
                            Assert.Equal(4, message.EndLine);
                            Assert.Equal(5, message.EndColumn);
                        });
                });
        }
Beispiel #60
0
        public void GetOrAdd_CachesExceptionsInCompilationResult()
        {
            // Arrange
            var fileProvider = new TestFileProvider();
            fileProvider.AddFile(ViewPath, "some content");
            var cache = new CompilerCache(fileProvider);
            var diagnosticMessages = new[]
            {
                new AspNetCore.Diagnostics.DiagnosticMessage("message", "message", ViewPath, 1, 1, 1, 1)
            };
            var compilationResult = new CompilationResult(new[]
            {
                new CompilationFailure(ViewPath, "some content", "compiled content", diagnosticMessages)
            });

            // Act and Assert - 1
            var ex = Assert.Throws<CompilationFailedException>(() => cache.GetOrAdd(ViewPath, _ => compilationResult));
            Assert.Same(compilationResult.CompilationFailures, ex.CompilationFailures);

            // Act and Assert - 2
            ex = Assert.Throws<CompilationFailedException>(() => cache.GetOrAdd(ViewPath, ThrowsIfCalled));
            Assert.Same(compilationResult.CompilationFailures, ex.CompilationFailures);
        }