mirror of
https://gitlab.com/msrd0/gotham-restful.git
synced 2025-02-23 13:02:28 +00:00
improve test coverage for the result types
This commit is contained in:
parent
0d95ca4abb
commit
101e94b900
6 changed files with 171 additions and 84 deletions
|
@ -6,7 +6,7 @@ use crate::{
|
||||||
};
|
};
|
||||||
use super::SECURITY_NAME;
|
use super::SECURITY_NAME;
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
use mime::{Mime, STAR_STAR};
|
use mime::Mime;
|
||||||
use openapiv3::{
|
use openapiv3::{
|
||||||
MediaType, Operation, Parameter, ParameterData, ParameterSchemaOrContent, ReferenceOr,
|
MediaType, Operation, Parameter, ParameterData, ParameterSchemaOrContent, ReferenceOr,
|
||||||
ReferenceOr::Item, RequestBody as OARequestBody, Response, Responses, Schema, SchemaKind,
|
ReferenceOr::Item, RequestBody as OARequestBody, Response, Responses, Schema, SchemaKind,
|
||||||
|
@ -148,7 +148,7 @@ impl<'a> OperationDescription<'a>
|
||||||
let (operation_id, default_status, accepted_types, schema, params, body_schema, supported_types, requires_auth) = (
|
let (operation_id, default_status, accepted_types, schema, params, body_schema, supported_types, requires_auth) = (
|
||||||
self.operation_id, self.default_status, self.accepted_types, self.schema, self.params, self.body_schema, self.supported_types, self.requires_auth);
|
self.operation_id, self.default_status, self.accepted_types, self.schema, self.params, self.body_schema, self.supported_types, self.requires_auth);
|
||||||
|
|
||||||
let content = Self::schema_to_content(accepted_types.unwrap_or_else(|| vec![STAR_STAR]), schema);
|
let content = Self::schema_to_content(accepted_types.or_all_types(), schema);
|
||||||
|
|
||||||
let mut responses : IndexMap<StatusCode, ReferenceOr<Response>> = IndexMap::new();
|
let mut responses : IndexMap<StatusCode, ReferenceOr<Response>> = IndexMap::new();
|
||||||
responses.insert(StatusCode::Code(default_status.as_u16()), Item(Response {
|
responses.insert(StatusCode::Code(default_status.as_u16()), Item(Response {
|
||||||
|
@ -159,7 +159,7 @@ impl<'a> OperationDescription<'a>
|
||||||
|
|
||||||
let request_body = body_schema.map(|schema| Item(OARequestBody {
|
let request_body = body_schema.map(|schema| Item(OARequestBody {
|
||||||
description: None,
|
description: None,
|
||||||
content: Self::schema_to_content(supported_types.unwrap_or_else(|| vec![STAR_STAR]), schema),
|
content: Self::schema_to_content(supported_types.or_all_types(), schema),
|
||||||
required: true
|
required: true
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -199,7 +199,7 @@ mod test
|
||||||
{
|
{
|
||||||
let types = NoContent::accepted_types();
|
let types = NoContent::accepted_types();
|
||||||
let schema = <NoContent as OpenapiType>::schema();
|
let schema = <NoContent as OpenapiType>::schema();
|
||||||
let content = OperationDescription::schema_to_content(types.unwrap_or_else(|| vec![STAR_STAR]), Item(schema.into_schema()));
|
let content = OperationDescription::schema_to_content(types.or_all_types(), Item(schema.into_schema()));
|
||||||
assert!(content.is_empty());
|
assert!(content.is_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -208,7 +208,7 @@ mod test
|
||||||
{
|
{
|
||||||
let types = Raw::<&str>::accepted_types();
|
let types = Raw::<&str>::accepted_types();
|
||||||
let schema = <Raw<&str> as OpenapiType>::schema();
|
let schema = <Raw<&str> as OpenapiType>::schema();
|
||||||
let content = OperationDescription::schema_to_content(types.unwrap_or_else(|| vec![STAR_STAR]), Item(schema.into_schema()));
|
let content = OperationDescription::schema_to_content(types.or_all_types(), Item(schema.into_schema()));
|
||||||
assert_eq!(content.len(), 1);
|
assert_eq!(content.len(), 1);
|
||||||
let json = serde_json::to_string(&content.values().nth(0).unwrap()).unwrap();
|
let json = serde_json::to_string(&content.values().nth(0).unwrap()).unwrap();
|
||||||
assert_eq!(json, r#"{"schema":{"type":"string","format":"binary"}}"#);
|
assert_eq!(json, r#"{"schema":{"type":"string","format":"binary"}}"#);
|
||||||
|
|
|
@ -2,7 +2,7 @@ use crate::Response;
|
||||||
#[cfg(feature = "openapi")]
|
#[cfg(feature = "openapi")]
|
||||||
use crate::OpenapiSchema;
|
use crate::OpenapiSchema;
|
||||||
use futures_util::future::FutureExt;
|
use futures_util::future::FutureExt;
|
||||||
use mime::Mime;
|
use mime::{Mime, STAR_STAR};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use std::{
|
use std::{
|
||||||
error::Error,
|
error::Error,
|
||||||
|
@ -26,6 +26,21 @@ pub use result::IntoResponseError;
|
||||||
mod success;
|
mod success;
|
||||||
pub use success::Success;
|
pub use success::Success;
|
||||||
|
|
||||||
|
|
||||||
|
pub(crate) trait OrAllTypes
|
||||||
|
{
|
||||||
|
fn or_all_types(self) -> Vec<Mime>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OrAllTypes for Option<Vec<Mime>>
|
||||||
|
{
|
||||||
|
fn or_all_types(self) -> Vec<Mime>
|
||||||
|
{
|
||||||
|
self.unwrap_or_else(|| vec![STAR_STAR])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// A trait provided to convert a resource's result to json.
|
/// A trait provided to convert a resource's result to json.
|
||||||
pub trait ResourceResult
|
pub trait ResourceResult
|
||||||
{
|
{
|
||||||
|
@ -145,13 +160,11 @@ where
|
||||||
mod test
|
mod test
|
||||||
{
|
{
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{OpenapiType, StatusCode};
|
|
||||||
use futures_executor::block_on;
|
use futures_executor::block_on;
|
||||||
use mime::{APPLICATION_JSON, TEXT_PLAIN};
|
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
#[derive(Debug, Default, Deserialize, Serialize)]
|
#[derive(Debug, Default, Deserialize, Serialize)]
|
||||||
#[cfg_attr(feature = "openapi", derive(OpenapiType))]
|
#[cfg_attr(feature = "openapi", derive(crate::OpenapiType))]
|
||||||
struct Msg
|
struct Msg
|
||||||
{
|
{
|
||||||
msg : String
|
msg : String
|
||||||
|
@ -162,63 +175,16 @@ mod test
|
||||||
struct MsgError;
|
struct MsgError;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn resource_result_ok()
|
fn result_from_future()
|
||||||
{
|
{
|
||||||
let ok : Result<Msg, MsgError> = Ok(Msg::default());
|
let nc = NoContent::default();
|
||||||
let res = block_on(ok.into_response()).expect("didn't expect error response");
|
let res = block_on(nc.into_response()).unwrap();
|
||||||
assert_eq!(res.status, StatusCode::OK);
|
|
||||||
assert_eq!(res.mime, Some(APPLICATION_JSON));
|
|
||||||
assert_eq!(res.full_body().unwrap(), r#"{"msg":""}"#.as_bytes());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
let fut_nc = async move { NoContent::default() }.boxed();
|
||||||
fn resource_result_err()
|
let fut_res = block_on(fut_nc.into_response()).unwrap();
|
||||||
{
|
|
||||||
let err : Result<Msg, MsgError> = Err(MsgError::default());
|
|
||||||
let res = block_on(err.into_response()).expect("didn't expect error response");
|
|
||||||
assert_eq!(res.status, StatusCode::INTERNAL_SERVER_ERROR);
|
|
||||||
assert_eq!(res.mime, Some(APPLICATION_JSON));
|
|
||||||
assert_eq!(res.full_body().unwrap(), format!(r#"{{"error":true,"message":"{}"}}"#, MsgError::default()).as_bytes());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
assert_eq!(res.status, fut_res.status);
|
||||||
fn success_always_successfull()
|
assert_eq!(res.mime, fut_res.mime);
|
||||||
{
|
assert_eq!(res.full_body().unwrap(), fut_res.full_body().unwrap());
|
||||||
let success : Success<Msg> = Msg::default().into();
|
|
||||||
let res = block_on(success.into_response()).expect("didn't expect error response");
|
|
||||||
assert_eq!(res.status, StatusCode::OK);
|
|
||||||
assert_eq!(res.mime, Some(APPLICATION_JSON));
|
|
||||||
assert_eq!(res.full_body().unwrap(), r#"{"msg":""}"#.as_bytes());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn no_content_has_empty_response()
|
|
||||||
{
|
|
||||||
let no_content = NoContent::default();
|
|
||||||
let res = block_on(no_content.into_response()).expect("didn't expect error response");
|
|
||||||
assert_eq!(res.status, StatusCode::NO_CONTENT);
|
|
||||||
assert_eq!(res.mime, None);
|
|
||||||
assert_eq!(res.full_body().unwrap(), &[] as &[u8]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn no_content_result()
|
|
||||||
{
|
|
||||||
let no_content : Result<NoContent, MsgError> = Ok(NoContent::default());
|
|
||||||
let res = block_on(no_content.into_response()).expect("didn't expect error response");
|
|
||||||
assert_eq!(res.status, StatusCode::NO_CONTENT);
|
|
||||||
assert_eq!(res.mime, None);
|
|
||||||
assert_eq!(res.full_body().unwrap(), &[] as &[u8]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn raw_response()
|
|
||||||
{
|
|
||||||
let msg = "Test";
|
|
||||||
let raw = Raw::new(msg, TEXT_PLAIN);
|
|
||||||
let res = block_on(raw.into_response()).expect("didn't expect error response");
|
|
||||||
assert_eq!(res.status, StatusCode::OK);
|
|
||||||
assert_eq!(res.mime, Some(TEXT_PLAIN));
|
|
||||||
assert_eq!(res.full_body().unwrap(), msg.as_bytes());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,3 +104,37 @@ where
|
||||||
NoContent::default_status()
|
NoContent::default_status()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test
|
||||||
|
{
|
||||||
|
use super::*;
|
||||||
|
use futures_executor::block_on;
|
||||||
|
use gotham::hyper::StatusCode;
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Error)]
|
||||||
|
#[error("An Error")]
|
||||||
|
struct MsgError;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn no_content_has_empty_response()
|
||||||
|
{
|
||||||
|
let no_content = NoContent::default();
|
||||||
|
let res = block_on(no_content.into_response()).expect("didn't expect error response");
|
||||||
|
assert_eq!(res.status, StatusCode::NO_CONTENT);
|
||||||
|
assert_eq!(res.mime, None);
|
||||||
|
assert_eq!(res.full_body().unwrap(), &[] as &[u8]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn no_content_result()
|
||||||
|
{
|
||||||
|
let no_content : Result<NoContent, MsgError> = Ok(NoContent::default());
|
||||||
|
let res = block_on(no_content.into_response()).expect("didn't expect error response");
|
||||||
|
assert_eq!(res.status, StatusCode::NO_CONTENT);
|
||||||
|
assert_eq!(res.mime, None);
|
||||||
|
assert_eq!(res.full_body().unwrap(), &[] as &[u8]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -10,10 +10,11 @@ use mime::Mime;
|
||||||
use openapiv3::{SchemaKind, StringFormat, StringType, Type, VariantOrUnknownOrEmpty};
|
use openapiv3::{SchemaKind, StringFormat, StringType, Type, VariantOrUnknownOrEmpty};
|
||||||
use serde_json::error::Error as SerdeJsonError;
|
use serde_json::error::Error as SerdeJsonError;
|
||||||
use std::{
|
use std::{
|
||||||
fmt::{Debug, Display},
|
fmt::Display,
|
||||||
pin::Pin
|
pin::Pin
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct Raw<T>
|
pub struct Raw<T>
|
||||||
{
|
{
|
||||||
pub raw : T,
|
pub raw : T,
|
||||||
|
@ -39,13 +40,6 @@ impl<T : Clone> Clone for Raw<T>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T : Debug> Debug for Raw<T>
|
|
||||||
{
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
write!(f, "Raw({:?}, {:?})", self.raw, self.mime)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T : Into<Body>> ResourceResult for Raw<T>
|
impl<T : Into<Body>> ResourceResult for Raw<T>
|
||||||
where
|
where
|
||||||
Self : Send
|
Self : Send
|
||||||
|
@ -88,3 +82,23 @@ where
|
||||||
<Raw<T> as ResourceResult>::schema()
|
<Raw<T> as ResourceResult>::schema()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test
|
||||||
|
{
|
||||||
|
use super::*;
|
||||||
|
use futures_executor::block_on;
|
||||||
|
use mime::TEXT_PLAIN;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn raw_response()
|
||||||
|
{
|
||||||
|
let msg = "Test";
|
||||||
|
let raw = Raw::new(msg, TEXT_PLAIN);
|
||||||
|
let res = block_on(raw.into_response()).expect("didn't expect error response");
|
||||||
|
assert_eq!(res.status, StatusCode::OK);
|
||||||
|
assert_eq!(res.mime, Some(TEXT_PLAIN));
|
||||||
|
assert_eq!(res.full_body().unwrap(), msg.as_bytes());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -57,3 +57,50 @@ where
|
||||||
R::schema()
|
R::schema()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test
|
||||||
|
{
|
||||||
|
use super::*;
|
||||||
|
use crate::result::OrAllTypes;
|
||||||
|
use futures_executor::block_on;
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Deserialize, Serialize)]
|
||||||
|
#[cfg_attr(feature = "openapi", derive(crate::OpenapiType))]
|
||||||
|
struct Msg
|
||||||
|
{
|
||||||
|
msg : String
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Error)]
|
||||||
|
#[error("An Error")]
|
||||||
|
struct MsgError;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn result_ok()
|
||||||
|
{
|
||||||
|
let ok : Result<Msg, MsgError> = Ok(Msg::default());
|
||||||
|
let res = block_on(ok.into_response()).expect("didn't expect error response");
|
||||||
|
assert_eq!(res.status, StatusCode::OK);
|
||||||
|
assert_eq!(res.mime, Some(APPLICATION_JSON));
|
||||||
|
assert_eq!(res.full_body().unwrap(), r#"{"msg":""}"#.as_bytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn result_err()
|
||||||
|
{
|
||||||
|
let err : Result<Msg, MsgError> = Err(MsgError::default());
|
||||||
|
let res = block_on(err.into_response()).expect("didn't expect error response");
|
||||||
|
assert_eq!(res.status, StatusCode::INTERNAL_SERVER_ERROR);
|
||||||
|
assert_eq!(res.mime, Some(APPLICATION_JSON));
|
||||||
|
assert_eq!(res.full_body().unwrap(), format!(r#"{{"error":true,"message":"{}"}}"#, MsgError::default()).as_bytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn success_accepts_json()
|
||||||
|
{
|
||||||
|
assert!(<Result<Msg, MsgError>>::accepted_types().or_all_types().contains(&APPLICATION_JSON))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -41,6 +41,7 @@ fn read_all(_state: &mut State) -> Success<MyResponse> {
|
||||||
# }
|
# }
|
||||||
```
|
```
|
||||||
*/
|
*/
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct Success<T>(T);
|
pub struct Success<T>(T);
|
||||||
|
|
||||||
impl<T> AsMut<T> for Success<T>
|
impl<T> AsMut<T> for Success<T>
|
||||||
|
@ -97,13 +98,6 @@ impl<T : Copy> Copy for Success<T>
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T : Debug> Debug for Success<T>
|
|
||||||
{
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
write!(f, "Success({:?})", self.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T : Default> Default for Success<T>
|
impl<T : Default> Default for Success<T>
|
||||||
{
|
{
|
||||||
fn default() -> Self
|
fn default() -> Self
|
||||||
|
@ -134,3 +128,35 @@ where
|
||||||
T::schema()
|
T::schema()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test
|
||||||
|
{
|
||||||
|
use super::*;
|
||||||
|
use crate::result::OrAllTypes;
|
||||||
|
use futures_executor::block_on;
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Serialize)]
|
||||||
|
#[cfg_attr(feature = "openapi", derive(crate::OpenapiType))]
|
||||||
|
struct Msg
|
||||||
|
{
|
||||||
|
msg : String
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn success_always_successfull()
|
||||||
|
{
|
||||||
|
let success : Success<Msg> = Msg::default().into();
|
||||||
|
let res = block_on(success.into_response()).expect("didn't expect error response");
|
||||||
|
assert_eq!(res.status, StatusCode::OK);
|
||||||
|
assert_eq!(res.mime, Some(APPLICATION_JSON));
|
||||||
|
assert_eq!(res.full_body().unwrap(), r#"{"msg":""}"#.as_bytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn success_accepts_json()
|
||||||
|
{
|
||||||
|
assert!(<Success<Msg>>::accepted_types().or_all_types().contains(&APPLICATION_JSON))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue