public void Create_CreatesParameterPolicy_FromRoutePattern_Constraint()
        {
            // Arrange
            var factory = GetParameterPolicyFactory();

            var parameter = RoutePatternFactory.ParameterPart(
                "id",
                @default: null,
                parameterKind: RoutePatternParameterKind.Standard,
                parameterPolicies: new[] { RoutePatternFactory.ParameterPolicy(new IntRouteConstraint()), });

            // Act
            var parameterPolicy = factory.Create(parameter, parameter.ParameterPolicies[0]);

            // Assert
            Assert.IsType <IntRouteConstraint>(parameterPolicy);
        }
Пример #2
0
    private static ParameterPolicyParseResults ParseConstraints(
        string text,
        int currentIndex,
        int endIndex)
    {
        var constraints = new ArrayBuilder <RoutePatternParameterPolicyReference>(0);
        var state       = ParseState.Start;
        var startIndex  = currentIndex;

        do
        {
            var currentChar = currentIndex > endIndex ? null : (char?)text[currentIndex];
            switch (state)
            {
            case ParseState.Start:
                switch (currentChar)
                {
                case null:
                    state = ParseState.End;
                    break;

                case ':':
                    state      = ParseState.ParsingName;
                    startIndex = currentIndex + 1;
                    break;

                case '(':
                    state = ParseState.InsideParenthesis;
                    break;

                case '=':
                    state = ParseState.End;
                    currentIndex--;
                    break;
                }
                break;

            case ParseState.InsideParenthesis:
                switch (currentChar)
                {
                case null:
                    state = ParseState.End;
                    var constraintText = text.Substring(startIndex, currentIndex - startIndex);
                    constraints.Add(RoutePatternFactory.ParameterPolicy(constraintText));
                    break;

                case ')':
                    // Only consume a ')' token if
                    // (a) it is the last token
                    // (b) the next character is the start of the new constraint ':'
                    // (c) the next character is the start of the default value.

                    var nextChar = currentIndex + 1 > endIndex ? null : (char?)text[currentIndex + 1];
                    switch (nextChar)
                    {
                    case null:
                        state          = ParseState.End;
                        constraintText = text.Substring(startIndex, currentIndex - startIndex + 1);
                        constraints.Add(RoutePatternFactory.ParameterPolicy(constraintText));
                        break;

                    case ':':
                        state          = ParseState.Start;
                        constraintText = text.Substring(startIndex, currentIndex - startIndex + 1);
                        constraints.Add(RoutePatternFactory.ParameterPolicy(constraintText));
                        startIndex = currentIndex + 1;
                        break;

                    case '=':
                        state          = ParseState.End;
                        constraintText = text.Substring(startIndex, currentIndex - startIndex + 1);
                        constraints.Add(RoutePatternFactory.ParameterPolicy(constraintText));
                        break;
                    }
                    break;

                case ':':
                case '=':
                    // In the original implementation, the Regex would've backtracked if it encountered an
                    // unbalanced opening bracket followed by (not necessarily immediately) a delimiter.
                    // Simply verifying that the parentheses will eventually be closed should suffice to
                    // determine if the terminator needs to be consumed as part of the current constraint
                    // specification.
                    var indexOfClosingParantheses = text.IndexOf(')', currentIndex + 1);
                    if (indexOfClosingParantheses == -1)
                    {
                        constraintText = text.Substring(startIndex, currentIndex - startIndex);
                        constraints.Add(RoutePatternFactory.ParameterPolicy(constraintText));

                        if (currentChar == ':')
                        {
                            state      = ParseState.ParsingName;
                            startIndex = currentIndex + 1;
                        }
                        else
                        {
                            state = ParseState.End;
                            currentIndex--;
                        }
                    }
                    else
                    {
                        currentIndex = indexOfClosingParantheses;
                    }

                    break;
                }
                break;

            case ParseState.ParsingName:
                switch (currentChar)
                {
                case null:
                    state = ParseState.End;
                    var constraintText = text.Substring(startIndex, currentIndex - startIndex);
                    if (constraintText.Length > 0)
                    {
                        constraints.Add(RoutePatternFactory.ParameterPolicy(constraintText));
                    }
                    break;

                case ':':
                    constraintText = text.Substring(startIndex, currentIndex - startIndex);
                    if (constraintText.Length > 0)
                    {
                        constraints.Add(RoutePatternFactory.ParameterPolicy(constraintText));
                    }
                    startIndex = currentIndex + 1;
                    break;

                case '(':
                    state = ParseState.InsideParenthesis;
                    break;

                case '=':
                    state          = ParseState.End;
                    constraintText = text.Substring(startIndex, currentIndex - startIndex);
                    if (constraintText.Length > 0)
                    {
                        constraints.Add(RoutePatternFactory.ParameterPolicy(constraintText));
                    }
                    currentIndex--;
                    break;
                }
                break;
            }

            currentIndex++;
        } while (state != ParseState.End);

        return(new ParameterPolicyParseResults(currentIndex, constraints.ToArray()));
    }