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 ParameterPart_ParameterNameAndDefaultAndParameterKindAndEnumerableOfParameterPolicies_ShouldMakeCopyOfParameterPolicies()
    {
        // Arrange (going through hoops to get an enumerable of RoutePatternParameterPolicyReference)
        const string name         = "Id";
        var          defaults     = new { a = "13", };
        var          x            = new InlineConstraint("x");
        var          y            = new InlineConstraint("y");
        var          z            = new InlineConstraint("z");
        var          constraints  = new[] { x, y, z };
        var          templatePart = TemplatePart.CreateParameter("t", false, false, null, constraints);
        var          routePatternParameterPart = (RoutePatternParameterPart)templatePart.ToRoutePatternPart();
        var          policies = routePatternParameterPart.ParameterPolicies.ToList();

        // Act
        var parameterPart = RoutePatternFactory.ParameterPart(name, defaults, RoutePatternParameterKind.Standard, policies);

        policies[0] = null;
        policies.RemoveAt(1);

        // Assert
        Assert.NotNull(parameterPart.ParameterPolicies);
        Assert.Equal(3, parameterPart.ParameterPolicies.Count);
        Assert.NotNull(parameterPart.ParameterPolicies[0]);
        Assert.NotNull(parameterPart.ParameterPolicies[1]);
        Assert.NotNull(parameterPart.ParameterPolicies[2]);
    }
    private static void RemoveParameterDefault(List <RoutePatternPathSegment> segments, List <RoutePatternParameterPart> parameters, RoutePatternParameterPart parameter)
    {
        // We know that a parameter can only appear once, so we only need to rewrite one segment and one parameter.
        for (var i = 0; i < segments.Count; i++)
        {
            var segment = segments[i];
            for (var j = 0; j < segment.Parts.Count; j++)
            {
                if (object.ReferenceEquals(parameter, segment.Parts[j]))
                {
                    // Found it!
                    var updatedParameter = RoutePatternFactory.ParameterPart(parameter.Name, @default: null, parameter.ParameterKind, parameter.ParameterPolicies);

                    var updatedParts = new List <RoutePatternPart>(segment.Parts);
                    updatedParts[j] = updatedParameter;
                    segments[i]     = RoutePatternFactory.Segment(updatedParts);

                    for (var k = 0; k < parameters.Count; k++)
                    {
                        if (ReferenceEquals(parameter, parameters[k]))
                        {
                            parameters[k] = updatedParameter;
                            break;
                        }
                    }

                    return;
                }
            }
        }
    }
Example #4
0
        public void ToRoutePatternPathSegment()
        {
            // Arrange
            var literalPartA    = RoutePatternFactory.LiteralPart("A");
            var paramPartB      = RoutePatternFactory.ParameterPart("B");
            var paramPartC      = RoutePatternFactory.ParameterPart("C");
            var paramPartD      = RoutePatternFactory.ParameterPart("D");
            var separatorPartE  = RoutePatternFactory.SeparatorPart("E");
            var templateSegment = new TemplateSegment(RoutePatternFactory.Segment(paramPartC, literalPartA, separatorPartE, paramPartB));

            // Act
            var routePatternPathSegment = templateSegment.ToRoutePatternPathSegment();

            templateSegment.Parts[1] = new TemplatePart(RoutePatternFactory.ParameterPart("D"));
            templateSegment.Parts.RemoveAt(0);

            // Assert
            Assert.Equal(4, routePatternPathSegment.Parts.Count);
            Assert.IsType <RoutePatternParameterPart>(routePatternPathSegment.Parts[0]);
            Assert.Equal(paramPartC.Name, ((RoutePatternParameterPart)routePatternPathSegment.Parts[0]).Name);
            Assert.IsType <RoutePatternLiteralPart>(routePatternPathSegment.Parts[1]);
            Assert.Equal(literalPartA.Content, ((RoutePatternLiteralPart)routePatternPathSegment.Parts[1]).Content);
            Assert.IsType <RoutePatternSeparatorPart>(routePatternPathSegment.Parts[2]);
            Assert.Equal(separatorPartE.Content, ((RoutePatternSeparatorPart)routePatternPathSegment.Parts[2]).Content);
            Assert.IsType <RoutePatternParameterPart>(routePatternPathSegment.Parts[3]);
            Assert.Equal(paramPartB.Name, ((RoutePatternParameterPart)routePatternPathSegment.Parts[3]).Name);
        }
        public void Create_CreatesParameterPolicy_FromConstraintText_AndRouteConstraint()
        {
            // Arrange
            var factory = GetParameterPolicyFactory();

            // Act
            var parameterPolicy = factory.Create(RoutePatternFactory.ParameterPart("id"), "int");

            // Assert
            Assert.IsType <IntRouteConstraint>(parameterPolicy);
        }
        public void Create_CreatesParameterPolicy_FromConstraintText_AndRouteConstraint_Optional()
        {
            // Arrange
            var factory = GetParameterPolicyFactory();

            // Act
            var parameterPolicy = factory.Create(RoutePatternFactory.ParameterPart("id", @default: null, RoutePatternParameterKind.Optional), "int");

            // Assert
            var optionalConstraint = Assert.IsType <OptionalRouteConstraint>(parameterPolicy);

            Assert.IsType <IntRouteConstraint>(optionalConstraint.InnerConstraint);
        }
        public void Create_CreatesParameterPolicy_FromConstraintText_AndRouteConstraintWithArgument()
        {
            // Arrange
            var factory = GetParameterPolicyFactory();

            // Act
            var parameterPolicy = factory.Create(RoutePatternFactory.ParameterPart("id"), "range(1,20)");

            // Assert
            var constraint = Assert.IsType <RangeRouteConstraint>(parameterPolicy);

            Assert.Equal(1, constraint.Min);
            Assert.Equal(20, constraint.Max);
        }
        public void Create_ThrowsException_IfNoConstraintOrParameterPolicy_FoundInMap()
        {
            // Arrange
            var factory = GetParameterPolicyFactory();

            // Act
            var exception = Assert.Throws <InvalidOperationException>(
                () => factory.Create(RoutePatternFactory.ParameterPart("id", @default: null, RoutePatternParameterKind.Optional), @"notpresent(\d+)"));

            // Assert
            Assert.Equal(
                "The constraint reference 'notpresent' could not be resolved to a type. " +
                $"Register the constraint type with '{typeof(RouteOptions)}.{nameof(RouteOptions.ConstraintMap)}'.",
                exception.Message);
        }
