public async Task CompileAsync_DoesNotCreateMultipleCompilationResults_ForConcurrentInvocations()
        {
            // Arrange
            var path         = "/Views/Home/Index.cshtml";
            var waitDuration = TimeSpan.FromSeconds(20);
            var fileProvider = new TestFileProvider();

            fileProvider.AddFile(path, "some content");
            var resetEvent1 = new ManualResetEvent(initialState: false);
            var resetEvent2 = new ManualResetEvent(initialState: false);
            var compiler    = GetViewCompiler(fileProvider);

            compiler.Compile = _ => {
                // Event 2
                resetEvent1.WaitOne(waitDuration);

                // Event 3
                resetEvent2.Set();
                return(new CompiledViewDescriptor());
            };

            // Act
            var task1 = Task.Run(() => compiler.CompileAsync(path));
            var task2 = Task.Run(() => {
                // Event 4
                Assert.True(resetEvent2.WaitOne(waitDuration));
                return(compiler.CompileAsync(path));
            });

            // Event 1
            resetEvent1.Set();
            await Task.WhenAll(task1, task2);

            // Assert
            var result1 = task1.Result;
            var result2 = task2.Result;

            Assert.Same(result1, result2);
        }
        public async Task CompileAsync_PrecompiledViewWithChecksum_CanRecompileWhenViewImportChanges()
        {
            // Arrange
            var path       = "/Views/Home/Index.cshtml";
            var importPath = "/Views/_ViewImports.cshtml";

            var fileProvider = new TestFileProvider();

            fileProvider.AddFile(path, "some content");
            var importFile = fileProvider.AddFile(importPath, "some import");

            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),
                    new RazorSourceChecksumAttribute("SHA1", GetChecksum("some import"), importPath),
                }),
            };

            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
            importFile.Content = "different content";
            fileProvider.GetChangeToken(importPath).HasChanged = true;
            viewCompiler.Compile = _ => expected2;
            result = await viewCompiler.CompileAsync(path);

            // Assert - 2
            Assert.Same(expected2, result);
        }
        public async Task CompileAsync_PerformsCaseInsensitiveLookupsForPrecompiledViews_WithNonNormalizedPaths()
        {
            // 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
            var result = await viewCompiler.CompileAsync("Views\\Home\\Index.cshtml");

            // Assert
            Assert.Same(precompiledView, result);
        }
        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/Home/Index.cshtml"),
                }),
                ExpirationTokens = new[] { fileProvider.Watch("/Views/Home/Index.cshtml") }
            };

            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.
            // NB: This is from the original tests and is no longer true
            // Assert.Null(result.ExpirationTokens);
        }
        public async Task GetOrAdd_AllowsConcurrentCompilationOfMultipleRazorPages()
        {
            // Arrange
            var path1        = "/Views/Home/Index.cshtml";
            var path2        = "/Views/Home/About.cshtml";
            var waitDuration = TimeSpan.FromSeconds(20);

            var fileProvider = new TestFileProvider();

            fileProvider.AddFile(path1, "some content");
            fileProvider.AddFile(path2, "some content");

            var resetEvent1 = new AutoResetEvent(initialState: false);
            var resetEvent2 = new ManualResetEvent(initialState: false);

            var compilingOne = false;
            var compilingTwo = false;

            var result1 = new CompiledViewDescriptor();
            var result2 = new CompiledViewDescriptor();

            var compiler = GetViewCompiler(fileProvider);

            compiler.Compile = path => {
                if (path == path1)
                {
                    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(result1);
                }
                else if (path == path2)
                {
                    compilingTwo = true;

                    // Event 4
                    Assert.True(resetEvent2.WaitOne(waitDuration));

                    // Event 5
                    Assert.True(resetEvent1.Set());

                    Assert.True(compilingOne);

                    return(result2);
                }
                else
                {
                    throw new Exception();
                }
            };

            // Act
            var task1 = Task.Run(() => compiler.CompileAsync(path1));
            var task2 = Task.Run(() => compiler.CompileAsync(path2));

            // Event 1
            resetEvent1.Set();

            await Task.WhenAll(task1, task2);

            // Assert
            Assert.True(compilingOne);
            Assert.True(compilingTwo);
            Assert.Same(result1, task1.Result);
            Assert.Same(result2, task2.Result);
        }