1 // Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information. 2 3 using System.IO; 4 using System.Web.Mvc.Properties; 5 using System.Web.Routing; 6 using Moq; 7 using Xunit; 8 using Assert = Microsoft.TestCommon.AssertEx; 9 10 namespace System.Web.Mvc.Html.Test 11 { 12 public class ChildActionExtensionsTest 13 { 14 Mock<HtmlHelper> htmlHelper; 15 Mock<HttpContextBase> httpContext; 16 Mock<RouteBase> route; 17 Mock<IViewDataContainer> viewDataContainer; 18 19 RouteData originalRouteData; 20 RouteCollection routes; 21 ViewContext viewContext; 22 VirtualPathData virtualPathData; 23 ChildActionExtensionsTest()24 public ChildActionExtensionsTest() 25 { 26 route = new Mock<RouteBase>(); 27 route.Setup(r => r.GetVirtualPath(It.IsAny<RequestContext>(), It.IsAny<RouteValueDictionary>())) 28 .Returns(() => virtualPathData); 29 30 virtualPathData = new VirtualPathData(route.Object, "~/VirtualPath"); 31 32 routes = new RouteCollection(); 33 routes.Add(route.Object); 34 35 originalRouteData = new RouteData(); 36 37 string returnValue = ""; 38 httpContext = new Mock<HttpContextBase>(); 39 httpContext.Setup(hc => hc.Request.ApplicationPath).Returns("~"); 40 httpContext.Setup(hc => hc.Response.ApplyAppPathModifier(It.IsAny<string>())) 41 .Callback<string>(s => returnValue = s) 42 .Returns(() => returnValue); 43 httpContext.Setup(hc => hc.Server.Execute(It.IsAny<IHttpHandler>(), It.IsAny<TextWriter>(), It.IsAny<bool>())); 44 45 viewContext = new ViewContext 46 { 47 RequestContext = new RequestContext(httpContext.Object, originalRouteData) 48 }; 49 50 viewDataContainer = new Mock<IViewDataContainer>(); 51 52 htmlHelper = new Mock<HtmlHelper>(viewContext, viewDataContainer.Object, routes); 53 } 54 55 [Fact] GuardClauses()56 public void GuardClauses() 57 { 58 // Act & Assert 59 Assert.ThrowsArgumentNull( 60 () => ChildActionExtensions.ActionHelper(null /* htmlHelper */, "abc", null /* controllerName */, null /* routeValues */, null /* textWriter */), 61 "htmlHelper" 62 ); 63 64 Assert.ThrowsArgumentNullOrEmpty( 65 () => ChildActionExtensions.ActionHelper(htmlHelper.Object, null /* actionName */, null /* controllerName */, null /* routeValues */, null /* textWriter */), 66 "actionName" 67 ); 68 69 Assert.ThrowsArgumentNullOrEmpty( 70 () => ChildActionExtensions.ActionHelper(htmlHelper.Object, String.Empty /* actionName */, null /* controllerName */, null /* routeValues */, null /* textWriter */), 71 "actionName" 72 ); 73 } 74 75 [Fact] ServerExecuteCalledWithWrappedChildActionMvcHandler()76 public void ServerExecuteCalledWithWrappedChildActionMvcHandler() 77 { 78 // Arrange 79 IHttpHandler callbackHandler = null; 80 TextWriter callbackTextWriter = null; 81 bool callbackPreserveForm = false; 82 httpContext.Setup(hc => hc.Server.Execute(It.IsAny<IHttpHandler>(), It.IsAny<TextWriter>(), It.IsAny<bool>())) 83 .Callback<IHttpHandler, TextWriter, bool>( 84 (handler, textWriter, preserveForm) => 85 { 86 callbackHandler = handler; 87 callbackTextWriter = textWriter; 88 callbackPreserveForm = preserveForm; 89 }); 90 TextWriter stringWriter = new StringWriter(); 91 92 // Act 93 ChildActionExtensions.ActionHelper(htmlHelper.Object, "actionName", null /* controllerName */, null /* routeValues */, stringWriter); 94 95 // Assert 96 Assert.NotNull(callbackHandler); 97 HttpHandlerUtil.ServerExecuteHttpHandlerWrapper wrapper = callbackHandler as HttpHandlerUtil.ServerExecuteHttpHandlerWrapper; 98 Assert.NotNull(wrapper); 99 Assert.NotNull(wrapper.InnerHandler); 100 ChildActionExtensions.ChildActionMvcHandler childHandler = wrapper.InnerHandler as ChildActionExtensions.ChildActionMvcHandler; 101 Assert.NotNull(childHandler); 102 Assert.Same(stringWriter, callbackTextWriter); 103 Assert.True(callbackPreserveForm); 104 } 105 106 [Fact] RouteDataTokensIncludesParentActionViewContext()107 public void RouteDataTokensIncludesParentActionViewContext() 108 { 109 // Arrange 110 MvcHandler mvcHandler = null; 111 httpContext.Setup(hc => hc.Server.Execute(It.IsAny<IHttpHandler>(), It.IsAny<TextWriter>(), It.IsAny<bool>())) 112 .Callback<IHttpHandler, TextWriter, bool>((handler, _, __) => mvcHandler = (MvcHandler)((HttpHandlerUtil.ServerExecuteHttpHandlerWrapper)handler).InnerHandler); 113 114 // Act 115 ChildActionExtensions.ActionHelper(htmlHelper.Object, "actionName", null /* controllerName */, null /* routeValues */, null /* textWriter */); 116 117 // Assert 118 Assert.Same(viewContext, mvcHandler.RequestContext.RouteData.DataTokens[ControllerContext.ParentActionViewContextToken]); 119 } 120 121 [Fact] RouteValuesIncludeNewActionName()122 public void RouteValuesIncludeNewActionName() 123 { 124 // Arrange 125 MvcHandler mvcHandler = null; 126 httpContext.Setup(hc => hc.Server.Execute(It.IsAny<IHttpHandler>(), It.IsAny<TextWriter>(), It.IsAny<bool>())) 127 .Callback<IHttpHandler, TextWriter, bool>((handler, _, __) => mvcHandler = (MvcHandler)((HttpHandlerUtil.ServerExecuteHttpHandlerWrapper)handler).InnerHandler); 128 129 // Act 130 ChildActionExtensions.ActionHelper(htmlHelper.Object, "actionName", null /* controllerName */, null /* routeValues */, null /* textWriter */); 131 132 // Assert 133 RouteData routeData = mvcHandler.RequestContext.RouteData; 134 Assert.Equal("actionName", routeData.Values["action"]); 135 } 136 137 [Fact] RouteValuesIncludeOldControllerNameWhenControllerNameIsNullOrEmpty()138 public void RouteValuesIncludeOldControllerNameWhenControllerNameIsNullOrEmpty() 139 { 140 // Arrange 141 originalRouteData.Values["controller"] = "oldController"; 142 MvcHandler mvcHandler = null; 143 httpContext.Setup(hc => hc.Server.Execute(It.IsAny<IHttpHandler>(), It.IsAny<TextWriter>(), It.IsAny<bool>())) 144 .Callback<IHttpHandler, TextWriter, bool>((handler, _, __) => mvcHandler = (MvcHandler)((HttpHandlerUtil.ServerExecuteHttpHandlerWrapper)handler).InnerHandler); 145 146 // Act 147 ChildActionExtensions.ActionHelper(htmlHelper.Object, "actionName", null /* controllerName */, null /* routeValues */, null /* textWriter */); 148 149 // Assert 150 RouteData routeData = mvcHandler.RequestContext.RouteData; 151 Assert.Equal("oldController", routeData.Values["controller"]); 152 } 153 154 [Fact] RouteValuesIncludeNewControllerNameWhenControllNameIsNotEmpty()155 public void RouteValuesIncludeNewControllerNameWhenControllNameIsNotEmpty() 156 { 157 // Arrange 158 originalRouteData.Values["controller"] = "oldController"; 159 MvcHandler mvcHandler = null; 160 httpContext.Setup(hc => hc.Server.Execute(It.IsAny<IHttpHandler>(), It.IsAny<TextWriter>(), It.IsAny<bool>())) 161 .Callback<IHttpHandler, TextWriter, bool>((handler, _, __) => mvcHandler = (MvcHandler)((HttpHandlerUtil.ServerExecuteHttpHandlerWrapper)handler).InnerHandler); 162 163 // Act 164 ChildActionExtensions.ActionHelper(htmlHelper.Object, "actionName", "newController", null /* routeValues */, null /* textWriter */); 165 166 // Assert 167 RouteData routeData = mvcHandler.RequestContext.RouteData; 168 Assert.Equal("newController", routeData.Values["controller"]); 169 } 170 171 [Fact] PassedRouteValuesOverrideParentRequestRouteValues()172 public void PassedRouteValuesOverrideParentRequestRouteValues() 173 { 174 // Arrange 175 originalRouteData.Values["name1"] = "value1"; 176 originalRouteData.Values["name2"] = "value2"; 177 MvcHandler mvcHandler = null; 178 httpContext.Setup(hc => hc.Server.Execute(It.IsAny<IHttpHandler>(), It.IsAny<TextWriter>(), It.IsAny<bool>())) 179 .Callback<IHttpHandler, TextWriter, bool>((handler, _, __) => mvcHandler = (MvcHandler)((HttpHandlerUtil.ServerExecuteHttpHandlerWrapper)handler).InnerHandler); 180 181 // Act 182 ChildActionExtensions.ActionHelper(htmlHelper.Object, "actionName", null /* controllerName */, new RouteValueDictionary { { "name2", "newValue2" } }, null /* textWriter */); 183 184 // Assert 185 RouteData routeData = mvcHandler.RequestContext.RouteData; 186 Assert.Equal("value1", routeData.Values["name1"]); 187 Assert.Equal("newValue2", routeData.Values["name2"]); 188 189 Assert.Equal("newValue2", (routeData.Values[ChildActionValueProvider.ChildActionValuesKey] as DictionaryValueProvider<object>).GetValue("name2").RawValue); 190 } 191 192 [Fact] NoChildActionValuesDictionaryCreatedIfNoRouteValuesPassed()193 public void NoChildActionValuesDictionaryCreatedIfNoRouteValuesPassed() 194 { 195 // Arrange 196 MvcHandler mvcHandler = null; 197 httpContext.Setup(hc => hc.Server.Execute(It.IsAny<IHttpHandler>(), It.IsAny<TextWriter>(), It.IsAny<bool>())) 198 .Callback<IHttpHandler, TextWriter, bool>((handler, _, __) => mvcHandler = (MvcHandler)((HttpHandlerUtil.ServerExecuteHttpHandlerWrapper)handler).InnerHandler); 199 200 // Act 201 ChildActionExtensions.ActionHelper(htmlHelper.Object, "actionName", null /* controllerName */, null, null /* textWriter */); 202 203 // Assert 204 RouteData routeData = mvcHandler.RequestContext.RouteData; 205 Assert.Null(routeData.Values[ChildActionValueProvider.ChildActionValuesKey]); 206 } 207 208 [Fact] RouteValuesDoesNotIncludeExplicitlyPassedAreaName()209 public void RouteValuesDoesNotIncludeExplicitlyPassedAreaName() 210 { 211 // Arrange 212 Route route = routes.MapRoute("my-area", "my-area"); 213 route.DataTokens["area"] = "myArea"; 214 MvcHandler mvcHandler = null; 215 httpContext.Setup(hc => hc.Server.Execute(It.IsAny<IHttpHandler>(), It.IsAny<TextWriter>(), It.IsAny<bool>())) 216 .Callback<IHttpHandler, TextWriter, bool>((handler, _, __) => mvcHandler = (MvcHandler)((HttpHandlerUtil.ServerExecuteHttpHandlerWrapper)handler).InnerHandler); 217 218 // Act 219 ChildActionExtensions.ActionHelper(htmlHelper.Object, "actionName", null /* controllerName */, new RouteValueDictionary { { "area", "myArea" } }, null /* textWriter */); 220 221 // Assert 222 RouteData routeData = mvcHandler.RequestContext.RouteData; 223 Assert.False(routeData.Values.ContainsKey("area")); 224 Assert.Null((routeData.Values[ChildActionValueProvider.ChildActionValuesKey] as DictionaryValueProvider<object>).GetValue("area")); 225 } 226 227 [Fact] RouteValuesIncludeExplicitlyPassedAreaNameIfAreasNotInUse()228 public void RouteValuesIncludeExplicitlyPassedAreaNameIfAreasNotInUse() 229 { 230 // Arrange 231 Route route = routes.MapRoute("my-area", "my-area"); 232 MvcHandler mvcHandler = null; 233 httpContext.Setup(hc => hc.Server.Execute(It.IsAny<IHttpHandler>(), It.IsAny<TextWriter>(), It.IsAny<bool>())) 234 .Callback<IHttpHandler, TextWriter, bool>((handler, _, __) => mvcHandler = (MvcHandler)((HttpHandlerUtil.ServerExecuteHttpHandlerWrapper)handler).InnerHandler); 235 236 // Act 237 ChildActionExtensions.ActionHelper(htmlHelper.Object, "actionName", null /* controllerName */, new RouteValueDictionary { { "area", "myArea" } }, null /* textWriter */); 238 239 // Assert 240 RouteData routeData = mvcHandler.RequestContext.RouteData; 241 Assert.True(routeData.Values.ContainsKey("area")); 242 Assert.Equal("myArea", (routeData.Values[ChildActionValueProvider.ChildActionValuesKey] as DictionaryValueProvider<object>).GetValue("area").RawValue); 243 } 244 245 [Fact] NoMatchingRouteThrows()246 public void NoMatchingRouteThrows() 247 { 248 // Arrange 249 routes.Clear(); 250 251 // Act & Assert 252 Assert.Throws<InvalidOperationException>( 253 () => ChildActionExtensions.ActionHelper(htmlHelper.Object, "actionName", null /* controllerName */, null /* routeValues */, null /* textWriter */), 254 MvcResources.Common_NoRouteMatched 255 ); 256 } 257 } 258 } 259