1
0
Fork 0
mirror of https://gitlab.com/msrd0/gotham-restful.git synced 2025-02-23 13:02:28 +00:00

add first tests

This commit is contained in:
Dominic 2019-10-14 02:17:25 +02:00
parent 5c5c7fc4fb
commit df3b735429
Signed by: msrd0
GPG key ID: DCC8C247452E98F9
7 changed files with 108 additions and 22 deletions

View file

@ -1,36 +1,38 @@
stages: stages:
- check - test
variables: variables:
CARGO_HOME: $CI_PROJECT_DIR/cargo CARGO_HOME: $CI_PROJECT_DIR/cargo
check-none: test-none:
stage: check stage: test
image: msrd0/rust:alpine image: msrd0/rust:alpine
before_script: before_script:
- cargo -V - cargo -V
script: script:
- cargo check --all --no-default-features - cargo test --all --no-default-features
cache: cache:
paths: paths:
- cargo/ - cargo/
- target/ - target/
check-all: test-all:
stage: check stage: test
image: msrd0/rust:alpine image: msrd0/rust:alpine-tarpaulin
before_script: before_script:
- apk add --no-cache bash curl
- cargo -V - cargo -V
script: script:
- cargo check --all --all-features - cargo tarpaulin --all --all-features --exclude-files 'cargo/*' --exclude-files 'example/*' --out Xml
- wget -qO- https://codecov.io/bash | bash -s -- -X gcov
cache: cache:
paths: paths:
- cargo/ - cargo/
- target/ - target/
readme: readme:
stage: check stage: test
image: msrd0/rust:alpine-readme image: msrd0/rust:alpine-readme
script: script:
- cargo readme -r gotham_restful -t ../README.tpl >README.md.new - cargo readme -r gotham_restful -t ../README.tpl >README.md.new

View file

@ -30,6 +30,9 @@ openapiv3 = { version = "0.3", optional = true }
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }
serde_json = "1" serde_json = "1"
[dev-dependencies]
thiserror = "1"
[features] [features]
default = [] default = []
openapi = ["gotham_restful_derive/openapi", "indexmap", "log", "openapiv3"] openapi = ["gotham_restful_derive/openapi", "indexmap", "log", "openapiv3"]

View file

