// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information. using System.Collections.Generic; using System.Linq; using System.Web.Routing; using Moq; using Xunit; using Assert = Microsoft.TestCommon.AssertEx; namespace System.Web.Mvc.Test { public class RemoteAttributeTest { // Good route name, bad route name // Controller + Action [Fact] public void GuardClauses() { // Act & Assert Assert.ThrowsArgumentNullOrEmpty( () => new RemoteAttribute(null, "controller"), "action"); Assert.ThrowsArgumentNullOrEmpty( () => new RemoteAttribute("action", null), "controller"); Assert.ThrowsArgumentNullOrEmpty( () => new RemoteAttribute(null), "routeName"); Assert.ThrowsArgumentNullOrEmpty( () => RemoteAttribute.FormatPropertyForClientValidation(String.Empty), "property"); Assert.ThrowsArgumentNullOrEmpty( () => new RemoteAttribute("foo").FormatAdditionalFieldsForClientValidation(String.Empty), "property"); } [Fact] public void IsValidAlwaysReturnsTrue() { // Act & Assert Assert.True(new RemoteAttribute("RouteName", "ParameterName").IsValid(null)); Assert.True(new RemoteAttribute("ActionName", "ControllerName", "ParameterName").IsValid(null)); } [Fact] public void BadRouteNameThrows() { // Arrange ControllerContext context = new ControllerContext(); ModelMetadata metadata = ModelMetadataProviders.Current.GetMetadataForType(null, typeof(object)); TestableRemoteAttribute attribute = new TestableRemoteAttribute("RouteName"); // Act & Assert Assert.Throws( () => new List(attribute.GetClientValidationRules(metadata, context)), "A route named 'RouteName' could not be found in the route collection.\r\nParameter name: name"); } [Fact] public void NoRouteWithActionControllerThrows() { // Arrange ControllerContext context = new ControllerContext(); ModelMetadata metadata = ModelMetadataProviders.Current.GetMetadataForProperty(null, typeof(string), "Length"); TestableRemoteAttribute attribute = new TestableRemoteAttribute("Action", "Controller"); // Act & Assert Assert.Throws( () => new List(attribute.GetClientValidationRules(metadata, context)), "No url for remote validation could be found."); } [Fact] public void GoodRouteNameReturnsCorrectClientData() { // Arrange string url = null; ModelMetadata metadata = ModelMetadataProviders.Current.GetMetadataForProperty(null, typeof(string), "Length"); TestableRemoteAttribute attribute = new TestableRemoteAttribute("RouteName"); attribute.RouteTable.Add("RouteName", new Route("my/url", new MvcRouteHandler())); // Act ModelClientValidationRule rule = attribute.GetClientValidationRules(metadata, GetMockControllerContext(url)).Single(); // Assert Assert.Equal("remote", rule.ValidationType); Assert.Equal("'Length' is invalid.", rule.ErrorMessage); Assert.Equal(2, rule.ValidationParameters.Count); Assert.Equal("/my/url", rule.ValidationParameters["url"]); } [Fact] public void ActionControllerReturnsCorrectClientDataWithoutNamedParameters() { // Arrange string url = null; ModelMetadata metadata = ModelMetadataProviders.Current.GetMetadataForProperty(null, typeof(string), "Length"); TestableRemoteAttribute attribute = new TestableRemoteAttribute("Action", "Controller"); attribute.RouteTable.Add(new Route("{controller}/{action}", new MvcRouteHandler())); // Act ModelClientValidationRule rule = attribute.GetClientValidationRules(metadata, GetMockControllerContext(url)).Single(); // Assert Assert.Equal("remote", rule.ValidationType); Assert.Equal("'Length' is invalid.", rule.ErrorMessage); Assert.Equal(2, rule.ValidationParameters.Count); Assert.Equal("/Controller/Action", rule.ValidationParameters["url"]); Assert.Equal("*.Length", rule.ValidationParameters["additionalfields"]); Assert.Throws( () => rule.ValidationParameters["type"], "The given key was not present in the dictionary."); } [Fact] public void ActionControllerReturnsCorrectClientDataWithNamedParameters() { // Arrange string url = null; ModelMetadata metadata = ModelMetadataProviders.Current.GetMetadataForProperty(null, typeof(string), "Length"); TestableRemoteAttribute attribute = new TestableRemoteAttribute("Action", "Controller"); attribute.HttpMethod = "POST"; attribute.AdditionalFields = "Password,ConfirmPassword"; attribute.RouteTable.Add(new Route("{controller}/{action}", new MvcRouteHandler())); // Act ModelClientValidationRule rule = attribute.GetClientValidationRules(metadata, GetMockControllerContext(url)).Single(); // Assert Assert.Equal("remote", rule.ValidationType); Assert.Equal("'Length' is invalid.", rule.ErrorMessage); Assert.Equal(3, rule.ValidationParameters.Count); Assert.Equal("/Controller/Action", rule.ValidationParameters["url"]); Assert.Equal("*.Length,*.Password,*.ConfirmPassword", rule.ValidationParameters["additionalfields"]); Assert.Equal("POST", rule.ValidationParameters["type"]); } private ControllerContext GetMockControllerContext(string url) { Mock context = new Mock(); context.Setup(c => c.HttpContext.Request.ApplicationPath) .Returns("/"); context.Setup(c => c.HttpContext.Response.ApplyAppPathModifier(It.IsAny())) .Callback(vpath => url = vpath) .Returns(() => url); return context.Object; } private class TestableRemoteAttribute : RemoteAttribute { public RouteCollection RouteTable = new RouteCollection(); public TestableRemoteAttribute(string action, string controller) : base(action, controller) { } public TestableRemoteAttribute(string routeName) : base(routeName) { } protected override RouteCollection Routes { get { return RouteTable; } } } } }