Example #9
0
        public void Create_CreatesMatchProcessor_FromRoutePattern_String_Optional()
        {
            // Arrange
            var factory = GetMatchProcessorFactory();

            var parameter = RoutePatternFactory.ParameterPart(
                "id",
                @default: null,
                parameterKind: RoutePatternParameterKind.Optional,
                constraints: new[] { RoutePatternFactory.Constraint("int"), });

            // Act
            var matchProcessor = factory.Create(parameter, parameter.Constraints[0]);

            // Assert
            Assert.IsType <OptionalMatchProcessor>(matchProcessor);
        }
        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);
        }
Example #11
0
        public void Create_CreatesMatchProcessor_FromRoutePattern_Constraint()
        {
            // Arrange
            var factory = GetMatchProcessorFactory();

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

            // Act
            var matchProcessor = factory.Create(parameter, parameter.Constraints[0]);

            // Assert
            Assert.IsType <IntRouteConstraint>(Assert.IsType <RouteConstraintMatchProcessor>(matchProcessor).Constraint);
        }
        public void Create_CreatesParameterPolicy_FromRoutePattern_String_Optional()
        {
            // Arrange
            var factory = GetParameterPolicyFactory();

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

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

            // Assert
            var optionalConstraint = Assert.IsType <OptionalRouteConstraint>(parameterPolicy);

            Assert.IsType <IntRouteConstraint>(optionalConstraint.InnerConstraint);
        }
        public void Create_CreatesParameterPolicy_FromConstraintText_AndParameterPolicy_Optional()
        {
            // Arrange
            var options = new RouteOptions();

            options.ConstraintMap.Add("customParameterPolicy", typeof(CustomParameterPolicy));

            var services = new ServiceCollection();

            services.AddTransient <CustomParameterPolicy>();

            var factory = GetParameterPolicyFactory(options, services);

            // Act
            var parameterPolicy = factory.Create(RoutePatternFactory.ParameterPart("id", @default: null, RoutePatternParameterKind.Optional), "customParameterPolicy");

            // Assert
            Assert.IsType <CustomParameterPolicy>(parameterPolicy);
        }
        public void Create_CreatesParameterPolicy_FromConstraintText_AndParameterPolicyWithArgumentAndUnresolvedServices_Throw()
        {
            // Arrange
            var options = new RouteOptions();

            options.ConstraintMap.Add("customConstraintPolicy", typeof(CustomParameterPolicyWithArguments));

            var services = new ServiceCollection();

            var factory = GetParameterPolicyFactory(options, services);

            // Act
            var exception = Assert.Throws <RouteCreationException>(
                () => factory.Create(RoutePatternFactory.ParameterPart("id"), "customConstraintPolicy(20)"));

            // Assert
            var inner = Assert.IsType <InvalidOperationException>(exception.InnerException);

            Assert.Equal($"No service for type '{typeof(ITestService).FullName}' has been registered.", inner.Message);
        }
        public void Create_ThrowsException_OnInvalidType()
        {
            // Arrange
            var options = new RouteOptions();

            options.ConstraintMap.Add("bad", typeof(string));

            var services = new ServiceCollection();

            var factory = GetParameterPolicyFactory(options, services);

            // Act
            var exception = Assert.Throws <RouteCreationException>(
                () => factory.Create(RoutePatternFactory.ParameterPart("id"), @"bad"));

            // Assert
            Assert.Equal(
                $"The constraint type '{typeof(string)}' which is mapped to constraint key 'bad' must implement the '{nameof(IParameterPolicy)}' interface.",
                exception.Message);
        }
    public void Segment_ArrayOfParts()
    {
        // Arrange
        var paramPartB = RoutePatternFactory.ParameterPart("B");
        var paramPartC = RoutePatternFactory.ParameterPart("C");
        var paramPartD = RoutePatternFactory.ParameterPart("D");
        var parts      = new[] { paramPartB, paramPartC, paramPartD };

        // Act
        var actual = RoutePatternFactory.Segment(parts);

        parts[1] = RoutePatternFactory.ParameterPart("E");
        Array.Resize(ref parts, 2);

        // Assert
        Assert.Equal(3, actual.Parts.Count);
        Assert.Same(paramPartB, actual.Parts[0]);
        Assert.Same(paramPartC, actual.Parts[1]);
        Assert.Same(paramPartD, actual.Parts[2]);
    }
        public void Create_ThrowsException_OnInvalidType()
        {
            // Arrange
            var options = new RouteOptions();

            options.ConstraintMap.Add("bad", typeof(string));

            var services = new ServiceCollection();

            var factory = GetParameterPolicyFactory(options, services);

            // Act
            var exception = Assert.Throws <InvalidOperationException>(
                () => factory.Create(RoutePatternFactory.ParameterPart("id"), @"bad"));

            // Assert
            Assert.Equal(
                $"Invalid constraint type '{typeof(string)}' registered as 'bad'. " +
                $"A constraint  type must either implement '{typeof(IRouteConstraint)}', or inherit from '{typeof(IParameterPolicy)}'.",
                exception.Message);
        }
        public void Create_CreatesParameterPolicy_FromConstraintText_AndParameterPolicyWithAmbigiousMatchingCtors()
        {
            // Arrange
            var options = new RouteOptions();

            options.ConstraintMap.Add("customConstraintPolicy", typeof(CustomParameterPolicyWithAmbigiousMultpleCtors));

            var services = new ServiceCollection();

            services.AddTransient <ITestService, TestService>();

            var factory = GetParameterPolicyFactory(options, services);

            // Act
            var exception = Assert.Throws <RouteCreationException>(
                () => factory.Create(RoutePatternFactory.ParameterPart("id"), "customConstraintPolicy(1)"));

            // Assert
            Assert.Equal($"The constructor to use for activating the constraint type '{nameof(CustomParameterPolicyWithAmbigiousMultpleCtors)}' is ambiguous. "
                         + "Multiple constructors were found with the following number of parameters: 2.", exception.Message);
        }
        public void Create_CreatesParameterPolicy_FromConstraintText_AndParameterPolicyWithSingleArgumentAndServiceArgument()
        {
            // Arrange
            var options = new RouteOptions();

            options.ConstraintMap.Add("regex-service", typeof(RegexInlineRouteConstraintWithService));

            var services = new ServiceCollection();

            services.AddTransient <ITestService, TestService>();

            var factory = GetParameterPolicyFactory(options, services);

            // Act
            var parameterPolicy = factory.Create(RoutePatternFactory.ParameterPart("id"), @"regex-service(\\d{1,2})");

            // Assert
            var constraint = Assert.IsType <RegexInlineRouteConstraintWithService>(parameterPolicy);

            Assert.NotNull(constraint.TestService);
            Assert.Equal("\\\\d{1,2}", constraint.Constraint.ToString());
        }
        public void Create_CreatesParameterPolicy_FromConstraintText_AndParameterPolicyWithMultipleMatchingCtors()
        {
            // Arrange
            var options = new RouteOptions();

            options.ConstraintMap.Add("customConstraintPolicy", typeof(CustomParameterPolicyWithMultpleCtors));

            var services = new ServiceCollection();

            services.AddTransient <ITestService, TestService>();

            var factory = GetParameterPolicyFactory(options, services);

            // Act
            var parameterPolicy = factory.Create(RoutePatternFactory.ParameterPart("id"), "customConstraintPolicy(1)");

            // Assert
            var constraint = Assert.IsType <CustomParameterPolicyWithMultpleCtors>(parameterPolicy);

            Assert.NotNull(constraint.TestService);
            Assert.Equal(1, constraint.Count);
        }
        public void Create_CreatesParameterPolicy_FromConstraintText_AndParameterPolicyWithOnlyServiceArguments()
        {
            // Arrange
            var options = new RouteOptions();

            options.ConstraintMap.Add("customConstraintPolicy", typeof(CustomParameterPolicyWithOnlyServiceArguments));

            var services = new ServiceCollection();

            services.AddTransient <ITestService, TestService>();

            var factory = GetParameterPolicyFactory(options, services);

            // Act
            var parameterPolicy = factory.Create(RoutePatternFactory.ParameterPart("id"), "customConstraintPolicy");

            // Assert
            var constraint = Assert.IsType <CustomParameterPolicyWithOnlyServiceArguments>(parameterPolicy);

            Assert.NotNull(constraint.TestService1);
            Assert.NotNull(constraint.TestService2);
        }
