From fbcc626478e125302110a6832aa3dbd56fd0c837 Mon Sep 17 00:00:00 2001 From: Dominic Date: Mon, 13 Apr 2020 02:46:01 +0200 Subject: [PATCH] write tests for the openapi types --- Cargo.toml | 1 + gotham_restful/Cargo.toml | 1 + gotham_restful/src/openapi/types.rs | 100 ++++++++++++++++++++++++---- 3 files changed, 88 insertions(+), 14 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 418c362..ce5a3ac 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,3 +10,4 @@ members = [ [patch.crates-io] gotham_restful = { path = "./gotham_restful" } gotham_restful_derive = { path = "./gotham_restful_derive" } +openapiv3 = { git = "https://github.com/glademiller/openapiv3", rev = "4c3bd95c966a3f9d59bb494c3d8e30c5c3068bdb" } \ No newline at end of file diff --git a/gotham_restful/Cargo.toml b/gotham_restful/Cargo.toml index acff902..4aad918 100644 --- a/gotham_restful/Cargo.toml +++ b/gotham_restful/Cargo.toml @@ -34,6 +34,7 @@ serde_json = "1.0.45" uuid = { version = ">= 0.1, < 0.9", optional = true } [dev-dependencies] +paste = "0.1.10" thiserror = "1" [features] diff --git a/gotham_restful/src/openapi/types.rs b/gotham_restful/src/openapi/types.rs index 3b29c59..5cbacce 100644 --- a/gotham_restful/src/openapi/types.rs +++ b/gotham_restful/src/openapi/types.rs @@ -4,8 +4,8 @@ use chrono::{ }; use indexmap::IndexMap; use openapiv3::{ - ArrayType, IntegerType, NumberType, ObjectType, ReferenceOr::Item, ReferenceOr::Reference, Schema, - SchemaData, SchemaKind, StringType, Type, VariantOrUnknownOrEmpty + AdditionalProperties, ArrayType, IntegerType, NumberFormat, NumberType, ObjectType, ReferenceOr::Item, + ReferenceOr::Reference, Schema, SchemaData, SchemaKind, StringType, Type, VariantOrUnknownOrEmpty }; #[cfg(feature = "uuid")] use uuid::Uuid; @@ -86,7 +86,10 @@ impl OpenapiType for () { fn schema() -> OpenapiSchema { - OpenapiSchema::new(SchemaKind::Type(Type::Object(ObjectType::default()))) + OpenapiSchema::new(SchemaKind::Type(Type::Object(ObjectType { + additional_properties: Some(AdditionalProperties::Any(false)), + ..Default::default() + }))) } } @@ -164,18 +167,21 @@ int_types!(bits = 128, i128); int_types!(unsigned bits = 128, u128); macro_rules! num_types { - ($($num_ty:ty),*) => {$( + ($($num_ty:ty = $num_fmt:ident),*) => {$( impl OpenapiType for $num_ty { fn schema() -> OpenapiSchema { - OpenapiSchema::new(SchemaKind::Type(Type::Number(NumberType::default()))) + OpenapiSchema::new(SchemaKind::Type(Type::Number(NumberType { + format: VariantOrUnknownOrEmpty::Item(NumberFormat::$num_fmt), + ..Default::default() + }))) } } )*} } -num_types!(f32, f64); +num_types!(f32 = Float, f64 = Double); macro_rules! str_types { ($($str_ty:ty),*) => {$( @@ -219,6 +225,14 @@ macro_rules! str_types { str_types!(String, &str); +#[cfg(feature = "chrono")] +str_types!(format = Date, Date, Date, Date, NaiveDate); +#[cfg(feature = "chrono")] +str_types!(format = DateTime, DateTime, DateTime, DateTime, NaiveDateTime); + +#[cfg(feature = "uuid")] +str_types!(format_str = "uuid", Uuid); + impl OpenapiType for Option { fn schema() -> OpenapiSchema @@ -290,14 +304,6 @@ impl OpenapiType for HashSet } } -#[cfg(feature = "chrono")] -str_types!(format = Date, Date, Date, Date, NaiveDate); -#[cfg(feature = "chrono")] -str_types!(format = DateTime, DateTime, DateTime, DateTime, NaiveDateTime); - -#[cfg(feature = "uuid")] -str_types!(format_str = "uuid", Uuid); - impl OpenapiType for serde_json::Value { fn schema() -> OpenapiSchema @@ -310,3 +316,69 @@ impl OpenapiType for serde_json::Value } } } + + +#[cfg(test)] +mod test +{ + use super::*; + use serde_json::Value; + + type Unit = (); + + macro_rules! assert_schema { + ($ty:ident $(<$generic:ident>)* => $json:expr) => { + paste::item! { + #[test] + fn []() + { + let schema = <$ty $(<$generic>)* as OpenapiType>::schema().into_schema(); + let schema_json = serde_json::to_string(&schema).expect(&format!("Unable to serialize schema for {}", stringify!($ty))); + assert_eq!(schema_json, $json); + } + } + }; + } + + assert_schema!(Unit => r#"{"type":"object","additionalProperties":false}"#); + assert_schema!(bool => r#"{"type":"boolean"}"#); + assert_schema!(isize => r#"{"type":"integer"}"#); + assert_schema!(usize => r#"{"type":"integer","minimum":0}"#); + assert_schema!(i8 => r#"{"type":"integer","format":"int8"}"#); + assert_schema!(u8 => r#"{"type":"integer","format":"int8","minimum":0}"#); + assert_schema!(i16 => r#"{"type":"integer","format":"int16"}"#); + assert_schema!(u16 => r#"{"type":"integer","format":"int16","minimum":0}"#); + assert_schema!(i32 => r#"{"type":"integer","format":"int32"}"#); + assert_schema!(u32 => r#"{"type":"integer","format":"int32","minimum":0}"#); + assert_schema!(i64 => r#"{"type":"integer","format":"int64"}"#); + assert_schema!(u64 => r#"{"type":"integer","format":"int64","minimum":0}"#); + assert_schema!(i128 => r#"{"type":"integer","format":"int128"}"#); + assert_schema!(u128 => r#"{"type":"integer","format":"int128","minimum":0}"#); + assert_schema!(f32 => r#"{"type":"number","format":"float"}"#); + assert_schema!(f64 => r#"{"type":"number","format":"double"}"#); + + assert_schema!(String => r#"{"type":"string"}"#); + #[cfg(feature = "chrono")] + assert_schema!(Date => r#"{"type":"string","format":"date"}"#); + #[cfg(feature = "chrono")] + assert_schema!(Date => r#"{"type":"string","format":"date"}"#); + #[cfg(feature = "chrono")] + assert_schema!(Date => r#"{"type":"string","format":"date"}"#); + #[cfg(feature = "chrono")] + assert_schema!(NaiveDate => r#"{"type":"string","format":"date"}"#); + #[cfg(feature = "chrono")] + assert_schema!(DateTime => r#"{"type":"string","format":"date-time"}"#); + #[cfg(feature = "chrono")] + assert_schema!(DateTime => r#"{"type":"string","format":"date-time"}"#); + #[cfg(feature = "chrono")] + assert_schema!(DateTime => r#"{"type":"string","format":"date-time"}"#); + #[cfg(feature = "chrono")] + assert_schema!(NaiveDateTime => r#"{"type":"string","format":"date-time"}"#); + #[cfg(feature = "uuid")] + assert_schema!(Uuid => r#"{"type":"string","format":"uuid"}"#); + + assert_schema!(Option => r#"{"nullable":true,"type":"string"}"#); + assert_schema!(Vec => r#"{"type":"array","items":{"type":"string"}}"#); + + assert_schema!(Value => r#"{"nullable":true}"#); +}