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; } } } }
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); }
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); }
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); }
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); }
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); }