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);
            }
Beispiel #9
0
        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);
        }
Beispiel #10
0
        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);
            }
        }