// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information. using System; using System.Linq.Expressions; using System.Web.Mvc; using System.Web.Routing; using Xunit; using Assert = Microsoft.TestCommon.AssertEx; using ExpressionHelper = Microsoft.Web.Mvc.Internal.ExpressionHelper; namespace Microsoft.Web.Mvc.Test { public class ExpressionHelperTest { [Fact] public void BuildRouteValueDictionary_TargetsAsynchronousAsyncMethod_StripsSuffix() { // Arrange Expression> expr = (c => c.AsynchronousAsync()); // Act RouteValueDictionary rvd = ExpressionHelper.GetRouteValuesFromExpression(expr); // Assert Assert.Equal("Asynchronous", rvd["action"]); Assert.Equal("TestAsync", rvd["controller"]); Assert.False(rvd.ContainsKey("area")); } [Fact] public void BuildRouteValueDictionary_TargetsAsynchronousCompletedMethod_Throws() { // Arrange Expression> expr = (c => c.AsynchronousCompleted()); // Act & assert Assert.Throws( delegate { ExpressionHelper.GetRouteValuesFromExpression(expr); }, @"The method 'AsynchronousCompleted' is an asynchronous completion method and cannot be called directly."); } [Fact] public void BuildRouteValueDictionary_TargetsControllerWithAreaAttribute_AddsAreaName() { // Arrange Expression> expr = c => c.Index(); // Act RouteValueDictionary rvd = ExpressionHelper.GetRouteValuesFromExpression(expr); // Assert Assert.Equal("Index", rvd["action"]); Assert.Equal("ControllerWithArea", rvd["controller"]); Assert.Equal("the area name", rvd["area"]); } [Fact] public void BuildRouteValueDictionary_TargetsNonActionMethod_Throws() { // Arrange Expression> expr = (c => c.NotAnAction()); // Act & assert Assert.Throws( delegate { ExpressionHelper.GetRouteValuesFromExpression(expr); }, @"The method 'NotAnAction' is marked [NonAction] and cannot be called directly."); } [Fact] public void BuildRouteValueDictionary_TargetsRenamedMethod_UsesNewName() { // Arrange Expression> expr = (c => c.Renamed()); // Act RouteValueDictionary rvd = ExpressionHelper.GetRouteValuesFromExpression(expr); // Assert Assert.Equal("NewName", rvd["action"]); Assert.Equal("Test", rvd["controller"]); Assert.False(rvd.ContainsKey("area")); } [Fact] public void BuildRouteValueDictionary_TargetsSynchronousMethodOnAsyncController_ReturnsOriginalName() { // Arrange Expression> expr = (c => c.Synchronous()); // Act RouteValueDictionary rvd = ExpressionHelper.GetRouteValuesFromExpression(expr); // Assert Assert.Equal("Synchronous", rvd["action"]); Assert.Equal("TestAsync", rvd["controller"]); Assert.False(rvd.ContainsKey("area")); } [Fact] public void BuildRouteValueDictionaryWithNullExpressionThrowsArgumentNullException() { Assert.ThrowsArgumentNull( () => ExpressionHelper.GetRouteValuesFromExpression(null), "action"); } [Fact] public void BuildRouteValueDictionaryWithNonMethodExpressionThrowsInvalidOperationException() { // Arrange Expression> expression = c => new TestController(); // Act & Assert Assert.Throws( () => ExpressionHelper.GetRouteValuesFromExpression(expression), "Expression must be a method call." + Environment.NewLine + "Parameter name: action"); } [Fact] public void BuildRouteValueDictionaryWithoutControllerSuffixThrowsInvalidOperationException() { // Arrange Expression> index = (c => c.Index(123)); // Act & Assert Assert.Throws( () => ExpressionHelper.GetRouteValuesFromExpression(index), "Controller name must end in 'Controller'." + Environment.NewLine + "Parameter name: action"); } [Fact] public void BuildRouteValueDictionaryWithControllerBaseClassThrowsInvalidOperationException() { // Arrange Expression> index = (c => c.Dispose()); // Act & Assert Assert.Throws( () => ExpressionHelper.GetRouteValuesFromExpression(index), "Cannot route to class named 'Controller'." + Environment.NewLine + "Parameter name: action"); } [Fact] public void BuildRouteValueDictionaryAddsControllerNameToDictionary() { // Arrange Expression> index = (c => c.Index(123)); // Act RouteValueDictionary rvd = ExpressionHelper.GetRouteValuesFromExpression(index); // Assert Assert.Equal("Test", rvd["Controller"]); } [Fact] public void BuildRouteValueDictionaryFromExpressionReturnsCorrectDictionary() { // Arrange Expression> index = (c => c.Index(123)); // Act RouteValueDictionary rvd = ExpressionHelper.GetRouteValuesFromExpression(index); // Assert Assert.Equal("Test", rvd["Controller"]); Assert.Equal("Index", rvd["Action"]); Assert.Equal(123, rvd["page"]); } [Fact] public void BuildRouteValueDictionaryFromNonConstantExpressionReturnsCorrectDictionary() { // Arrange Expression> index = (c => c.About(Foo)); // Act RouteValueDictionary rvd = ExpressionHelper.GetRouteValuesFromExpression(index); // Assert Assert.Equal("Test", rvd["Controller"]); Assert.Equal("About", rvd["Action"]); Assert.Equal("FooValue", rvd["s"]); } [Fact] public void GetInputNameFromPropertyExpressionReturnsPropertyName() { // Arrange Expression> expression = m => m.IntProperty; // Act string name = ExpressionHelper.GetInputName(expression); // Assert Assert.Equal("IntProperty", name); } [Fact] public void GetInputNameFromPropertyWithMethodCallExpressionReturnsPropertyName() { // Arrange Expression> expression = m => m.IntProperty.ToString(); // Act string name = ExpressionHelper.GetInputName(expression); // Assert Assert.Equal("IntProperty", name); } [Fact] public void GetInputNameFromPropertyWithTwoMethodCallExpressionReturnsPropertyName() { // Arrange Expression> expression = m => m.IntProperty.ToString().ToUpper(); // Act string name = ExpressionHelper.GetInputName(expression); // Assert Assert.Equal("IntProperty", name); } [Fact] public void GetInputNameFromExpressionWithTwoPropertiesUsesWholeExpression() { // Arrange Expression> expression = m => m.StringProperty.Length; // Act string name = ExpressionHelper.GetInputName(expression); // Assert Assert.Equal("StringProperty.Length", name); } public class TestController : Controller { public ActionResult Index(int page) { return null; } public string About(string s) { return "The value is " + s; } [ActionName("NewName")] public void Renamed() { } [NonAction] public void NotAnAction() { } } public class TestAsyncController : AsyncController { public void Synchronous() { } public void AsynchronousAsync() { } public void AsynchronousCompleted() { } } public string Foo { get { return "FooValue"; } } public class TestControllerNot : Controller { public ActionResult Index(int page) { return null; } } [ActionLinkArea("the area name")] public class ControllerWithAreaController : Controller { public ActionResult Index() { return null; } } public class TestModel { public int IntProperty { get; set; } public string StringProperty { get; set; } } } }