From 70402c8f2ccf28cf0d317ae34016af32b1572e94 Mon Sep 17 00:00:00 2001 From: harshgMSFT Date: Mon, 11 Aug 2014 18:57:16 -0700 Subject: [PATCH] Adding RegexInlineRouteConstraint --- .../Constraints/RegexInlineRouteConstraint.cs | 20 ++++ .../Microsoft.AspNet.Routing.kproj | 1 + src/Microsoft.AspNet.Routing/RouteOptions.cs | 1 + .../RegexInlineRouteConstraintTests.cs | 91 +++++++++++++++++++ ...tTests.cs => RegexRouteConstraintTests.cs} | 2 +- .../DefaultInlineConstraintResolverTest.cs | 11 +++ .../Microsoft.AspNet.Routing.Tests.kproj | 1 + 7 files changed, 126 insertions(+), 1 deletion(-) create mode 100644 src/Microsoft.AspNet.Routing/Constraints/RegexInlineRouteConstraint.cs create mode 100644 test/Microsoft.AspNet.Routing.Tests/Constraints/RegexInlineRouteConstraintTests.cs rename test/Microsoft.AspNet.Routing.Tests/Constraints/{RegexConstraintTests.cs => RegexRouteConstraintTests.cs} (98%) diff --git a/src/Microsoft.AspNet.Routing/Constraints/RegexInlineRouteConstraint.cs b/src/Microsoft.AspNet.Routing/Constraints/RegexInlineRouteConstraint.cs new file mode 100644 index 0000000000..be035af694 --- /dev/null +++ b/src/Microsoft.AspNet.Routing/Constraints/RegexInlineRouteConstraint.cs @@ -0,0 +1,20 @@ +// 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. + +namespace Microsoft.AspNet.Routing.Constraints +{ + /// + /// Represents a regex constraint which can be used as an inlineConstraint. + /// + public class RegexInlineRouteConstraint : RegexRouteConstraint + { + /// + /// Initializes a new instance of the class. + /// + /// The regular expression pattern to match. + public RegexInlineRouteConstraint([NotNull] string regexPattern) + : base(regexPattern) + { + } + } +} diff --git a/src/Microsoft.AspNet.Routing/Microsoft.AspNet.Routing.kproj b/src/Microsoft.AspNet.Routing/Microsoft.AspNet.Routing.kproj index b3983b08bb..ce9c337704 100644 --- a/src/Microsoft.AspNet.Routing/Microsoft.AspNet.Routing.kproj +++ b/src/Microsoft.AspNet.Routing/Microsoft.AspNet.Routing.kproj @@ -16,5 +16,6 @@ 2.0 + \ No newline at end of file diff --git a/src/Microsoft.AspNet.Routing/RouteOptions.cs b/src/Microsoft.AspNet.Routing/RouteOptions.cs index 227f4d74aa..96c78c992f 100644 --- a/src/Microsoft.AspNet.Routing/RouteOptions.cs +++ b/src/Microsoft.AspNet.Routing/RouteOptions.cs @@ -56,6 +56,7 @@ namespace Microsoft.AspNet.Routing // Regex-based constraints { "alpha", typeof(AlphaRouteConstraint) }, + { "regex", typeof(RegexInlineRouteConstraint) }, }; } } diff --git a/test/Microsoft.AspNet.Routing.Tests/Constraints/RegexInlineRouteConstraintTests.cs b/test/Microsoft.AspNet.Routing.Tests/Constraints/RegexInlineRouteConstraintTests.cs new file mode 100644 index 0000000000..39c36c4faf --- /dev/null +++ b/test/Microsoft.AspNet.Routing.Tests/Constraints/RegexInlineRouteConstraintTests.cs @@ -0,0 +1,91 @@ +// 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.Globalization; +using System.Threading; +using Microsoft.AspNet.Http; +using Microsoft.AspNet.Routing.Constraints; +using Moq; +using Xunit; + +namespace Microsoft.AspNet.Routing.Tests +{ + public class RegexInlineRouteConstraintTests + { + [Theory] + [InlineData("abc", "abc", true)] // simple match + [InlineData("Abc", "abc", true)] // case insensitive match + [InlineData("Abc ", "abc", true)] // Extra space on input match (because we don't add ^({0})$ + [InlineData("Abcd", "abc", true)] // Extra char + [InlineData("^Abcd", "abc", true)] // Extra special char + [InlineData("Abc", " abc", false)] // Missing char + public void RegexInlineConstraintBuildRegexVerbatimFromInput(string routeValue, + string constraintValue, + bool shouldMatch) + { + // Arrange + var constraint = new RegexInlineRouteConstraint(constraintValue); + var values = new RouteValueDictionary(new {controller = routeValue}); + + // Assert + Assert.Equal(shouldMatch, EasyMatch(constraint, "controller", values)); + } + + [Fact] + public void RegexInlineConstraint_FailsIfKeyIsNotFoundInRouteValues() + { + // Arrange + var constraint = new RegexInlineRouteConstraint("^abc$"); + var values = new RouteValueDictionary(new { action = "abc" }); + + // Assert + Assert.False(EasyMatch(constraint, "controller", values)); + } + + [Fact] + public void RegexInlineConstraint_IsCultureInsensitive() + { + // Arrange + var constraint = new RegexInlineRouteConstraint("^([a-z]+)$"); + var values = new RouteValueDictionary(new { controller = "\u0130" }); // Turkish upper-case dotted I + + var currentThread = Thread.CurrentThread; + var backupCulture = currentThread.CurrentCulture; + + bool matchInTurkish; + bool matchInUsEnglish; + + // Act + try + { + currentThread.CurrentCulture = new CultureInfo("tr-TR"); // Turkish culture + matchInTurkish = EasyMatch(constraint, "controller", values); + + currentThread.CurrentCulture = new CultureInfo("en-US"); + matchInUsEnglish = EasyMatch(constraint, "controller", values); + } + finally + { + currentThread.CurrentCulture = backupCulture; + } + + // Assert + Assert.False(matchInUsEnglish); // this just verifies the test + Assert.False(matchInTurkish); + } + + private static bool EasyMatch(IRouteConstraint constraint, + string routeKey, + RouteValueDictionary values) + { + return constraint.Match(httpContext: new Mock().Object, + route: new Mock().Object, + routeKey: routeKey, + values: values, + routeDirection: RouteDirection.IncomingRequest); + } + } +} +#endif \ No newline at end of file diff --git a/test/Microsoft.AspNet.Routing.Tests/Constraints/RegexConstraintTests.cs b/test/Microsoft.AspNet.Routing.Tests/Constraints/RegexRouteConstraintTests.cs similarity index 98% rename from test/Microsoft.AspNet.Routing.Tests/Constraints/RegexConstraintTests.cs rename to test/Microsoft.AspNet.Routing.Tests/Constraints/RegexRouteConstraintTests.cs index 0c67824e03..7aa8e91377 100644 --- a/test/Microsoft.AspNet.Routing.Tests/Constraints/RegexConstraintTests.cs +++ b/test/Microsoft.AspNet.Routing.Tests/Constraints/RegexRouteConstraintTests.cs @@ -13,7 +13,7 @@ using Xunit; namespace Microsoft.AspNet.Routing.Tests { - public class RegexConstraintTests + public class RegexRouteConstraintTests { [Theory] [InlineData("abc", "abc", true)] // simple match diff --git a/test/Microsoft.AspNet.Routing.Tests/DefaultInlineConstraintResolverTest.cs b/test/Microsoft.AspNet.Routing.Tests/DefaultInlineConstraintResolverTest.cs index 07195cbd99..b9908954e1 100644 --- a/test/Microsoft.AspNet.Routing.Tests/DefaultInlineConstraintResolverTest.cs +++ b/test/Microsoft.AspNet.Routing.Tests/DefaultInlineConstraintResolverTest.cs @@ -42,6 +42,7 @@ namespace Microsoft.AspNet.Routing.Tests " with the following number of parameters: 1.", ex.Message); } + [Fact] public void ResolveConstraint_AlphaConstraint() { @@ -52,6 +53,16 @@ namespace Microsoft.AspNet.Routing.Tests Assert.IsType(constraint); } + [Fact] + public void ResolveConstraint_RegexInlineConstraint_WithAComma_PassesAsASingleArgument() + { + // Arrange & Act + var constraint = _constraintResolver.ResolveConstraint("regex(ab,1)"); + + // Assert + Assert.IsType(constraint); + } + [Fact] public void ResolveConstraint_BoolConstraint() { 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 4514503b19..323a4b4b09 100644 --- a/test/Microsoft.AspNet.Routing.Tests/Microsoft.AspNet.Routing.Tests.kproj +++ b/test/Microsoft.AspNet.Routing.Tests/Microsoft.AspNet.Routing.Tests.kproj @@ -16,5 +16,6 @@ 2.0 + \ No newline at end of file