Skip to content

Commit 3f31315

Browse files
committed
Add validation filter tests for ProblemDetails handling
Introduces the `ValidationFilterEndpointFactoryTests` class with two unit tests. These tests validate HTTP request behavior with and without the `ProblemDetails` service registered, ensuring correct status codes, content types, and the structure of the returned `ProblemDetails` object for validation errors.
1 parent 29168ec commit 3f31315

File tree

1 file changed

+121
-0
lines changed

1 file changed

+121
-0
lines changed
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
#pragma warning disable ASP0029 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
2+
3+
// Licensed to the .NET Foundation under one or more agreements.
4+
// The .NET Foundation licenses this file to you under the MIT license.
5+
6+
using System.ComponentModel.DataAnnotations;
7+
using System.Net.Mime;
8+
using System.Text.Json;
9+
using Microsoft.AspNetCore.Builder;
10+
using Microsoft.AspNetCore.InternalTesting;
11+
using Microsoft.AspNetCore.Mvc;
12+
using Microsoft.AspNetCore.Routing;
13+
using Microsoft.Extensions.DependencyInjection;
14+
15+
namespace Microsoft.AspNetCore.Http.Extensions.Tests;
16+
17+
public class ValidationFilterEndpointFactoryTests
18+
{
19+
[Fact]
20+
public async Task GetHttpValidationProblemDetailsWhenProblemDetailsServiceNotRegistered()
21+
{
22+
var services = new ServiceCollection();
23+
services.AddValidation();
24+
var serviceProvider = services.BuildServiceProvider();
25+
26+
var builder = new DefaultEndpointRouteBuilder(new ApplicationBuilder(serviceProvider));
27+
28+
// Act - Create one endpoint with validation
29+
builder.MapGet("test-enabled", ([Range(5, 10)] int param) => "Validation enabled here.");
30+
31+
// Build the endpoints
32+
var dataSource = Assert.Single(builder.DataSources);
33+
var endpoints = dataSource.Endpoints;
34+
35+
// Get filter factories from endpoint
36+
var endpoint = endpoints[0];
37+
38+
var context = new DefaultHttpContext
39+
{
40+
RequestServices = serviceProvider
41+
};
42+
43+
context.Request.Method = "GET";
44+
context.Request.QueryString = new QueryString("?param=15");
45+
using var ms = new MemoryStream();
46+
context.Response.Body = ms;
47+
48+
await endpoint.RequestDelegate(context);
49+
50+
// Assert
51+
Assert.Equal(StatusCodes.Status400BadRequest, context.Response.StatusCode);
52+
Assert.StartsWith(MediaTypeNames.Application.Json, context.Response.ContentType, StringComparison.OrdinalIgnoreCase);
53+
54+
ms.Seek(0, SeekOrigin.Begin);
55+
var problemDetails = await JsonSerializer.DeserializeAsync<ProblemDetails>(ms, JsonSerializerOptions.Web);
56+
57+
Assert.Equal("One or more validation errors occurred.", problemDetails.Title);
58+
59+
// Check that ProblemDetails contains the errors object with 1 validation error
60+
Assert.True(problemDetails.Extensions.TryGetValue("errors", out var errorsObj));
61+
var errors = Assert.IsType<JsonElement>(errorsObj);
62+
Assert.True(errors.EnumerateObject().Count() == 1);
63+
}
64+
65+
[Fact]
66+
public async Task UseProblemDetailsServiceWhenAddedInServiceCollection()
67+
{
68+
var services = new ServiceCollection();
69+
services.AddValidation();
70+
services.AddProblemDetails();
71+
var serviceProvider = services.BuildServiceProvider();
72+
73+
var builder = new DefaultEndpointRouteBuilder(new ApplicationBuilder(serviceProvider));
74+
75+
// Act - Create one endpoint with validation
76+
builder.MapGet("test-enabled", ([Range(5, 10)] int param) => "Validation enabled here.");
77+
78+
// Build the endpoints
79+
var dataSource = Assert.Single(builder.DataSources);
80+
var endpoints = dataSource.Endpoints;
81+
82+
// Get filter factories from endpoint
83+
var endpoint = endpoints[0];
84+
85+
var context = new DefaultHttpContext
86+
{
87+
RequestServices = serviceProvider
88+
};
89+
90+
context.Request.Method = "GET";
91+
context.Request.QueryString = new QueryString("?param=15");
92+
using var ms = new MemoryStream();
93+
context.Response.Body = ms;
94+
95+
await endpoint.RequestDelegate(context);
96+
97+
// Assert
98+
Assert.Equal(StatusCodes.Status400BadRequest, context.Response.StatusCode);
99+
Assert.StartsWith(MediaTypeNames.Application.ProblemJson, context.Response.ContentType, StringComparison.OrdinalIgnoreCase);
100+
101+
ms.Seek(0, SeekOrigin.Begin);
102+
var problemDetails = await JsonSerializer.DeserializeAsync<ProblemDetails>(ms, JsonSerializerOptions.Web);
103+
104+
Assert.Equal("https://tools.ietf.org/html/rfc9110#section-15.5.1", problemDetails.Type);
105+
Assert.Equal("One or more validation errors occurred.", problemDetails.Title);
106+
Assert.Equal(StatusCodes.Status400BadRequest, problemDetails.Status);
107+
108+
// Check that ProblemDetails contains the errors object with 1 validation error
109+
Assert.True(problemDetails.Extensions.TryGetValue("errors", out var errorsObj));
110+
var errors = Assert.IsType<JsonElement>(errorsObj);
111+
Assert.True(errors.EnumerateObject().Count() == 1);
112+
}
113+
114+
private class DefaultEndpointRouteBuilder(IApplicationBuilder applicationBuilder) : IEndpointRouteBuilder
115+
{
116+
private IApplicationBuilder ApplicationBuilder { get; } = applicationBuilder ?? throw new ArgumentNullException(nameof(applicationBuilder));
117+
public IApplicationBuilder CreateApplicationBuilder() => ApplicationBuilder.New();
118+
public ICollection<EndpointDataSource> DataSources { get; } = [];
119+
public IServiceProvider ServiceProvider => ApplicationBuilder.ApplicationServices;
120+
}
121+
}

0 commit comments

Comments
 (0)