353 lines
8.5 KiB
Rust
353 lines
8.5 KiB
Rust
use crate::prelude::*;
|
|
use schemars::generate::SchemaSettings;
|
|
|
|
#[derive(JsonSchema, Deserialize, Serialize)]
|
|
struct EmptyStruct {}
|
|
|
|
#[derive(JsonSchema, Deserialize, Serialize)]
|
|
enum External1 {
|
|
Unit1,
|
|
Unit2,
|
|
}
|
|
|
|
#[derive(JsonSchema, Deserialize, Serialize)]
|
|
enum External2 {
|
|
Unit3,
|
|
ValueNewType(Value),
|
|
}
|
|
|
|
#[derive(JsonSchema, Deserialize, Serialize)]
|
|
enum External3 {
|
|
Int(u32),
|
|
Tuple(u8, bool),
|
|
}
|
|
|
|
#[derive(JsonSchema, Deserialize, Serialize)]
|
|
enum External4 {
|
|
StructNewType(EmptyStruct),
|
|
Struct { foo: i32, bar: bool },
|
|
}
|
|
|
|
#[derive(JsonSchema, Deserialize, Serialize)]
|
|
struct ExternalContainer {
|
|
f: f32,
|
|
#[serde(flatten)]
|
|
e1: External1,
|
|
#[serde(flatten)]
|
|
e2: External2,
|
|
#[serde(flatten)]
|
|
e3: External3,
|
|
#[serde(flatten)]
|
|
e4: External4,
|
|
}
|
|
|
|
impl ExternalContainer {
|
|
fn values() -> impl IntoIterator<Item = Self> {
|
|
[
|
|
Self {
|
|
f: 1.23,
|
|
e1: External1::Unit1,
|
|
e2: External2::Unit3,
|
|
e3: External3::Int(123),
|
|
e4: External4::StructNewType(EmptyStruct {}),
|
|
},
|
|
Self {
|
|
f: 9.87,
|
|
e1: External1::Unit2,
|
|
e2: External2::ValueNewType(json!({"key": "value"})),
|
|
e3: External3::Tuple(0, true),
|
|
e4: External4::Struct { foo: 1, bar: true },
|
|
},
|
|
]
|
|
}
|
|
}
|
|
|
|
#[derive(JsonSchema, Deserialize, Serialize)]
|
|
#[serde(deny_unknown_fields)]
|
|
struct ExternalContainerDenyUnknownFields {
|
|
f: f32,
|
|
#[serde(flatten)]
|
|
e1: External1,
|
|
#[serde(flatten)]
|
|
e2: External2,
|
|
#[serde(flatten)]
|
|
e3: External3,
|
|
#[serde(flatten)]
|
|
e4: External4,
|
|
}
|
|
|
|
impl ExternalContainerDenyUnknownFields {
|
|
fn values() -> impl IntoIterator<Item = Self> {
|
|
[
|
|
Self {
|
|
f: 1.23,
|
|
e1: External1::Unit1,
|
|
e2: External2::Unit3,
|
|
e3: External3::Int(123),
|
|
e4: External4::StructNewType(EmptyStruct {}),
|
|
},
|
|
Self {
|
|
f: 9.87,
|
|
e1: External1::Unit2,
|
|
e2: External2::ValueNewType(json!({"key": "value"})),
|
|
e3: External3::Tuple(0, true),
|
|
e4: External4::Struct { foo: 1, bar: true },
|
|
},
|
|
]
|
|
}
|
|
}
|
|
|
|
fn external_container_json_with_extra_field() -> Value {
|
|
json!({
|
|
"f": 1.23,
|
|
"Unit1": null,
|
|
"Unit3": null,
|
|
"Int": 123,
|
|
"StructNewType": {},
|
|
"extra": null
|
|
})
|
|
}
|
|
|
|
#[test]
|
|
fn external_enums_flattened() {
|
|
test!(ExternalContainer)
|
|
.assert_snapshot()
|
|
.assert_allows_ser_roundtrip(ExternalContainer::values())
|
|
.assert_matches_de_roundtrip(arbitrary_values())
|
|
.assert_allows_de_roundtrip([external_container_json_with_extra_field()]);
|
|
}
|
|
|
|
#[test]
|
|
fn external_enums_flattened_deny_unknown_fields() {
|
|
test!(ExternalContainerDenyUnknownFields)
|
|
.assert_snapshot()
|
|
.assert_allows_ser_roundtrip(ExternalContainerDenyUnknownFields::values())
|
|
.assert_matches_de_roundtrip(arbitrary_values())
|
|
.assert_rejects_de([external_container_json_with_extra_field()]);
|
|
}
|
|
|
|
#[test]
|
|
fn external_enums_flattened_deny_unknown_fields_draft07() {
|
|
test!(
|
|
ExternalContainerDenyUnknownFields,
|
|
SchemaSettings::draft07()
|
|
)
|
|
.assert_snapshot()
|
|
.assert_allows_ser_roundtrip(ExternalContainerDenyUnknownFields::values())
|
|
.assert_matches_de_roundtrip(arbitrary_values())
|
|
.assert_rejects_de([external_container_json_with_extra_field()]);
|
|
}
|
|
|
|
#[derive(JsonSchema, Deserialize, Serialize)]
|
|
#[serde(tag = "tag1")]
|
|
enum Internal1 {
|
|
Unit1,
|
|
Unit2,
|
|
}
|
|
|
|
#[derive(JsonSchema, Deserialize, Serialize)]
|
|
#[serde(tag = "tag2")]
|
|
enum Internal2 {
|
|
Unit3,
|
|
ValueNewType(Value),
|
|
}
|
|
|
|
#[derive(JsonSchema, Deserialize, Serialize)]
|
|
#[serde(tag = "tag3")]
|
|
enum Internal3 {
|
|
StructNewType(EmptyStruct),
|
|
Struct { foo: i32, bar: bool },
|
|
}
|
|
|
|
#[derive(JsonSchema, Deserialize, Serialize)]
|
|
struct InternalContainer {
|
|
f: f32,
|
|
#[serde(flatten)]
|
|
e1: Internal1,
|
|
#[serde(flatten)]
|
|
e2: Internal2,
|
|
#[serde(flatten)]
|
|
e3: Internal3,
|
|
}
|
|
|
|
impl InternalContainer {
|
|
fn values() -> impl IntoIterator<Item = Self> {
|
|
[
|
|
Self {
|
|
f: 1.23,
|
|
e1: Internal1::Unit1,
|
|
e2: Internal2::Unit3,
|
|
e3: Internal3::StructNewType(EmptyStruct {}),
|
|
},
|
|
Self {
|
|
f: 9.87,
|
|
e1: Internal1::Unit2,
|
|
e2: Internal2::ValueNewType(json!({"key": "value"})),
|
|
e3: Internal3::Struct { foo: 1, bar: true },
|
|
},
|
|
]
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn internal_enums_flattened() {
|
|
test!(InternalContainer)
|
|
.assert_snapshot()
|
|
.assert_allows_ser_roundtrip(InternalContainer::values())
|
|
.assert_matches_de_roundtrip(arbitrary_values());
|
|
}
|
|
|
|
#[derive(JsonSchema, Deserialize, Serialize)]
|
|
#[serde(tag = "tag1", content = "content1")]
|
|
enum Adjacent1 {
|
|
Unit1,
|
|
Unit2,
|
|
}
|
|
|
|
#[derive(JsonSchema, Deserialize, Serialize)]
|
|
#[serde(tag = "tag2", content = "content2")]
|
|
enum Adjacent2 {
|
|
Unit3,
|
|
ValueNewType(Value),
|
|
}
|
|
|
|
#[derive(JsonSchema, Deserialize, Serialize)]
|
|
#[serde(tag = "tag3", content = "content3")]
|
|
enum Adjacent3 {
|
|
Int(u32),
|
|
Tuple(u8, bool),
|
|
}
|
|
|
|
#[derive(JsonSchema, Deserialize, Serialize)]
|
|
#[serde(tag = "tag4", content = "content4")]
|
|
enum Adjacent4 {
|
|
StructNewType(EmptyStruct),
|
|
Struct { foo: i32, bar: bool },
|
|
}
|
|
|
|
#[derive(JsonSchema, Deserialize, Serialize)]
|
|
struct AdjacentContainer {
|
|
f: f32,
|
|
#[serde(flatten)]
|
|
e1: Adjacent1,
|
|
#[serde(flatten)]
|
|
e2: Adjacent2,
|
|
#[serde(flatten)]
|
|
e3: Adjacent3,
|
|
#[serde(flatten)]
|
|
e4: Adjacent4,
|
|
}
|
|
|
|
impl AdjacentContainer {
|
|
fn values() -> impl IntoIterator<Item = Self> {
|
|
[
|
|
Self {
|
|
f: 1.23,
|
|
e1: Adjacent1::Unit1,
|
|
e2: Adjacent2::Unit3,
|
|
e3: Adjacent3::Int(123),
|
|
e4: Adjacent4::StructNewType(EmptyStruct {}),
|
|
},
|
|
Self {
|
|
f: 9.87,
|
|
e1: Adjacent1::Unit2,
|
|
e2: Adjacent2::ValueNewType(json!({"key": "value"})),
|
|
e3: Adjacent3::Tuple(0, true),
|
|
e4: Adjacent4::Struct { foo: 1, bar: true },
|
|
},
|
|
]
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn adjacent_enums_flattened() {
|
|
test!(AdjacentContainer)
|
|
.assert_snapshot()
|
|
.assert_allows_ser_roundtrip(AdjacentContainer::values())
|
|
.assert_matches_de_roundtrip(arbitrary_values());
|
|
}
|
|
|
|
#[derive(JsonSchema, Deserialize, Serialize)]
|
|
#[serde(untagged)]
|
|
enum Untagged {
|
|
Struct1 { foo: i32 },
|
|
Struct2 { bar: bool },
|
|
ValueNewType(Value),
|
|
}
|
|
|
|
#[derive(JsonSchema, Deserialize, Serialize)]
|
|
struct UntaggedContainer {
|
|
f: f32,
|
|
#[serde(flatten)]
|
|
e1: Untagged,
|
|
}
|
|
|
|
impl UntaggedContainer {
|
|
fn values() -> impl IntoIterator<Item = Self> {
|
|
[
|
|
Self {
|
|
f: 1.23,
|
|
e1: Untagged::Struct1 { foo: 1 },
|
|
},
|
|
Self {
|
|
f: 9.87,
|
|
e1: Untagged::Struct2 { bar: true },
|
|
},
|
|
Self {
|
|
f: 42.0,
|
|
e1: Untagged::ValueNewType(json!({"key": "value"})),
|
|
},
|
|
]
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn untagged_enums_flattened() {
|
|
test!(UntaggedContainer)
|
|
.assert_snapshot()
|
|
.assert_allows_ser_roundtrip(UntaggedContainer::values())
|
|
.assert_matches_de_roundtrip(arbitrary_values());
|
|
}
|
|
|
|
#[derive(JsonSchema, Deserialize, Serialize)]
|
|
struct MixedContainer {
|
|
f: f32,
|
|
#[serde(flatten)]
|
|
e1: External1,
|
|
#[serde(flatten)]
|
|
i2: Internal2,
|
|
#[serde(flatten)]
|
|
a3: Adjacent3,
|
|
#[serde(flatten)]
|
|
u: Untagged,
|
|
}
|
|
|
|
impl MixedContainer {
|
|
fn values() -> impl IntoIterator<Item = Self> {
|
|
[
|
|
Self {
|
|
f: 1.23,
|
|
e1: External1::Unit1,
|
|
i2: Internal2::Unit3,
|
|
a3: Adjacent3::Int(123),
|
|
u: Untagged::Struct1 { foo: 1 },
|
|
},
|
|
Self {
|
|
f: 9.87,
|
|
e1: External1::Unit2,
|
|
i2: Internal2::ValueNewType(json!({"key": "value"})),
|
|
a3: Adjacent3::Tuple(0, true),
|
|
u: Untagged::ValueNewType(json!({"key": "value"})),
|
|
},
|
|
]
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn mixed_enums_flattened() {
|
|
test!(MixedContainer)
|
|
.assert_snapshot()
|
|
.assert_allows_ser_roundtrip(MixedContainer::values())
|
|
.assert_matches_de_roundtrip(arbitrary_values());
|
|
}
|