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)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::tests::{Rejection, ValidTest};
|
use crate::tests::{Rejection, ValidTest};
|
||||||
|
use crate::Valid;
|
||||||
use axum::http::StatusCode;
|
use axum::http::StatusCode;
|
||||||
use axum_extra::extract::{Cached, WithRejection};
|
use axum_extra::extract::{Cached, WithRejection};
|
||||||
use reqwest::RequestBuilder;
|
use reqwest::RequestBuilder;
|
||||||
@@ -52,7 +53,6 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<T: ValidTest, R: Rejection> ValidTest for WithRejection<T, R> {
|
impl<T: ValidTest, R: Rejection> ValidTest for WithRejection<T, R> {
|
||||||
// just use conflict to test
|
|
||||||
const ERROR_STATUS_CODE: StatusCode = R::STATUS_CODE;
|
const ERROR_STATUS_CODE: StatusCode = R::STATUS_CODE;
|
||||||
|
|
||||||
fn set_valid_request(builder: RequestBuilder) -> RequestBuilder {
|
fn set_valid_request(builder: RequestBuilder) -> RequestBuilder {
|
||||||
@@ -68,4 +68,28 @@ mod tests {
|
|||||||
T::set_invalid_request(builder)
|
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.
|
/// 3. For an invalid request according to Valid, the server should return VALIDATION_ERROR_STATUS as the error code.
|
||||||
///
|
///
|
||||||
pub trait ValidTest {
|
pub trait ValidTest {
|
||||||
/// Http status code when inner extractor failed
|
/// The HTTP status code returned when inner extractor failed.
|
||||||
const ERROR_STATUS_CODE: StatusCode;
|
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`.
|
/// Build a valid request, the server should return `200 OK`.
|
||||||
fn set_valid_request(builder: RequestBuilder) -> RequestBuilder;
|
fn set_valid_request(builder: RequestBuilder) -> RequestBuilder;
|
||||||
/// Build an invalid request according to the extractor, the server should return `Self::ERROR_STATUS_CODE`
|
/// 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::tests::{ValidTest, ValidTestParameter};
|
||||||
use crate::{Valid, VALIDATION_ERROR_STATUS};
|
use crate::{HasValidate, Valid, VALIDATION_ERROR_STATUS};
|
||||||
use axum::extract::{Path, Query};
|
use axum::extract::{Path, Query};
|
||||||
use axum::routing::{get, post};
|
use axum::routing::{get, post};
|
||||||
use axum::{Form, Json, Router};
|
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]
|
#[tokio::test]
|
||||||
async fn test_main() -> anyhow::Result<()> {
|
async fn test_main() -> anyhow::Result<()> {
|
||||||
let router = Router::new()
|
let router = Router::new()
|
||||||
@@ -67,6 +76,10 @@ async fn test_main() -> anyhow::Result<()> {
|
|||||||
.route(
|
.route(
|
||||||
extra::route::WITH_REJECTION,
|
extra::route::WITH_REJECTION,
|
||||||
post(extra::extract_with_rejection),
|
post(extra::extract_with_rejection),
|
||||||
|
)
|
||||||
|
.route(
|
||||||
|
extra::route::WITH_REJECTION_VALID,
|
||||||
|
post(extra::extract_with_rejection_valid),
|
||||||
);
|
);
|
||||||
|
|
||||||
#[cfg(feature = "extra_query")]
|
#[cfg(feature = "extra_query")]
|
||||||
@@ -182,16 +195,22 @@ async fn test_main() -> anyhow::Result<()> {
|
|||||||
#[cfg(feature = "extra")]
|
#[cfg(feature = "extra")]
|
||||||
{
|
{
|
||||||
use axum_extra::extract::{Cached, WithRejection};
|
use axum_extra::extract::{Cached, WithRejection};
|
||||||
use extra::TestRejection;
|
use extra::ValidWithRejectionRejection;
|
||||||
test_executor
|
test_executor
|
||||||
.execute::<Cached<Parameters>>(Method::POST, extra::route::CACHED)
|
.execute::<Cached<Parameters>>(Method::POST, extra::route::CACHED)
|
||||||
.await?;
|
.await?;
|
||||||
test_executor
|
test_executor
|
||||||
.execute::<WithRejection<Parameters, TestRejection>>(
|
.execute::<WithRejection<Parameters, ValidWithRejectionRejection>>(
|
||||||
Method::POST,
|
Method::POST,
|
||||||
extra::route::WITH_REJECTION,
|
extra::route::WITH_REJECTION,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
test_executor
|
||||||
|
.execute::<WithRejection<Valid<Parameters>, WithRejectionValidRejection<ParametersRejection>>>(
|
||||||
|
Method::POST,
|
||||||
|
extra::route::WITH_REJECTION_VALID,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "extra_query")]
|
#[cfg(feature = "extra_query")]
|
||||||
@@ -290,12 +309,15 @@ impl TestExecutor {
|
|||||||
let invalid_response = T::set_invalid_request(invalid_builder).send().await?;
|
let invalid_response = T::set_invalid_request(invalid_builder).send().await?;
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
invalid_response.status(),
|
invalid_response.status(),
|
||||||
VALIDATION_ERROR_STATUS,
|
T::INVALID_STATUS_CODE,
|
||||||
"Invalid '{}' test failed.",
|
"Invalid '{}' test failed.",
|
||||||
type_name
|
type_name
|
||||||
);
|
);
|
||||||
#[cfg(feature = "into_json")]
|
#[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);
|
println!("All '{}' tests passed.", type_name);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -424,7 +446,7 @@ mod typed_header {
|
|||||||
mod extra {
|
mod extra {
|
||||||
use crate::test::{validate_again, Parameters};
|
use crate::test::{validate_again, Parameters};
|
||||||
use crate::tests::{Rejection, ValidTest, ValidTestParameter};
|
use crate::tests::{Rejection, ValidTest, ValidTestParameter};
|
||||||
use crate::Valid;
|
use crate::{Valid, ValidRejection};
|
||||||
use axum::extract::FromRequestParts;
|
use axum::extract::FromRequestParts;
|
||||||
use axum::http::request::Parts;
|
use axum::http::request::Parts;
|
||||||
use axum::http::StatusCode;
|
use axum::http::StatusCode;
|
||||||
@@ -435,6 +457,7 @@ mod extra {
|
|||||||
pub mod route {
|
pub mod route {
|
||||||
pub const CACHED: &str = "/cached";
|
pub const CACHED: &str = "/cached";
|
||||||
pub const WITH_REJECTION: &str = "/with_rejection";
|
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 PARAMETERS_HEADER: &str = "parameters-header";
|
||||||
pub const CACHED_REJECTION_STATUS: StatusCode = StatusCode::FORBIDDEN;
|
pub const CACHED_REJECTION_STATUS: StatusCode = StatusCode::FORBIDDEN;
|
||||||
@@ -503,25 +526,27 @@ mod extra {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct TestRejection {
|
pub struct ValidWithRejectionRejection {
|
||||||
_inner: ParametersRejection,
|
inner: ParametersRejection,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Rejection for TestRejection {
|
impl Rejection for ValidWithRejectionRejection {
|
||||||
const STATUS_CODE: StatusCode = StatusCode::CONFLICT;
|
const STATUS_CODE: StatusCode = StatusCode::CONFLICT;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IntoResponse for TestRejection {
|
impl IntoResponse for ValidWithRejectionRejection {
|
||||||
fn into_response(self) -> Response {
|
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
|
// satisfy the `WithRejection`'s extractor trait bound
|
||||||
// R: From<E::Rejection> + IntoResponse
|
// R: From<E::Rejection> + IntoResponse
|
||||||
impl From<ParametersRejection> for TestRejection {
|
impl From<ParametersRejection> for ValidWithRejectionRejection {
|
||||||
fn from(_inner: ParametersRejection) -> Self {
|
fn from(inner: ParametersRejection) -> Self {
|
||||||
Self { _inner }
|
Self { inner }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -532,7 +557,43 @@ mod extra {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn extract_with_rejection(
|
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 {
|
) -> StatusCode {
|
||||||
validate_again(parameters)
|
validate_again(parameters)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user