add tests for WithRejection<Valid<...>>
This commit is contained in:
26
src/extra.rs
26
src/extra.rs
@@ -30,6 +30,7 @@ impl<T: Validate, R> HasValidate for WithRejection<T, R> {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::tests::{Rejection, ValidTest};
|
||||
use crate::Valid;
|
||||
use axum::http::StatusCode;
|
||||
use axum_extra::extract::{Cached, WithRejection};
|
||||
use reqwest::RequestBuilder;
|
||||
@@ -52,7 +53,6 @@ mod tests {
|
||||
}
|
||||
|
||||
impl<T: ValidTest, R: Rejection> ValidTest for WithRejection<T, R> {
|
||||
// just use conflict to test
|
||||
const ERROR_STATUS_CODE: StatusCode = R::STATUS_CODE;
|
||||
|
||||
fn set_valid_request(builder: RequestBuilder) -> RequestBuilder {
|
||||
@@ -68,4 +68,28 @@ mod tests {
|
||||
T::set_invalid_request(builder)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ValidTest, R> ValidTest for WithRejection<Valid<T>, R> {
|
||||
// just use `418 I'm a teapot` to test
|
||||
const ERROR_STATUS_CODE: StatusCode = StatusCode::IM_A_TEAPOT;
|
||||
// If `WithRejection` is the outermost extractor,
|
||||
// the error code returned will always be the one provided by WithRejection.
|
||||
const INVALID_STATUS_CODE: StatusCode = StatusCode::IM_A_TEAPOT;
|
||||
// If `WithRejection` is the outermost extractor,
|
||||
// the returned body may not be in JSON format.
|
||||
const JSON_SERIALIZABLE: bool = false;
|
||||
|
||||
fn set_valid_request(builder: RequestBuilder) -> RequestBuilder {
|
||||
T::set_valid_request(builder)
|
||||
}
|
||||
|
||||
fn set_error_request(builder: RequestBuilder) -> RequestBuilder {
|
||||
// invalid requests will cause the Valid extractor to fail.
|
||||
T::set_invalid_request(builder)
|
||||
}
|
||||
|
||||
fn set_invalid_request(builder: RequestBuilder) -> RequestBuilder {
|
||||
T::set_invalid_request(builder)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,8 +155,13 @@ pub mod tests {
|
||||
/// 3. For an invalid request according to Valid, the server should return VALIDATION_ERROR_STATUS as the error code.
|
||||
///
|
||||
pub trait ValidTest {
|
||||
/// Http status code when inner extractor failed
|
||||
/// The HTTP status code returned when inner extractor failed.
|
||||
const ERROR_STATUS_CODE: StatusCode;
|
||||
/// The HTTP status code returned when the outer extractor fails.
|
||||
/// Use crate::VALIDATION_ERROR_STATUS by default.
|
||||
const INVALID_STATUS_CODE: StatusCode = crate::VALIDATION_ERROR_STATUS;
|
||||
/// If the response body can be serialized into JSON format
|
||||
const JSON_SERIALIZABLE: bool = true;
|
||||
/// Build a valid request, the server should return `200 OK`.
|
||||
fn set_valid_request(builder: RequestBuilder) -> RequestBuilder;
|
||||
/// Build an invalid request according to the extractor, the server should return `Self::ERROR_STATUS_CODE`
|
||||
|
||||
91
src/test.rs
91
src/test.rs
@@ -1,5 +1,6 @@
|
||||
use crate::test::extra::{ParametersRejection, WithRejectionValidRejection};
|
||||
use crate::tests::{ValidTest, ValidTestParameter};
|
||||
use crate::{Valid, VALIDATION_ERROR_STATUS};
|
||||
use crate::{HasValidate, Valid, VALIDATION_ERROR_STATUS};
|
||||
use axum::extract::{Path, Query};
|
||||
use axum::routing::{get, post};
|
||||
use axum::{Form, Json, Router};
|
||||
@@ -47,6 +48,14 @@ impl ValidTestParameter for Parameters {
|
||||
}
|
||||
}
|
||||
|
||||
impl HasValidate for Parameters {
|
||||
type Validate = Parameters;
|
||||
|
||||
fn get_validate(&self) -> &Self::Validate {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_main() -> anyhow::Result<()> {
|
||||
let router = Router::new()
|
||||
@@ -67,6 +76,10 @@ async fn test_main() -> anyhow::Result<()> {
|
||||
.route(
|
||||
extra::route::WITH_REJECTION,
|
||||
post(extra::extract_with_rejection),
|
||||
)
|
||||
.route(
|
||||
extra::route::WITH_REJECTION_VALID,
|
||||
post(extra::extract_with_rejection_valid),
|
||||
);
|
||||
|
||||
#[cfg(feature = "extra_query")]
|
||||
@@ -182,16 +195,22 @@ async fn test_main() -> anyhow::Result<()> {
|
||||
#[cfg(feature = "extra")]
|
||||
{
|
||||
use axum_extra::extract::{Cached, WithRejection};
|
||||
use extra::TestRejection;
|
||||
use extra::ValidWithRejectionRejection;
|
||||
test_executor
|
||||
.execute::<Cached<Parameters>>(Method::POST, extra::route::CACHED)
|
||||
.await?;
|
||||
test_executor
|
||||
.execute::<WithRejection<Parameters, TestRejection>>(
|
||||
.execute::<WithRejection<Parameters, ValidWithRejectionRejection>>(
|
||||
Method::POST,
|
||||
extra::route::WITH_REJECTION,
|
||||
)
|
||||
.await?;
|
||||
test_executor
|
||||
.execute::<WithRejection<Valid<Parameters>, WithRejectionValidRejection<ParametersRejection>>>(
|
||||
Method::POST,
|
||||
extra::route::WITH_REJECTION_VALID,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
|
||||
#[cfg(feature = "extra_query")]
|
||||
@@ -290,12 +309,15 @@ impl TestExecutor {
|
||||
let invalid_response = T::set_invalid_request(invalid_builder).send().await?;
|
||||
assert_eq!(
|
||||
invalid_response.status(),
|
||||
VALIDATION_ERROR_STATUS,
|
||||
T::INVALID_STATUS_CODE,
|
||||
"Invalid '{}' test failed.",
|
||||
type_name
|
||||
);
|
||||
#[cfg(feature = "into_json")]
|
||||
check_json(type_name, invalid_response).await;
|
||||
if T::JSON_SERIALIZABLE {
|
||||
check_json(type_name, invalid_response).await;
|
||||
}
|
||||
|
||||
println!("All '{}' tests passed.", type_name);
|
||||
|
||||
Ok(())
|
||||
@@ -424,7 +446,7 @@ mod typed_header {
|
||||
mod extra {
|
||||
use crate::test::{validate_again, Parameters};
|
||||
use crate::tests::{Rejection, ValidTest, ValidTestParameter};
|
||||
use crate::Valid;
|
||||
use crate::{Valid, ValidRejection};
|
||||
use axum::extract::FromRequestParts;
|
||||
use axum::http::request::Parts;
|
||||
use axum::http::StatusCode;
|
||||
@@ -435,6 +457,7 @@ mod extra {
|
||||
pub mod route {
|
||||
pub const CACHED: &str = "/cached";
|
||||
pub const WITH_REJECTION: &str = "/with_rejection";
|
||||
pub const WITH_REJECTION_VALID: &str = "/with_rejection_valid";
|
||||
}
|
||||
pub const PARAMETERS_HEADER: &str = "parameters-header";
|
||||
pub const CACHED_REJECTION_STATUS: StatusCode = StatusCode::FORBIDDEN;
|
||||
@@ -503,25 +526,27 @@ mod extra {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TestRejection {
|
||||
_inner: ParametersRejection,
|
||||
pub struct ValidWithRejectionRejection {
|
||||
inner: ParametersRejection,
|
||||
}
|
||||
|
||||
impl Rejection for TestRejection {
|
||||
impl Rejection for ValidWithRejectionRejection {
|
||||
const STATUS_CODE: StatusCode = StatusCode::CONFLICT;
|
||||
}
|
||||
|
||||
impl IntoResponse for TestRejection {
|
||||
impl IntoResponse for ValidWithRejectionRejection {
|
||||
fn into_response(self) -> Response {
|
||||
Self::STATUS_CODE.into_response()
|
||||
let mut response = self.inner.into_response();
|
||||
*response.status_mut() = Self::STATUS_CODE;
|
||||
response
|
||||
}
|
||||
}
|
||||
|
||||
// satisfy the `WithRejection`'s extractor trait bound
|
||||
// R: From<E::Rejection> + IntoResponse
|
||||
impl From<ParametersRejection> for TestRejection {
|
||||
fn from(_inner: ParametersRejection) -> Self {
|
||||
Self { _inner }
|
||||
impl From<ParametersRejection> for ValidWithRejectionRejection {
|
||||
fn from(inner: ParametersRejection) -> Self {
|
||||
Self { inner }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -532,7 +557,43 @@ mod extra {
|
||||
}
|
||||
|
||||
pub async fn extract_with_rejection(
|
||||
Valid(WithRejection(parameters, _)): Valid<WithRejection<Parameters, TestRejection>>,
|
||||
Valid(WithRejection(parameters, _)): Valid<
|
||||
WithRejection<Parameters, ValidWithRejectionRejection>,
|
||||
>,
|
||||
) -> StatusCode {
|
||||
validate_again(parameters)
|
||||
}
|
||||
|
||||
pub struct WithRejectionValidRejection<E> {
|
||||
inner: ValidRejection<E>,
|
||||
}
|
||||
|
||||
impl<E> From<ValidRejection<E>> for WithRejectionValidRejection<E> {
|
||||
fn from(inner: ValidRejection<E>) -> Self {
|
||||
Self { inner }
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: IntoResponse> IntoResponse for WithRejectionValidRejection<E> {
|
||||
fn into_response(self) -> Response {
|
||||
match self.inner {
|
||||
ValidRejection::Valid(v) => {
|
||||
(StatusCode::IM_A_TEAPOT, v.to_string()).into_response()
|
||||
}
|
||||
ValidRejection::Inner(i) => {
|
||||
let mut res = i.into_response();
|
||||
*res.status_mut() = StatusCode::IM_A_TEAPOT;
|
||||
res
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn extract_with_rejection_valid(
|
||||
WithRejection(Valid(parameters), _): WithRejection<
|
||||
Valid<Parameters>,
|
||||
WithRejectionValidRejection<ParametersRejection>,
|
||||
>,
|
||||
) -> StatusCode {
|
||||
validate_again(parameters)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user