Add test for openapi3-compatible schema generation

This commit is contained in:
Graham Esau 2019-08-06 08:42:43 +01:00
parent 48465b51cf
commit 70c8d0f763
4 changed files with 216 additions and 7 deletions

View file

@ -262,6 +262,8 @@ map_impl!(<K: Eq + core::hash::Hash, V, H: core::hash::BuildHasher> MakeSchema f
impl<T: MakeSchema> MakeSchema for Option<T> { impl<T: MakeSchema> MakeSchema for Option<T> {
fn is_referenceable() -> bool { fn is_referenceable() -> bool {
// TODO only really needs to be referenceable with option_nullable enabled.
// TODO what if T is Box<U> and U is referenceable?
T::is_referenceable() T::is_referenceable()
} }
@ -279,10 +281,11 @@ impl<T: MakeSchema> MakeSchema for Option<T> {
} }
} }
if gen.settings().option_nullable { if gen.settings().option_nullable {
let mut deref = gen.try_get_schema_object(&schema); let deref = gen.try_get_schema_object(&schema);
debug_assert!(deref.is_some(), "Could not get schema object: {:?}", schema); debug_assert!(deref.is_some(), "Could not get schema object: {:?}", schema);
if let Some(ref mut schema) = deref { if let Some(mut deref) = deref {
schema.extensions.insert("nullable".to_owned(), json!(true)); deref.extensions.insert("nullable".to_owned(), json!(true));
schema = Schema::Object(deref);
} }
}; };
schema schema

View file

@ -4,8 +4,6 @@ use serde::{Deserialize, Serialize};
use serde_json::Value; use serde_json::Value;
use std::collections::BTreeMap as Map; use std::collections::BTreeMap as Map;
// TODO use serde_json::Map (or some other wrapper) instead of BTreeMap to ensure preserve_order is possible
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, MakeSchema)] #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, MakeSchema)]
#[serde(untagged)] #[serde(untagged)]
pub enum Schema { pub enum Schema {

View file

@ -0,0 +1,191 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "schemars__schema__Schema",
"anyOf": [
{
"type": "boolean"
},
{
"$ref": "#/components/schemas/schemars__schema__SchemaRef"
},
{
"$ref": "#/components/schemas/schemars__schema__SchemaObject"
}
],
"definitions": {
"core__option__Option_schemars__schema__SingleOrVec_schemars__schema__InstanceType__": {
"anyOf": [
{
"$ref": "#/components/schemas/schemars__schema__InstanceType"
},
{
"type": "array",
"items": {
"$ref": "#/components/schemas/schemars__schema__InstanceType"
}
}
],
"nullable": true
},
"core__option__Option_schemars__schema__SingleOrVec_schemars__schema__Schema__": {
"anyOf": [
{
"$ref": "#/components/schemas/schemars__schema__Schema"
},
{
"type": "array",
"items": {
"$ref": "#/components/schemas/schemars__schema__Schema"
}
}
],
"nullable": true
},
"schemars__schema__InstanceType": {
"enum": [
"null",
"boolean",
"object",
"array",
"number",
"string",
"integer"
]
},
"schemars__schema__Schema": {
"anyOf": [
{
"type": "boolean"
},
{
"$ref": "#/components/schemas/schemars__schema__SchemaRef"
},
{
"$ref": "#/components/schemas/schemars__schema__SchemaObject"
}
]
},
"schemars__schema__SchemaObject": {
"properties": {
"$id": {
"type": "string",
"nullable": true
},
"$schema": {
"type": "string",
"nullable": true
},
"allOf": {
"type": "array",
"items": {
"$ref": "#/components/schemas/schemars__schema__Schema"
},
"nullable": true
},
"anyOf": {
"type": "array",
"items": {
"$ref": "#/components/schemas/schemars__schema__Schema"
},
"nullable": true
},
"definitions": {
"type": "object",
"additionalProperties": {
"$ref": "#/components/schemas/schemars__schema__Schema"
}
},
"description": {
"type": "string",
"nullable": true
},
"enum": {
"type": "array",
"items": {},
"nullable": true
},
"extensions": {
"type": "object",
"additionalProperties": true
},
"items": {
"$ref": "#/components/schemas/core__option__Option_schemars__schema__SingleOrVec_schemars__schema__Schema__"
},
"not": {
"anyOf": [
{
"type": "boolean"
},
{
"$ref": "#/components/schemas/schemars__schema__SchemaRef"
},
{
"$ref": "#/components/schemas/schemars__schema__SchemaObject"
}
],
"nullable": true
},
"oneOf": {
"type": "array",
"items": {
"$ref": "#/components/schemas/schemars__schema__Schema"
},
"nullable": true
},
"properties": {
"type": "object",
"additionalProperties": {
"$ref": "#/components/schemas/schemars__schema__Schema"
}
},
"required": {
"type": "array",
"items": {
"type": "string"
},
"nullable": true
},
"title": {
"type": "string",
"nullable": true
},
"type": {
"$ref": "#/components/schemas/core__option__Option_schemars__schema__SingleOrVec_schemars__schema__InstanceType__"
}
}
},
"schemars__schema__SchemaRef": {
"properties": {
"$ref": {
"type": "string"
}
}
},
"schemars__schema__SingleOrVec_schemars__schema__InstanceType_": {
"anyOf": [
{
"$ref": "#/components/schemas/schemars__schema__InstanceType"
},
{
"type": "array",
"items": {
"$ref": "#/components/schemas/schemars__schema__InstanceType"
}
}
]
},
"schemars__schema__SingleOrVec_schemars__schema__Schema_": {
"anyOf": [
{
"$ref": "#/components/schemas/schemars__schema__Schema"
},
{
"type": "array",
"items": {
"$ref": "#/components/schemas/schemars__schema__Schema"
}
}
]
}
}
}

View file

@ -1,5 +1,5 @@
use schemars::schema::*; use schemars::schema::*;
use schemars::schema_for; use schemars::{gen, schema_for};
use serde_json::{from_str, to_string_pretty}; use serde_json::{from_str, to_string_pretty};
use std::fs; use std::fs;
@ -8,7 +8,7 @@ mod tests {
use super::*; use super::*;
#[test] #[test]
fn schema_matches() -> Result<(), Box<dyn std::error::Error>> { fn schema_matches_default_settings() -> Result<(), Box<dyn std::error::Error>> {
let expected_json = fs::read_to_string("tests/schema.json")?; let expected_json = fs::read_to_string("tests/schema.json")?;
let expected: Schema = from_str(&expected_json)?; let expected: Schema = from_str(&expected_json)?;
@ -18,4 +18,21 @@ mod tests {
assert_eq!(actual, expected, "\n\nGenerated schema did not match saved schema - generated schema has been written to \"tests/schema.actual.json\"."); assert_eq!(actual, expected, "\n\nGenerated schema did not match saved schema - generated schema has been written to \"tests/schema.actual.json\".");
Ok(()) Ok(())
} }
#[test]
fn schema_matches_openapi3() -> Result<(), Box<dyn std::error::Error>> {
let expected_json = fs::read_to_string("tests/schema-openapi3.json")?;
let expected: Schema = from_str(&expected_json)?;
let actual = gen::SchemaSettings::openapi3()
.into_generator()
.into_root_schema_for::<Schema>();
fs::write(
"tests/schema-openapi3.actual.json",
to_string_pretty(&actual)?,
)?;
assert_eq!(actual, expected, "\n\nGenerated schema did not match saved schema - generated schema has been written to \"tests/schema-openapi3.actual.json\".");
Ok(())
}
} }