public void Parse_OptionalParameter() { // Arrange var template = "{p?}"; var builder = RoutePatternBuilder.Create(template); builder.AddPathSegmentFromText("{p?}", RoutePatternPart.CreateParameterFromText("{p?}", "p", null, RoutePatternParameterKind.Optional)); var expected = builder.Build(); // Act var actual = RoutePatternParser.Parse(template); // Assert Assert.Equal <RoutePattern>(expected, actual, new RoutePatternEqualityComparer()); }
public void Parse_SingleLiteral() { // Arrange var template = "cool"; var builder = RoutePatternBuilder.Create(template); builder.AddPathSegmentFromText("cool", RoutePatternPart.CreateLiteralFromText("cool", "cool")); var expected = builder.Build(); // Act var actual = RoutePatternParser.Parse(template); // Assert Assert.Equal <RoutePattern>(expected, actual, new RoutePatternEqualityComparer()); }
public void Parse_MultipleParameters() { // Arrange var template = "{p1}/{p2}/{*p3}"; var builder = RoutePatternBuilder.Create(template); builder.AddPathSegmentFromText("{p1}", RoutePatternPart.CreateParameterFromText("{p1}", "p1")); builder.AddPathSegmentFromText("{p2}", RoutePatternPart.CreateParameterFromText("{p2}", "p2")); builder.AddPathSegmentFromText("{*p3}", RoutePatternPart.CreateParameterFromText("{*p3}", "p3", null, RoutePatternParameterKind.CatchAll)); var expected = builder.Build(); // Act var actual = RoutePatternParser.Parse(template); // Assert Assert.Equal <RoutePattern>(expected, actual, new RoutePatternEqualityComparer()); }
public void Parse_ComplexSegment_OptionalParameterFollowingPeriod_PeriodAfterSlash() { // Arrange var template = "{p2}/.{p3?}"; var builder = RoutePatternBuilder.Create(template); builder.AddPathSegmentFromText("{p2}", RoutePatternPart.CreateParameterFromText("{p2}", "p2")); builder.AddPathSegmentFromText(".{p3?}", RoutePatternPart.CreateSeparatorFromText(".", "."), RoutePatternPart.CreateParameterFromText("{p3?}", "p3", null, RoutePatternParameterKind.Optional)); var expected = builder.Build(); // Act var actual = RoutePatternParser.Parse(template); // Assert Assert.Equal <RoutePattern>(expected, actual, new RoutePatternEqualityComparer()); }
public void Parse_ComplexSegment_ParametersFollowingPeriod() { // Arrange var template = "{p1}.{p2}"; var builder = RoutePatternBuilder.Create(template); builder.AddPathSegmentFromText( "{p1}.{p2}", RoutePatternPart.CreateParameterFromText("{p1}", "p1"), RoutePatternPart.CreateLiteralFromText(".", "."), RoutePatternPart.CreateParameterFromText("{p2}", "p2")); var expected = builder.Build(); // Act var actual = RoutePatternParser.Parse(template); // Assert Assert.Equal <RoutePattern>(expected, actual, new RoutePatternEqualityComparer()); }
public void Parse_ComplexSegment_LPL() { // Arrange var template = "cool-{p1}-awesome"; var builder = RoutePatternBuilder.Create(template); builder.AddPathSegmentFromText( template, RoutePatternPart.CreateLiteralFromText("cool-", "cool-"), RoutePatternPart.CreateParameterFromText("{p1}", "p1"), RoutePatternPart.CreateLiteralFromText("-awesome", "-awesome")); var expected = builder.Build(); // Act var actual = RoutePatternParser.Parse(template); // Assert Assert.Equal <RoutePattern>(expected, actual, new RoutePatternEqualityComparer()); }
[InlineData(@"{p1:regex(([{{(])\w+)}", @"regex(([{(])\w+)")] // Not balanced { public void Parse_RegularExpressions(string template, string constraint) { // Arrange var builder = RoutePatternBuilder.Create(template); builder.AddPathSegmentFromText( template, RoutePatternPart.CreateParameterFromText( template, "p1", null, RoutePatternParameterKind.Standard, ConstraintReference.CreateFromText(constraint, constraint))); var expected = builder.Build(); // Act var actual = RoutePatternParser.Parse(template); // Assert Assert.Equal <RoutePattern>(expected, actual, new RoutePatternEqualityComparer()); }
private bool Equals(RoutePatternPart x, RoutePatternPart y) { if (x.GetType() != y.GetType()) { return(false); } if (x.IsLiteral && y.IsLiteral) { return(Equals((RoutePatternLiteral)x, (RoutePatternLiteral)y)); } else if (x.IsParameter && y.IsParameter) { return(Equals((RoutePatternParameter)x, (RoutePatternParameter)y)); } else if (x.IsSeparator && y.IsSeparator) { return(Equals((RoutePatternSeparator)x, (RoutePatternSeparator)y)); } Debug.Fail("This should not be reachable. Do you need to update the comparison logic?"); return(false); }
private static bool IsSegmentValid(TemplateParserContext context, List <RoutePatternPart> parts) { // If a segment has multiple parts, then it can't contain a catch all. for (var i = 0; i < parts.Count; i++) { var part = parts[i]; if (part.IsParameter && ((RoutePatternParameter)part).IsCatchAll && parts.Count > 1) { context.Error = Resources.TemplateRoute_CannotHaveCatchAllInMultiSegment; return(false); } } // if a segment has multiple parts, then only the last one parameter can be optional // if it is following a optional seperator. for (var i = 0; i < parts.Count; i++) { var part = parts[i]; if (part.IsParameter && ((RoutePatternParameter)part).IsOptional && parts.Count > 1) { // This optional parameter is the last part in the segment if (i == parts.Count - 1) { var previousPart = parts[i - 1]; if (!previousPart.IsLiteral && !previousPart.IsSeparator) { // The optional parameter is preceded by something that is not a literal or separator // Example of error message: // "In the segment '{RouteValue}{param?}', the optional parameter 'param' is preceded // by an invalid segment '{RouteValue}'. Only a period (.) can precede an optional parameter. context.Error = string.Format( Resources.TemplateRoute_OptionalParameterCanbBePrecededByPeriod, RoutePatternPathSegment.DebuggerToString(parts), ((RoutePatternParameter)part).Name, parts[i - 1].DebuggerToString()); return(false); } else if (previousPart is RoutePatternLiteral literal && literal.Content != PeriodString) { // The optional parameter is preceded by a literal other than period. // Example of error message: // "In the segment '{RouteValue}-{param?}', the optional parameter 'param' is preceded // by an invalid segment '-'. Only a period (.) can precede an optional parameter. context.Error = string.Format( Resources.TemplateRoute_OptionalParameterCanbBePrecededByPeriod, RoutePatternPathSegment.DebuggerToString(parts), ((RoutePatternParameter)part).Name, parts[i - 1].DebuggerToString()); return(false); } parts[i - 1] = RoutePatternPart.CreateSeparatorFromText(previousPart.RawText, ((RoutePatternLiteral)previousPart).Content); } else { // This optional parameter is not the last one in the segment // Example: // An optional parameter must be at the end of the segment. In the segment '{RouteValue?})', // optional parameter 'RouteValue' is followed by ')' context.Error = string.Format( Resources.TemplateRoute_OptionalParameterHasTobeTheLast, RoutePatternPathSegment.DebuggerToString(parts), ((RoutePatternParameter)part).Name, parts[i + 1].DebuggerToString()); return(false); } } } // A segment cannot contain two consecutive parameters var isLastSegmentParameter = false; for (var i = 0; i < parts.Count; i++) { var part = parts[i]; if (part.IsParameter && isLastSegmentParameter) { context.Error = Resources.TemplateRoute_CannotHaveConsecutiveParameters; return(false); } isLastSegmentParameter = part.IsParameter; } return(true); }
private static bool ParseLiteral(TemplateParserContext context, List <RoutePatternPart> parts) { context.Mark(); while (true) { if (context.Current == Separator) { // End of the segment break; } else if (context.Current == OpenBrace) { if (!context.MoveNext()) { // This is a dangling open-brace, which is not allowed context.Error = Resources.TemplateRoute_MismatchedParameter; return(false); } if (context.Current == OpenBrace) { // This is an 'escaped' brace in a literal, like "{{foo" - keep going. } else { // We've just seen the start of a parameter, so back up. context.Back(); break; } } else if (context.Current == CloseBrace) { if (!context.MoveNext()) { // This is a dangling close-brace, which is not allowed context.Error = Resources.TemplateRoute_MismatchedParameter; return(false); } if (context.Current == CloseBrace) { // This is an 'escaped' brace in a literal, like "{{foo" - keep going. } else { // This is an unbalanced close-brace, which is not allowed context.Error = Resources.TemplateRoute_MismatchedParameter; return(false); } } if (!context.MoveNext()) { break; } } var encoded = context.Capture(); var decoded = encoded.Replace("}}", "}").Replace("{{", "{"); if (IsValidLiteral(context, decoded)) { parts.Add(RoutePatternPart.CreateLiteralFromText(encoded, decoded)); return(true); } else { return(false); } }