@ -174,7 +174,7 @@ impl<E : Error> ResourceResult for Result<NoContent, E>
fn to_json(&self) -> Result<(StatusCode, String), SerdeJsonError> fn to_json(&self) -> Result<(StatusCode, String), SerdeJsonError>
{ {
Ok(match self { Ok(match self {
Ok(_) => (StatusCode::NO_CONTENT, "".to_string()), Ok(_) => (Self::default_status(), "".to_string()),
Err(e) => { Err(e) => {
let err : ResourceError = e.into(); let err : ResourceError = e.into();
(StatusCode::INTERNAL_SERVER_ERROR, serde_json::to_string(&err)?) (StatusCode::INTERNAL_SERVER_ERROR, serde_json::to_string(&err)?)
@ -185,12 +185,75 @@ impl<E : Error> ResourceResult for Result<NoContent, E>
#[cfg(feature = "openapi")] #[cfg(feature = "openapi")]
fn schema() -> OpenapiSchema fn schema() -> OpenapiSchema
{ {
<()>::schema() <NoContent as ResourceResult>::schema()
} }
#[cfg(feature = "openapi")] #[cfg(feature = "openapi")]
fn default_status() -> StatusCode fn default_status() -> StatusCode
{ {
StatusCode::NO_CONTENT NoContent::default_status()
}
}
#[cfg(test)]
mod test
{
use super::*;
use thiserror::Error;
#[derive(Debug, Default, Deserialize, Serialize)]
#[cfg_attr(feature = "openapi", derive(OpenapiType))]
struct Msg
{
msg : String
}
#[derive(Debug, Default, Error)]
#[error("An Error")]
struct MsgError;
#[test]
fn resource_result_ok()
{
let ok : Result<Msg, MsgError> = Ok(Msg::default());
let (status, json) = ok.to_json().expect("didn't expect error response");
assert_eq!(status, StatusCode::OK);
assert_eq!(json, r#"{"msg":""}"#);
}
#[test]
fn resource_result_err()
{
let err : Result<Msg, MsgError> = Err(MsgError::default());
let (status, json) = err.to_json().expect("didn't expect error response");
assert_eq!(status, StatusCode::INTERNAL_SERVER_ERROR);
assert_eq!(json, format!(r#"{{"error":true,"message":"{}"}}"#, err.unwrap_err()));
}
#[test]
fn success_always_successfull()
{
let success : Success<Msg> = Msg::default().into();
let (status, json) = success.to_json().expect("didn't expect error response");
assert_eq!(status, StatusCode::OK);
assert_eq!(json, r#"{"msg":""}"#);
}
#[test]
fn no_content_has_empty_json()
{
let no_content = NoContent::default();
let (status, json) = no_content.to_json().expect("didn't expect error response");
assert_eq!(status, StatusCode::NO_CONTENT);
assert_eq!(json, "");
}
#[test]
fn no_content_result()
{
let no_content = NoContent::default();
let res_def = no_content.to_json().expect("didn't expect error response");
let res_err = Result::<NoContent, MsgError>::Ok(no_content).to_json().expect("didn't expect error response");
assert_eq!(res_def, res_err);
} }
} }

View file

@ -1,6 +1,9 @@
extern crate proc_macro; extern crate proc_macro;
use proc_macro::TokenStream; use proc_macro::TokenStream;
use proc_macro2::TokenStream as TokenStream2;
use quote::quote;
use std::env;
mod method; mod method;
use method::{expand_method, Method}; use method::{expand_method, Method};
@ -9,6 +12,18 @@ use resource::expand_resource;
#[cfg(feature = "openapi")] #[cfg(feature = "openapi")]
mod openapi_type; mod openapi_type;
fn krate() -> TokenStream2
{
if env::var("CARGO_PKG_NAME").unwrap() == "gotham_restful"
{
quote!(crate)
}
else
{
quote!(::gotham_restful)
}
}
#[cfg(feature = "openapi")] #[cfg(feature = "openapi")]
#[proc_macro_derive(OpenapiType)] #[proc_macro_derive(OpenapiType)]
pub fn derive_openapi_type(tokens : TokenStream) -> TokenStream pub fn derive_openapi_type(tokens : TokenStream) -> TokenStream

View file

@ -84,11 +84,12 @@ impl Method
pub fn expand_method(method : Method, attrs : TokenStream, item : TokenStream) -> TokenStream pub fn expand_method(method : Method, attrs : TokenStream, item : TokenStream) -> TokenStream
{ {
let krate = super::krate();
let ident = parse_macro_input!(attrs as Ident); let ident = parse_macro_input!(attrs as Ident);
let fun = parse_macro_input!(item as ItemFn); let fun = parse_macro_input!(item as ItemFn);
let (ret, is_no_content) = match fun.sig.output { let (ret, is_no_content) = match fun.sig.output {
ReturnType::Default => (quote!(::gotham_restful::NoContent), true), ReturnType::Default => (quote!(#krate::NoContent), true),
ReturnType::Type(_, ty) => (quote!(#ty), false) ReturnType::Type(_, ty) => (quote!(#ty), false)
}; };
let args : Vec<(TokenStream2, TokenStream2)> = fun.sig.inputs.iter().map(|arg| match arg { let args : Vec<(TokenStream2, TokenStream2)> = fun.sig.inputs.iter().map(|arg| match arg {
@ -103,15 +104,15 @@ pub fn expand_method(method : Method, attrs : TokenStream, item : TokenStream) -
generics.push(quote!(#ret)); generics.push(quote!(#ret));
let args : Vec<TokenStream2> = args.into_iter().map(|(pat, ty)| quote!(#pat : #ty)).collect(); let args : Vec<TokenStream2> = args.into_iter().map(|(pat, ty)| quote!(#pat : #ty)).collect();
let block = fun.block.stmts; let block = fun.block.stmts;
let ret_stmt = if is_no_content { Some(quote!(#ret::default())) } else { None }; let ret_stmt = if is_no_content { Some(quote!(Default::default())) } else { None };
let trait_ident = method.trait_ident(); let trait_ident = method.trait_ident();
let fn_ident = method.fn_ident(); let fn_ident = method.fn_ident();
let setup_ident = method.setup_ident(); let setup_ident = method.setup_ident();
let output = quote! { let output = quote! {
impl ::gotham_restful::#trait_ident<#(#generics),*> for #ident impl #krate::#trait_ident<#(#generics),*> for #ident
where #ident : ::gotham_restful::Resource where #ident : #krate::Resource
{ {
fn #fn_ident(#(#args),*) -> #ret fn #fn_ident(#(#args),*) -> #ret
{ {
@ -121,7 +122,7 @@ pub fn expand_method(method : Method, attrs : TokenStream, item : TokenStream) -
} }
#[deny(dead_code)] #[deny(dead_code)]
fn #setup_ident<D : ::gotham_restful::DrawResourceRoutes>(route : &mut D) fn #setup_ident<D : #krate::DrawResourceRoutes>(route : &mut D)
{ {
route.#fn_ident::<#ident, #(#generics),*>(); route.#fn_ident::<#ident, #(#generics),*>();
} }

View file

@ -114,6 +114,7 @@ fn expand_field(field : &Field) -> TokenStream2
pub fn expand_struct(input : ItemStruct) -> TokenStream2 pub fn expand_struct(input : ItemStruct) -> TokenStream2
{ {
let krate = super::krate();
let ident = input.ident; let ident = input.ident;
let generics = input.generics; let generics = input.generics;
@ -126,11 +127,11 @@ pub fn expand_struct(input : ItemStruct) -> TokenStream2
}; };
quote!{ quote!{
impl #generics ::gotham_restful::OpenapiType for #ident #generics impl #generics #krate::OpenapiType for #ident #generics
{ {
fn schema() -> ::gotham_restful::OpenapiSchema fn schema() -> #krate::OpenapiSchema
{ {
use ::gotham_restful::{export::{openapi::*, IndexMap}, OpenapiSchema}; use #krate::{export::{openapi::*, IndexMap}, OpenapiSchema};
let mut properties : IndexMap<String, ReferenceOr<Box<Schema>>> = IndexMap::new(); let mut properties : IndexMap<String, ReferenceOr<Box<Schema>>> = IndexMap::new();
let mut required : Vec<String> = Vec::new(); let mut required : Vec<String> = Vec::new();

View file

@ -28,6 +28,7 @@ impl Parse for MethodList
pub fn expand_resource(tokens : TokenStream) -> TokenStream pub fn expand_resource(tokens : TokenStream) -> TokenStream
{ {
let krate = super::krate();
let input = parse_macro_input!(tokens as ItemStruct); let input = parse_macro_input!(tokens as ItemStruct);
let ident = input.ident; let ident = input.ident;
@ -43,14 +44,14 @@ pub fn expand_resource(tokens : TokenStream) -> TokenStream
}).collect(); }).collect();
let output = quote! { let output = quote! {
impl ::gotham_restful::Resource for #ident impl #krate::Resource for #ident
{ {
fn name() -> String fn name() -> String
{ {
stringify!(#ident).to_string() stringify!(#ident).to_string()
} }
fn setup<D : ::gotham_restful::DrawResourceRoutes>(mut route : D) fn setup<D : #krate::DrawResourceRoutes>(mut route : D)
{ {
#(#methods)* #(#methods)*
} }