Example #22
0
        public RoutePatternPart ToRoutePatternPart()
        {
            if (IsLiteral && IsOptionalSeperator)
            {
                return(RoutePatternFactory.SeparatorPart(Text));
            }
            else if (IsLiteral)
            {
                return(RoutePatternFactory.LiteralPart(Text));
            }
            else
            {
                var kind = IsCatchAll ?
                           RoutePatternParameterKind.CatchAll :
                           IsOptional ?
                           RoutePatternParameterKind.Optional :
                           RoutePatternParameterKind.Standard;

                var constraints = InlineConstraints.Select(c => new RoutePatternParameterPolicyReference(c.Constraint));
                return(RoutePatternFactory.ParameterPart(Name, DefaultValue, kind, constraints));
            }
        }
    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);
    }
Example #24
0
        private IReadOnlyList <Endpoint> Update(StaticFileOptionsProvider staticFileOptionsProvider)
        {
            const string HtmlExtension      = ".html";
            const string CatchAllSlugPrefix = "...";

            var staticFileOptions = staticFileOptionsProvider.StaticFileOptions;
            var requestDelegate   = CreateRequestDelegate(this.endpointRouteBuilder, staticFileOptions);
            var endpoints         = new List <Endpoint>();

            foreach (var filePath in TraverseFiles(staticFileOptions.FileProvider))
            {
                if (!filePath.EndsWith(HtmlExtension))
                {
                    continue;
                }

                var fileWithoutHtml = filePath.Substring(0, filePath.Length - HtmlExtension.Length);
                var patternSegments = new List <RoutePatternPathSegment>();
                var segments        = fileWithoutHtml.Split('/');

                // NOTE: Start at 1 because paths here always have a leading slash
                for (int i = 1; i < segments.Length; i++)
                {
                    var segment = segments[i];
                    if (i == segments.Length - 1 && segment == "index")
                    {
                        // Skip `index` segment, match whatever we got so far.
                        // This is so that e.g. file `/a/b/index.html` is served at path `/a/b`, as desired.

                        // TODO: Should we also serve the same file at `/a/b/index`? Note that `/a/b/index.html` will already work
                        // via the UseStaticFiles middleware added by `NextjsStaticHostingExtensions.UseNextjsStaticHosting`.
                        break;
                    }

                    var match = slugRegex.Match(segment);
                    if (match.Success)
                    {
                        string slugName = match.Groups[1].Value;
                        if (slugName.StartsWith(CatchAllSlugPrefix))
                        {
                            // Catch all route -- see: https://nextjs.org/docs/routing/dynamic-routes#catch-all-routes
                            var parameterName = slugName.Substring(CatchAllSlugPrefix.Length);
                            patternSegments.Add(
                                RoutePatternFactory.Segment(
                                    RoutePatternFactory.ParameterPart(parameterName, null, RoutePatternParameterKind.CatchAll)));
                        }
                        else
                        {
                            // Dynamic route -- see: https://nextjs.org/docs/routing/dynamic-routes
                            patternSegments.Add(
                                RoutePatternFactory.Segment(
                                    RoutePatternFactory.ParameterPart(slugName)));
                        }
                    }
                    else
                    {
                        // Literal match
                        patternSegments.Add(
                            RoutePatternFactory.Segment(
                                RoutePatternFactory.LiteralPart(segment)));
                    }
                }
                var endpointBuilder = new RouteEndpointBuilder(requestDelegate, RoutePatternFactory.Pattern(patternSegments), order: DefaultEndpointOrder);

                endpointBuilder.Metadata.Add(new StaticFileEndpointMetadata(filePath));
                endpointBuilder.DisplayName = $"Next.js {filePath}";
                var endpoint = endpointBuilder.Build();
                endpoints.Add(endpoint);
            }

            return(endpoints);
        }