diff --git a/samples/RoutingSample.Web/Startup.cs b/samples/RoutingSample.Web/Startup.cs
index c0f8704d97..fb3dc00172 100644
--- a/samples/RoutingSample.Web/Startup.cs
+++ b/samples/RoutingSample.Web/Startup.cs
@@ -1,8 +1,7 @@
using System.Text.RegularExpressions;
-using Microsoft.AspNet;
using Microsoft.AspNet.Builder;
-using Microsoft.AspNet.Http;
using Microsoft.AspNet.Routing;
+using Microsoft.AspNet.Routing.Constraints;
namespace RoutingSample.Web
{
diff --git a/src/Microsoft.AspNet.Routing/Microsoft.AspNet.Routing.kproj b/src/Microsoft.AspNet.Routing/Microsoft.AspNet.Routing.kproj
index b7a6c5c243..f82446805f 100644
--- a/src/Microsoft.AspNet.Routing/Microsoft.AspNet.Routing.kproj
+++ b/src/Microsoft.AspNet.Routing/Microsoft.AspNet.Routing.kproj
@@ -24,6 +24,7 @@
+
@@ -33,7 +34,6 @@
-
@@ -52,4 +52,4 @@
-
+
\ No newline at end of file
diff --git a/src/Microsoft.AspNet.Routing/Template/TemplateParser.cs b/src/Microsoft.AspNet.Routing/Template/TemplateParser.cs
index 7e1981f3c7..be6dc62012 100644
--- a/src/Microsoft.AspNet.Routing/Template/TemplateParser.cs
+++ b/src/Microsoft.AspNet.Routing/Template/TemplateParser.cs
@@ -196,10 +196,6 @@ namespace Microsoft.AspNet.Routing.Template
context.Error = Resources.TemplateRoute_OptionalCannotHaveDefaultValue;
return false;
}
- // A workaround is to add it as a separate entry in the defaults argument.
- context.Error = Resources.TemplateRoute_OptionalCannotHaveDefaultValue;
- return false;
- }
var parameterName = templatePart.Name;
if (IsValidParameterName(context, parameterName))
diff --git a/src/Microsoft.AspNet.Routing/Template/TemplateRoute.cs b/src/Microsoft.AspNet.Routing/Template/TemplateRoute.cs
index c86a880689..3979ddf413 100644
--- a/src/Microsoft.AspNet.Routing/Template/TemplateRoute.cs
+++ b/src/Microsoft.AspNet.Routing/Template/TemplateRoute.cs
@@ -43,13 +43,13 @@ namespace Microsoft.AspNet.Routing.Template
_routeTemplate = routeTemplate ?? string.Empty;
Name = routeName;
_defaults = defaults ?? new Dictionary(StringComparer.OrdinalIgnoreCase);
- _constraints = RouteConstraintBuilder.BuildConstraints(constraints, _routeTemplate) ??
+ _constraints = RouteConstraintBuilder.BuildConstraints(constraints, _routeTemplate) ??
new Dictionary();
// The parser will throw for invalid routes.
_parsedTemplate = TemplateParser.Parse(RouteTemplate, inlineConstraintResolver);
UpdateInlineDefaultValuesAndConstraints();
-
+
_matcher = new TemplateMatcher(_parsedTemplate);
_binder = new TemplateBinder(_parsedTemplate, _defaults);
}
@@ -184,14 +184,13 @@ namespace Microsoft.AspNet.Routing.Template
IRouteConstraint constraint;
if (_constraints.TryGetValue(parameter.Name, out constraint))
{
- _constraints[parameter.Name] =
- new CompositeRouteConstraint(new []{ constraint, parameter.InlineConstraint });
+ _constraints[parameter.Name] =
+ new CompositeRouteConstraint(new[] { constraint, parameter.InlineConstraint });
}
else
{
_constraints[parameter.Name] = parameter.InlineConstraint;
}
- }
}
if (parameter.DefaultValue != null)
@@ -210,4 +209,4 @@ namespace Microsoft.AspNet.Routing.Template
}
}
}
-}
+}
\ No newline at end of file
diff --git a/test/Microsoft.AspNet.Routing.Tests/DefaultInlineConstraintResolverTest.cs b/test/Microsoft.AspNet.Routing.Tests/DefaultInlineConstraintResolverTest.cs
new file mode 100644
index 0000000000..5e60434e23
--- /dev/null
+++ b/test/Microsoft.AspNet.Routing.Tests/DefaultInlineConstraintResolverTest.cs
@@ -0,0 +1,81 @@
+// 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.Http;
+using Microsoft.AspNet.Routing.Constraints;
+using Xunit;
+
+namespace Microsoft.AspNet.Routing.Tests
+{
+ public class DefaultInlineConstraintResolverTest
+ {
+ [Fact]
+ public void ResolveConstraint_IntConstraint_ResolvesCorrectly()
+ {
+ // Arrange & Act
+ var constraint = new DefaultInlineConstraintResolver().ResolveConstraint("int");
+
+ // Assert
+ Assert.IsType(constraint);
+ }
+
+ [Fact]
+ public void ResolveConstraint_IntConstraintWithArgument_Throws()
+ {
+ // Act & Assert
+ var ex = Assert.Throws(
+ () => new DefaultInlineConstraintResolver().ResolveConstraint("int(5)"));
+ Assert.Equal("Could not find a constructor for constraint type 'IntRouteConstraint'"+
+ " with the following number of parameters: 1.",
+ ex.Message);
+ }
+
+ [Fact]
+ public void ResolveConstraint_SupportsCustomConstraints()
+ {
+ // Arrange
+ var resolver = new DefaultInlineConstraintResolver();
+ resolver.ConstraintMap.Add("custom", typeof(CustomRouteConstraint));
+
+ // Act
+ var constraint = resolver.ResolveConstraint("custom(argument)");
+
+ // Assert
+ Assert.IsType(constraint);
+ }
+
+ [Fact]
+ public void ResolveConstraint_CustomConstraintThatDoesNotImplementIRouteConstraint_Throws()
+ {
+ // Arrange
+ var resolver = new DefaultInlineConstraintResolver();
+ resolver.ConstraintMap.Add("custom", typeof(string));
+
+ // Act & Assert
+ var ex = Assert.Throws(() => resolver.ResolveConstraint("custom"));
+ Assert.Equal("The constraint type 'System.String' which is mapped to constraint key 'custom'"+
+ " must implement the 'IRouteConstraint' interface.",
+ ex.Message);
+ }
+
+ private class CustomRouteConstraint : IRouteConstraint
+ {
+ public CustomRouteConstraint(string pattern)
+ {
+ Pattern = pattern;
+ }
+
+ public string Pattern { get; private set; }
+ public bool Match(HttpContext httpContext,
+ IRouter route,
+ string routeKey,
+ IDictionary values,
+ RouteDirection routeDirection)
+ {
+ return true;
+ }
+ }
+ }
+}
diff --git a/test/Microsoft.AspNet.Routing.Tests/InlineRouteParameterParserTests.cs b/test/Microsoft.AspNet.Routing.Tests/InlineRouteParameterParserTests.cs
new file mode 100644
index 0000000000..20bf7be646
--- /dev/null
+++ b/test/Microsoft.AspNet.Routing.Tests/InlineRouteParameterParserTests.cs
@@ -0,0 +1,304 @@
+// 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 System.Linq;
+using Microsoft.AspNet.Http;
+using Microsoft.AspNet.Routing.Constraints;
+using Microsoft.AspNet.Routing.Template;
+using Xunit;
+
+namespace Microsoft.AspNet.Routing.Tests
+{
+ public class InlineRouteParameterParserTests
+ {
+ [Fact]
+ public void ParseRouteParameter_ConstraintAndDefault_ParsedCorrectly()
+ {
+ // Arrange & Act
+ var templatePart = ParseParameter("param:int=111111");
+
+ // Assert
+ Assert.Equal("param", templatePart.Name);
+ Assert.Equal("111111", templatePart.DefaultValue);
+ Assert.IsType(templatePart.InlineConstraint);
+ }
+
+ [Fact]
+ public void ParseRouteParameter_ConstraintWithArgumentsAndDefault_ParsedCorrectly()
+ {
+ // Arrange & Act
+ var templatePart = ParseParameter(@"param:test(\d+)=111111");
+
+ // Assert
+ Assert.Equal("param", templatePart.Name);
+ Assert.Equal("111111", templatePart.DefaultValue);
+ Assert.IsType(templatePart.InlineConstraint);
+ Assert.Equal(@"\d+", ((TestRouteConstraint)templatePart.InlineConstraint).Pattern);
+ }
+
+ [Fact]
+ public void ParseRouteParameter_ConstraintAndOptional_ParsedCorrectly()
+ {
+ // Arrange & Act
+ var templatePart = ParseParameter(@"param:int?");
+
+ // Assert
+ Assert.Equal("param", templatePart.Name);
+ Assert.True(templatePart.IsOptional);
+ Assert.IsType(templatePart.InlineConstraint);
+ }
+
+ [Fact]
+ public void ParseRouteParameter_ConstraintWithArgumentsAndOptional_ParsedCorrectly()
+ {
+ // Arrange & Act
+ var templatePart = ParseParameter(@"param:test(\d+)?");
+
+ // Assert
+ Assert.Equal("param", templatePart.Name);
+ Assert.True(templatePart.IsOptional);
+ Assert.Equal(@"\d+", ((TestRouteConstraint)templatePart.InlineConstraint).Pattern);
+ }
+
+ [Fact]
+ public void ParseRouteParameter_ChainedConstraints_ParsedCorrectly()
+ {
+ // Arrange & Act
+ var templatePart = ParseParameter(@"param:test(\d+):test(\w+)");
+
+ // Assert
+ Assert.Equal("param", templatePart.Name);
+ Assert.IsType(templatePart.InlineConstraint);
+ var constraint = (CompositeRouteConstraint)templatePart.InlineConstraint;
+ Assert.Equal(@"\d+", ((TestRouteConstraint)constraint.Constraints.ElementAt(0)).Pattern);
+ Assert.Equal(@"\w+", ((TestRouteConstraint)constraint.Constraints.ElementAt(1)).Pattern);
+ }
+
+ [Fact]
+ public void ParseRouteTemplate_ConstraintsDefaultsAndOptionalsInMultipleSections_ParsedCorrectly()
+ {
+ // Arrange & Act
+ var template = ParseRouteTemplate(@"some/url-{p1:int:test(3)=hello}/{p2=abc}/{p3?}");
+
+ // Assert
+ var parameters = template.Parameters.ToArray();
+
+ var param1 = parameters[0];
+ Assert.Equal("p1", param1.Name);
+ Assert.Equal("hello", param1.DefaultValue);
+ Assert.False(param1.IsOptional);
+ Assert.IsType(param1.InlineConstraint);
+ var constraint = (CompositeRouteConstraint)param1.InlineConstraint;
+ Assert.IsType(constraint.Constraints.ElementAt(0));
+ Assert.IsType(constraint.Constraints.ElementAt(1));
+
+ var param2 = parameters[1];
+ Assert.Equal("p2", param2.Name);
+ Assert.Equal("abc", param2.DefaultValue);
+ Assert.False(param2.IsOptional);
+
+ var param3 = parameters[2];
+ Assert.Equal("p3", param3.Name);
+ Assert.True(param3.IsOptional);
+ }
+
+ [Fact]
+ public void ParseRouteParameter_NoTokens_ParsedCorrectly()
+ {
+ // Arrange & Act
+ var templatePart = ParseParameter("world");
+
+ // Assert
+ Assert.Equal("world", templatePart.Name);
+ }
+
+ [Fact]
+ public void ParseRouteParameter_ParamDefault_ParsedCorrectly()
+ {
+ // Arrange & Act
+ var templatePart = ParseParameter("param=world");
+
+ // Assert
+ Assert.Equal("param", templatePart.Name);
+ Assert.Equal("world", templatePart.DefaultValue);
+ }
+
+ [Fact]
+ public void ParseRouteParameter_ConstraintWithClosingBraceInPattern_ClosingBraceIsParsedCorrectly()
+ {
+ // Arrange & Act
+ var templatePart = ParseParameter(@"param:test(\})");
+
+ // Assert
+ Assert.Equal("param", templatePart.Name);
+ Assert.IsType(templatePart.InlineConstraint);
+ Assert.Equal(@"\}", ((TestRouteConstraint)templatePart.InlineConstraint).Pattern);
+ }
+
+ [Fact]
+ public void ParseRouteParameter_ConstraintWithClosingParenInPattern_ClosingParenIsParsedCorrectly()
+ {
+ // Arrange & Act
+ var templatePart = ParseParameter(@"param:test(\))");
+
+ // Assert
+ Assert.Equal("param", templatePart.Name);
+ Assert.IsType(templatePart.InlineConstraint);
+ Assert.Equal(@"\)", ((TestRouteConstraint)templatePart.InlineConstraint).Pattern);
+ }
+
+ [Fact]
+ public void ParseRouteParameter_ConstraintWithColonInPattern_ColonIsParsedCorrectly()
+ {
+ // Arrange & Act
+ var templatePart = ParseParameter(@"param:test(:)");
+
+ // Assert
+ Assert.Equal("param", templatePart.Name);
+ Assert.IsType(templatePart.InlineConstraint);
+ Assert.Equal(@":", ((TestRouteConstraint)templatePart.InlineConstraint).Pattern);
+ }
+
+ [Fact]
+ public void ParseRouteParameter_ConstraintWithCommaInPattern_PatternIsParsedCorrectly()
+ {
+ // Arrange
+ var templatePart = ParseParameter(@"param:test(\w,\w)");
+
+ // Assert
+ Assert.Equal("param", templatePart.Name);
+ Assert.IsType(templatePart.InlineConstraint);
+ Assert.Equal(@"\w,\w", ((TestRouteConstraint)templatePart.InlineConstraint).Pattern);
+ }
+
+ [Theory]
+ [InlineData(",")]
+ [InlineData("(")]
+ [InlineData(")")]
+ [InlineData("}")]
+ [InlineData("{")]
+ public void ParseRouteParameter_MisplacedSpecialCharacterInParameter_Throws(string character)
+ {
+ // Arrange
+ var unresolvedConstraint = character + @"test(\w,\w)";
+ var parameter = "param:" + unresolvedConstraint;
+
+ // Act & Assert
+ var ex = Assert.Throws(() => ParseParameter(parameter));
+ Assert.Equal(@"The inline constraint resolver of type 'DefaultInlineConstraintResolver'"+
+ " was unable to resolve the following inline constraint: '"+ unresolvedConstraint + "'.",
+ ex.Message);
+ }
+
+ [Fact]
+ public void ParseRouteParameter_ConstraintWithEqualsSignInPattern_PatternIsParsedCorrectly()
+ {
+ // Arrange & Act
+ var templatePart = ParseParameter(@"param:test(=)");
+
+ // Assert
+ Assert.Equal("param", templatePart.Name);
+ Assert.Null(templatePart.DefaultValue);
+ Assert.IsType(templatePart.InlineConstraint);
+ Assert.Equal(@"=", ((TestRouteConstraint)templatePart.InlineConstraint).Pattern);
+ }
+
+ [Fact]
+ public void ParseRouteParameter_ConstraintWithOpenBraceInPattern_PatternIsParsedCorrectly()
+ {
+ // Arrange & Act
+ var templatePart = ParseParameter(@"param:test(\{)");
+
+ // Assert
+ Assert.Equal("param", templatePart.Name);
+ Assert.IsType(templatePart.InlineConstraint);
+ Assert.Equal(@"\{", ((TestRouteConstraint)templatePart.InlineConstraint).Pattern);
+ }
+
+ [Fact]
+ public void ParseRouteParameter_ConstraintWithOpenParenInPattern_PatternIsParsedCorrectly()
+ {
+ // Arrange & Act
+ var templatePart = ParseParameter(@"param:test(\()");
+
+ // Assert
+ Assert.Equal("param", templatePart.Name);
+ Assert.IsType(templatePart.InlineConstraint);
+ Assert.Equal(@"\(", ((TestRouteConstraint)templatePart.InlineConstraint).Pattern);
+ }
+
+ [Fact]
+ public void ParseRouteParameter_ConstraintWithQuestionMarkInPattern_PatternIsParsedCorrectly()
+ {
+ // Arrange & Act
+ var templatePart = ParseParameter(@"param:test(\?)");
+
+ // Assert
+ Assert.Equal("param", templatePart.Name);
+ Assert.Null(templatePart.DefaultValue);
+ Assert.False(templatePart.IsOptional);
+ Assert.IsType(templatePart.InlineConstraint);
+ Assert.Equal(@"\?", ((TestRouteConstraint)templatePart.InlineConstraint).Pattern);
+ }
+
+ [Theory]
+ [InlineData("", "")]
+ [InlineData("?", "")]
+ [InlineData("*", "")]
+ [InlineData(" ", " ")]
+ [InlineData("\t", "\t")]
+ [InlineData("#!@#$%Q@#@%", "#!@#$%Q@#@%")]
+ [InlineData(",,,", ",,,")]
+ public void ParseRouteParameter_ParameterWithoutInlineConstraint_ReturnsTemplatePartWithEmptyInlineValues(
+ string parameter,
+ string expectedParameterName)
+ {
+ // Arrange & Act
+ var templatePart = ParseParameter(parameter);
+
+ // Assert
+ Assert.Equal(expectedParameterName, templatePart.Name);
+ Assert.Null(templatePart.InlineConstraint);
+ Assert.Null(templatePart.DefaultValue);
+ }
+
+
+ private TemplatePart ParseParameter(string routeParameter)
+ {
+ var constraintResolver = new DefaultInlineConstraintResolver();
+
+ // TODO: This will be removed once this is supported in product code.
+ constraintResolver.ConstraintMap.Add("test", typeof(TestRouteConstraint));
+ var templatePart = InlineRouteParameterParser.ParseRouteParameter(routeParameter, constraintResolver);
+ return templatePart;
+ }
+
+ private static Template.Template ParseRouteTemplate(string template)
+ {
+ var constraintResolver = new DefaultInlineConstraintResolver();
+
+ constraintResolver.ConstraintMap.Add("test", typeof(TestRouteConstraint));
+ return TemplateParser.Parse(template, constraintResolver);
+ }
+
+ private class TestRouteConstraint : IRouteConstraint
+ {
+ public TestRouteConstraint(string pattern)
+ {
+ Pattern = pattern;
+ }
+
+ public string Pattern { get; private set; }
+ public bool Match(HttpContext httpContext,
+ IRouter route,
+ string routeKey,
+ IDictionary values,
+ RouteDirection routeDirection)
+ {
+ throw new NotImplementedException();
+ }
+ }
+ }
+}
diff --git a/test/Microsoft.AspNet.Routing.Tests/Microsoft.AspNet.Routing.Tests.kproj b/test/Microsoft.AspNet.Routing.Tests/Microsoft.AspNet.Routing.Tests.kproj
index 1e7eda8fbb..fadc051a54 100644
--- a/test/Microsoft.AspNet.Routing.Tests/Microsoft.AspNet.Routing.Tests.kproj
+++ b/test/Microsoft.AspNet.Routing.Tests/Microsoft.AspNet.Routing.Tests.kproj
@@ -22,8 +22,11 @@
+
+
+
diff --git a/test/Microsoft.AspNet.Routing.Tests/RouteConstraintsTests.cs b/test/Microsoft.AspNet.Routing.Tests/RouteConstraintsTests.cs
new file mode 100644
index 0000000000..3f1fa3f2ec
--- /dev/null
+++ b/test/Microsoft.AspNet.Routing.Tests/RouteConstraintsTests.cs
@@ -0,0 +1,97 @@
+// 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.
+
+#if NET45
+
+using System;
+using System.Collections.Generic;
+using System.Linq.Expressions;
+using Microsoft.AspNet.Http;
+using Microsoft.AspNet.Routing.Constraints;
+using Moq;
+using Xunit;
+
+namespace Microsoft.AspNet.Routing.Tests
+{
+ public class RouteConstraintsTests
+ {
+ [Theory]
+ [InlineData(42, true)]
+ [InlineData("42", true)]
+ [InlineData(3.14, false)]
+ [InlineData("43.567", false)]
+ [InlineData("42a", false)]
+ public void IntRouteConstraint_Match_AppliesConstraint(object parameterValue, bool expected)
+ {
+ // Arrange
+ var constraint = new IntRouteConstraint();
+
+ // Act
+ var actual = TestValue(constraint, parameterValue);
+
+ // Assert
+ Assert.Equal(expected, actual);
+ }
+
+ [Theory]
+ [InlineData(true, true, true)]
+ [InlineData(true, false, false)]
+ [InlineData(false, true, false)]
+ [InlineData(false, false, false)]
+ public void CompoundRouteConstraint_Match_CallsMatchOnInnerConstraints(bool inner1Result,
+ bool inner2Result,
+ bool expected)
+ {
+ // Arrange
+ var inner1 = MockConstraintWithResult(inner1Result);
+ var inner2 = MockConstraintWithResult(inner2Result);
+
+ // Act
+ var constraint = new CompositeRouteConstraint(new[] { inner1.Object, inner2.Object });
+ var actual = TestValue(constraint, null);
+
+ // Assert
+ Assert.Equal(expected, actual);
+ }
+
+ static Expression> ConstraintMatchMethodExpression =
+ c => c.Match(It.IsAny(),
+ It.IsAny(),
+ It.IsAny(),
+ It.IsAny>(),
+ It.IsAny());
+
+ private static Mock MockConstraintWithResult(bool result)
+ {
+ var mock = new Mock();
+ mock.Setup(ConstraintMatchMethodExpression)
+ .Returns(result)
+ .Verifiable();
+ return mock;
+ }
+
+ private static void AssertMatchWasCalled(Mock mock, Times times)
+ {
+ mock.Verify(ConstraintMatchMethodExpression, times);
+ }
+
+ private static bool TestValue(IRouteConstraint constraint, object value, Action routeConfig = null)
+ {
+ var context = new Mock();
+
+ IRouter route = new RouteCollection();
+
+ if (routeConfig != null)
+ {
+ routeConfig(route);
+ }
+
+ var parameterName = "fake";
+ var values = new Dictionary() { { parameterName, value } };
+ var routeDirection = RouteDirection.IncomingRequest;
+ return constraint.Match(context.Object, route, parameterName, values, routeDirection);
+ }
+ }
+}
+
+#endif
\ No newline at end of file
diff --git a/test/Microsoft.AspNet.Routing.Tests/Template/TemplateRouteTests.cs b/test/Microsoft.AspNet.Routing.Tests/Template/TemplateRouteTests.cs
index 336f714425..70efab66f1 100644
--- a/test/Microsoft.AspNet.Routing.Tests/Template/TemplateRouteTests.cs
+++ b/test/Microsoft.AspNet.Routing.Tests/Template/TemplateRouteTests.cs
@@ -4,6 +4,7 @@
#if NET45
using System;
using System.Collections.Generic;
+using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Routing.Constraints;
@@ -425,6 +426,49 @@ namespace Microsoft.AspNet.Routing.Template.Tests
Assert.Equal(mockConstraint, constraints["action"]);
}
+ [Fact]
+ public void RegisteringRouteWithOneInlineConstraintAndOneUsingConstraintArgument()
+ {
+ // Arrange
+ var collection = new RouteCollection();
+ collection.DefaultHandler = new Mock().Object;
+ collection.InlineConstraintResolver = new DefaultInlineConstraintResolver();
+
+ collection.MapRoute("mockName",
+ "{controller}/{action}/{id:int}",
+ defaults: null,
+ constraints: new { id = "1*" });
+
+ var constraints = ((TemplateRoute)collection[0]).Constraints;
+
+ // Assert
+ Assert.Equal(1, constraints.Count);
+ var constraint = (CompositeRouteConstraint)constraints["id"];
+ Assert.IsType(constraint);
+ Assert.IsType(constraint.Constraints.ElementAt(0));
+ Assert.IsType(constraint.Constraints.ElementAt(1));
+ }
+
+ [Fact]
+ public void RegisteringRoute_WithOneInlineConstraint_AddsItToConstraintCollection()
+ {
+ // Arrange
+ var collection = new RouteCollection();
+ collection.DefaultHandler = new Mock().Object;
+ collection.InlineConstraintResolver = new DefaultInlineConstraintResolver();
+
+ collection.MapRoute("mockName",
+ "{controller}/{action}/{id:int}",
+ defaults: null,
+ constraints: null);
+
+ var constraints = ((TemplateRoute)collection[0]).Constraints;
+
+ // Assert
+ Assert.Equal(1, constraints.Count);
+ Assert.IsType(constraints["id"]);
+ }
+
[Fact]
public void RegisteringRouteWithRouteName_WithNullDefaults_AddsTheRoute()
{