public void Pattern_CreatesConstraintFromString() { // Arrange var template = "{a}/{b}/{c}"; var defaults = new { }; var constraints = new { d = "foo", }; var original = RoutePatternFactory.Parse(template); // Act var actual = RoutePatternFactory.Pattern( original.RawText, defaults, constraints, original.PathSegments); // Assert Assert.Collection( actual.Constraints.OrderBy(kvp => kvp.Key), kvp => { Assert.Equal("d", kvp.Key); var regex = Assert.IsType <RegexRouteConstraint>(Assert.Single(kvp.Value).Constraint); Assert.Equal("^(foo)$", regex.Constraint.ToString()); }); }
public void Pattern_ExtraConstraints() { // Arrange var template = "{a}/{b}/{c}"; var defaults = new { }; var constraints = new { d = new RegexRouteConstraint("foo"), e = new RegexRouteConstraint("bar") }; var original = RoutePatternFactory.Parse(template); // Act var actual = RoutePatternFactory.Pattern( original.RawText, defaults, constraints, original.PathSegments); // Assert Assert.Collection( actual.Constraints.OrderBy(kvp => kvp.Key), kvp => { Assert.Equal("d", kvp.Key); Assert.Collection( kvp.Value, c => Assert.IsType <RegexRouteConstraint>(c.Constraint)); }, kvp => { Assert.Equal("e", kvp.Key); Assert.Collection( kvp.Value, c => Assert.IsType <RegexRouteConstraint>(c.Constraint)); }); }
public void Pattern_ExtraConstraints_MatchProcessor() { // Arrange var template = "{a}/{b}/{c}"; var defaults = new { }; var constraints = new { d = Mock.Of <MatchProcessor>(), e = Mock.Of <MatchProcessor>(), }; var original = RoutePatternFactory.Parse(template); // Act var actual = RoutePatternFactory.Pattern( original.RawText, defaults, constraints, original.PathSegments); // Assert Assert.Collection( actual.Constraints.OrderBy(kvp => kvp.Key), kvp => { Assert.Equal("d", kvp.Key); Assert.Collection( kvp.Value, c => Assert.NotNull(c.MatchProcessor)); }, kvp => { Assert.Equal("e", kvp.Key); Assert.Collection( kvp.Value, c => Assert.NotNull(c.MatchProcessor)); }); }
public void Pattern_RawTextAndArrayOfSegments_ShouldMakeCopyOfArrayOfSegments() { // Arrange var rawText = "raw"; var literalPartA = RoutePatternFactory.LiteralPart("A"); var paramPartB = RoutePatternFactory.ParameterPart("B"); var paramPartC = RoutePatternFactory.ParameterPart("C"); var paramPartD = RoutePatternFactory.ParameterPart("D"); var segments = new[] { RoutePatternFactory.Segment(literalPartA, paramPartB), RoutePatternFactory.Segment(paramPartC, literalPartA), RoutePatternFactory.Segment(paramPartD), RoutePatternFactory.Segment(literalPartA) }; // Act var actual = RoutePatternFactory.Pattern(rawText, segments); segments[1] = RoutePatternFactory.Segment(RoutePatternFactory.ParameterPart("E")); Array.Resize(ref segments, 2); // Assert Assert.Equal(3, actual.Parameters.Count); Assert.Same(paramPartB, actual.Parameters[0]); Assert.Same(paramPartC, actual.Parameters[1]); Assert.Same(paramPartD, actual.Parameters[2]); }
public void Pattern_MergesDefaultValues() { // Arrange var template = "{a}/{b}/{c=19}"; var defaults = new { a = "15", b = 17 }; var constraints = new { }; var original = RoutePatternFactory.Parse(template); // Act var actual = RoutePatternFactory.Pattern( original.RawText, defaults, constraints, original.PathSegments); // Assert Assert.Equal("15", actual.GetParameter("a").Default); Assert.Equal(17, actual.GetParameter("b").Default); Assert.Equal("19", actual.GetParameter("c").Default); Assert.Collection( actual.Defaults.OrderBy(kvp => kvp.Key), kvp => { Assert.Equal("a", kvp.Key); Assert.Equal("15", kvp.Value); }, kvp => { Assert.Equal("b", kvp.Key); Assert.Equal(17, kvp.Value); }, kvp => { Assert.Equal("c", kvp.Key); Assert.Equal("19", kvp.Value); }); }
public void Pattern_ExtraConstraints_MultipleConstraintsForKey() { // Arrange var template = "{a}/{b}/{c}"; var defaults = new { }; var constraints = new { d = new object[] { new RegexRouteConstraint("foo"), new RegexRouteConstraint("bar"), "baz" } }; var original = RoutePatternFactory.Parse(template); // Act var actual = RoutePatternFactory.Pattern( original.RawText, defaults, constraints, original.PathSegments); // Assert Assert.Collection( actual.ParameterPolicies.OrderBy(kvp => kvp.Key), kvp => { Assert.Equal("d", kvp.Key); Assert.Collection( kvp.Value, c => Assert.Equal("foo", Assert.IsType <RegexRouteConstraint>(c.ParameterPolicy).Constraint.ToString()), c => Assert.Equal("bar", Assert.IsType <RegexRouteConstraint>(c.ParameterPolicy).Constraint.ToString()), c => Assert.Equal("^(baz)$", Assert.IsType <RegexRouteConstraint>(c.ParameterPolicy).Constraint.ToString())); }); }
public static RoutePattern Parse(string pattern) { if (pattern == null) { throw new ArgumentNullException(nameof(pattern)); } var trimmedPattern = TrimPrefix(pattern); var context = new Context(trimmedPattern); var segments = new List <RoutePatternPathSegment>(); while (context.MoveNext()) { var i = context.Index; if (context.Current == Separator) { // If we get here is means that there's a consecutive '/' character. // Templates don't start with a '/' and parsing a segment consumes the separator. throw new RoutePatternException(pattern, Resources.TemplateRoute_CannotHaveConsecutiveSeparators); } if (!ParseSegment(context, segments)) { throw new RoutePatternException(pattern, context.Error); } // A successful parse should always result in us being at the end or at a separator. Debug.Assert(context.AtEnd() || context.Current == Separator); if (context.Index <= i) { // This shouldn't happen, but we want to crash if it does. var message = "Infinite loop detected in the parser. Please open an issue."; throw new InvalidProgramException(message); } } if (IsAllValid(context, segments)) { return(RoutePatternFactory.Pattern(pattern, segments)); } else { throw new RoutePatternException(pattern, context.Error); } }
public void Pattern_MergesConstraints() { // Arrange var template = "{a:int}/{b}/{c}"; var defaults = new { }; var constraints = new { a = new RegexRouteConstraint("foo"), b = new RegexRouteConstraint("bar") }; var original = RoutePatternFactory.Parse(template); // Act var actual = RoutePatternFactory.Pattern( original.RawText, defaults, constraints, original.PathSegments); // Assert Assert.Collection( actual.GetParameter("a").Constraints, c => Assert.IsType <RegexRouteConstraint>(c.Constraint), c => Assert.Equal("int", c.Content)); Assert.Collection( actual.GetParameter("b").Constraints, c => Assert.IsType <RegexRouteConstraint>(c.Constraint)); Assert.Collection( actual.Constraints.OrderBy(kvp => kvp.Key), kvp => { Assert.Equal("a", kvp.Key); Assert.Collection( kvp.Value, c => Assert.IsType <RegexRouteConstraint>(c.Constraint), c => Assert.Equal("int", c.Content)); }, kvp => { Assert.Equal("b", kvp.Key); Assert.Collection( kvp.Value, c => Assert.IsType <RegexRouteConstraint>(c.Constraint)); }); }
public void Pattern_ExtraConstraints_NestedArray_Throws() { // Arrange var template = "{a}/{b}/{c:int}"; var defaults = new { }; var constraints = new { c = new object[] { new object[0] } }; var original = RoutePatternFactory.Parse(template); // Act & Assert Assert.Throws <InvalidOperationException>(() => { RoutePatternFactory.Pattern( original.RawText, defaults, constraints, original.PathSegments); }); }
public void Pattern_OptionalParameterDefaultValue_Throws() { // Arrange var template = "{a}/{b}/{c?}"; var defaults = new { c = "15", }; var constraints = new { }; var original = RoutePatternFactory.Parse(template); // Act var ex = Assert.Throws <InvalidOperationException>(() => RoutePatternFactory.Pattern( original.RawText, defaults, constraints, original.PathSegments)); // Assert Assert.Equal( "An optional parameter cannot have default value.", ex.Message); }
public void Pattern_InvalidConstraintTypeThrows() { // Arrange var template = "{a}/{b}/{c}"; var defaults = new { }; var constraints = new { d = 17, }; var original = RoutePatternFactory.Parse(template); // Act var ex = Assert.Throws <InvalidOperationException>(() => RoutePatternFactory.Pattern( original.RawText, defaults, constraints, original.PathSegments)); // Assert Assert.Equal( $"Invalid constraint '17'. A constraint must be of type 'string', '{typeof(IRouteConstraint)}', or '{typeof(MatchProcessor)}'.", ex.Message); }
public void Pattern_SameDuplicateDefaultValue() { // Arrange var template = "{a=13}/{b}/{c}"; var defaults = new { a = "13", }; var constraints = new { }; var original = RoutePatternFactory.Parse(template); // Act var actual = RoutePatternFactory.Pattern( original.RawText, defaults, constraints, original.PathSegments); // Assert Assert.Collection( actual.Defaults, kvp => { Assert.Equal("a", kvp.Key); Assert.Equal("13", kvp.Value); }); }
public void Pattern_ExtraDefaultValues() { // Arrange var template = "{a}/{b}/{c}"; var defaults = new { d = "15", e = 17 }; var constraints = new { }; var original = RoutePatternFactory.Parse(template); // Act var actual = RoutePatternFactory.Pattern( original.RawText, defaults, constraints, original.PathSegments); // Assert Assert.Collection( actual.Defaults.OrderBy(kvp => kvp.Key), kvp => { Assert.Equal("d", kvp.Key); Assert.Equal("15", kvp.Value); }, kvp => { Assert.Equal("e", kvp.Key); Assert.Equal(17, kvp.Value); }); }
public void Pattern_RawTextAndDefaultsAndParameterPoliciesAndArrayOfSegments_ShouldMakeCopyOfArrayOfSegments() { // Arrange var rawText = "raw"; object defaults = new { B = 12, C = 4 }; object parameterPolicies = null; var literalPartA = RoutePatternFactory.LiteralPart("A"); var paramPartB = RoutePatternFactory.ParameterPart("B"); var paramPartC = RoutePatternFactory.ParameterPart("C"); var paramPartD = RoutePatternFactory.ParameterPart("D"); var segments = new[] { RoutePatternFactory.Segment(literalPartA, paramPartB), RoutePatternFactory.Segment(paramPartC, literalPartA), RoutePatternFactory.Segment(paramPartD), RoutePatternFactory.Segment(literalPartA) }; // Act var actual = RoutePatternFactory.Pattern(rawText, defaults, parameterPolicies, segments); segments[1] = RoutePatternFactory.Segment(RoutePatternFactory.ParameterPart("E")); Array.Resize(ref segments, 2); // Assert Assert.Equal(3, actual.Parameters.Count); Assert.Equal(paramPartB.Name, actual.Parameters[0].Name); Assert.Equal(12, actual.Parameters[0].Default); Assert.Null(paramPartB.Default); Assert.NotSame(paramPartB, actual.Parameters[0]); Assert.Equal(paramPartC.Name, actual.Parameters[1].Name); Assert.Equal(4, actual.Parameters[1].Default); Assert.NotSame(paramPartC, actual.Parameters[1]); Assert.Null(paramPartC.Default); Assert.Equal(paramPartD.Name, actual.Parameters[2].Name); Assert.Null(actual.Parameters[2].Default); Assert.Same(paramPartD, actual.Parameters[2]); Assert.Null(paramPartD.Default); }
public void Pattern_DuplicateDefaultValue_Throws() { // Arrange var template = "{a=13}/{b}/{c}"; var defaults = new { a = "15", }; var constraints = new { }; var original = RoutePatternFactory.Parse(template); // Act var ex = Assert.Throws <InvalidOperationException>(() => RoutePatternFactory.Pattern( original.RawText, defaults, constraints, original.PathSegments)); // Assert Assert.Equal( "The route parameter 'a' has both an inline default value and an explicit default " + "value specified. A route parameter cannot contain an inline default value when a " + "default value is specified explicitly. Consider removing one of them.", ex.Message); }