// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Collections.Generic; using Microsoft.AspNet.Mvc.Rendering; using Microsoft.AspNet.PipelineCore; using Microsoft.AspNet.Routing; using Moq; using Xunit; namespace Microsoft.AspNet.Mvc.Razor.Test { public class RazorViewEngineTest { private static readonly Dictionary _areaTestContext = new Dictionary() { {"area", "foo"}, {"controller", "bar"}, }; private static readonly Dictionary _controllerTestContext = new Dictionary() { {"controller", "bar"}, }; public static IEnumerable InvalidViewNameValues { get { yield return new[] { "~/foo/bar" }; yield return new[] { "/foo/bar" }; yield return new[] { "~/foo/bar.txt" }; yield return new[] { "/foo/bar.txt" }; } } [Theory] [MemberData(nameof(InvalidViewNameValues))] public void FindView_WithFullPathReturnsNotFound_WhenPathDoesNotMatchExtension(string viewName) { // Arrange var viewEngine = CreateSearchLocationViewEngineTester(); var context = GetActionContext(_controllerTestContext); // Act var result = viewEngine.FindView(context, viewName); // Assert Assert.False(result.Success); } [Theory] [MemberData(nameof(InvalidViewNameValues))] public void FindViewFullPathSucceedsWithCshtmlEnding(string viewName) { // Arrange var viewEngine = CreateSearchLocationViewEngineTester(); // Append .cshtml so the viewname is no longer invalid viewName += ".cshtml"; var context = GetActionContext(_controllerTestContext); // Act & Assert // If this throws then our test case fails var result = viewEngine.FindPartialView(context, viewName); Assert.False(result.Success); } [Theory] [MemberData(nameof(InvalidViewNameValues))] public void FindPartialView_WithFullPathReturnsNotFound_WhenPathDoesNotMatchExtension(string partialViewName) { // Arrange var viewEngine = CreateSearchLocationViewEngineTester(); var context = GetActionContext(_controllerTestContext); // Act var result = viewEngine.FindPartialView(context, partialViewName); // Assert Assert.False(result.Success); } [Theory] [MemberData(nameof(InvalidViewNameValues))] public void FindPartialViewFullPathSucceedsWithCshtmlEnding(string partialViewName) { // Arrange var viewEngine = CreateSearchLocationViewEngineTester(); // Append .cshtml so the viewname is no longer invalid partialViewName += ".cshtml"; var context = GetActionContext(_controllerTestContext); // Act & Assert // If this throws then our test case fails var result = viewEngine.FindPartialView(context, partialViewName); Assert.False(result.Success); } [Fact] public void FindPartialViewFailureSearchesCorrectLocationsWithAreas() { // Arrange var searchedLocations = new List(); var viewEngine = CreateSearchLocationViewEngineTester(); var context = GetActionContext(_areaTestContext); // Act var result = viewEngine.FindPartialView(context, "partial"); // Assert Assert.False(result.Success); Assert.Equal(new[] { "/Areas/foo/Views/bar/partial.cshtml", "/Areas/foo/Views/Shared/partial.cshtml", "/Views/Shared/partial.cshtml", }, result.SearchedLocations); } [Fact] public void FindPartialViewFailureSearchesCorrectLocationsWithoutAreas() { // Arrange var viewEngine = CreateSearchLocationViewEngineTester(); var context = GetActionContext(_controllerTestContext); // Act var result = viewEngine.FindPartialView(context, "partialNoArea"); // Assert Assert.False(result.Success); Assert.Equal(new[] { "/Views/bar/partialNoArea.cshtml", "/Views/Shared/partialNoArea.cshtml", }, result.SearchedLocations); } [Fact] public void FindViewFailureSearchesCorrectLocationsWithAreas() { // Arrange var viewEngine = CreateSearchLocationViewEngineTester(); var context = GetActionContext(_areaTestContext); // Act var result = viewEngine.FindView(context, "full"); // Assert Assert.False(result.Success); Assert.Equal(new[] { "/Areas/foo/Views/bar/full.cshtml", "/Areas/foo/Views/Shared/full.cshtml", "/Views/Shared/full.cshtml", }, result.SearchedLocations); } [Fact] public void FindViewFailureSearchesCorrectLocationsWithoutAreas() { // Arrange var viewEngine = CreateSearchLocationViewEngineTester(); var context = GetActionContext(_controllerTestContext); // Act var result = viewEngine.FindView(context, "fullNoArea"); // Assert Assert.False(result.Success); Assert.Equal(new[] { "/Views/bar/fullNoArea.cshtml", "/Views/Shared/fullNoArea.cshtml", }, result.SearchedLocations); } [Fact] public void FindView_ReturnsRazorView_IfLookupWasSuccessful() { // Arrange var pageFactory = new Mock(); var page = Mock.Of(); pageFactory.Setup(p => p.CreateInstance(It.IsAny())) .Returns(Mock.Of()); var viewEngine = new RazorViewEngine(pageFactory.Object); var context = GetActionContext(_controllerTestContext); // Act var result = viewEngine.FindView(context, "test-view"); // Assert Assert.True(result.Success); Assert.IsAssignableFrom(result.View); Assert.Equal("/Views/bar/test-view.cshtml", result.ViewName); } private IViewEngine CreateSearchLocationViewEngineTester() { var pageFactory = new Mock(); pageFactory.Setup(vpf => vpf.CreateInstance(It.IsAny())) .Returns(null); var viewEngine = new RazorViewEngine(pageFactory.Object); return viewEngine; } private static ActionContext GetActionContext(IDictionary routeValues, IRazorView razorView = null) { var httpContext = new DefaultHttpContext(); var serviceProvider = new Mock(); serviceProvider.Setup(p => p.GetService(typeof(IRazorView))) .Returns(razorView ?? Mock.Of()); httpContext.RequestServices = serviceProvider.Object; var routeData = new RouteData { Values = routeValues }; return new ActionContext(httpContext, routeData, new ActionDescriptor()); } } }