diff --git a/utoipa-gen/CHANGELOG.md b/utoipa-gen/CHANGELOG.md index 2a648045..086a4ca8 100644 --- a/utoipa-gen/CHANGELOG.md +++ b/utoipa-gen/CHANGELOG.md @@ -10,6 +10,7 @@ * Add quote_diagnostics! and quote_diagnostics_spanned! macros (https://github.com/juhaku/utoipa/pull/1553) * feat(gen): support Display types for security scopes (https://github.com/juhaku/utoipa/pull/1463) * Emit `title` and `default` on `RefBuilder` instead of wrapping in `oneOf` when `Option<_>` is non-nullable (https://github.com/juhaku/utoipa/pull/1380) +* Support untagged variants in enums (https://github.com/juhaku/utoipa/pull/1585) ### Changed diff --git a/utoipa-gen/src/component/schema.rs b/utoipa-gen/src/component/schema.rs index 191b59c4..3f905310 100644 --- a/utoipa-gen/src/component/schema.rs +++ b/utoipa-gen/src/component/schema.rs @@ -855,10 +855,20 @@ impl<'e> EnumSchema<'e> { parent: &'e Root<'e>, variants: &'e Punctuated, ) -> Result { - if variants + let variants_without_skipped = variants .iter() - .all(|variant| matches!(variant.fields, Fields::Unit)) - { + .filter_map(|variant| match serde::parse_value(&variant.attrs) { + Ok(rules) if rules.skip => None, + Ok(rules) => Some(Ok((variant, rules))), + Err(diagnostics) => Some(Err(diagnostics)), + }) + .collect::, Diagnostics>>()?; + + let all_unit_not_partially_tagged = variants_without_skipped + .iter() + .all(|(variant, rules)| matches!(variant.fields, Fields::Unit) && !rules.untagged); + + if all_unit_not_partially_tagged { #[cfg(feature = "repr")] let mut features = { if parent @@ -902,7 +912,7 @@ impl<'e> EnumSchema<'e> { } Ok(Self { - schema_type: EnumSchemaType::Plain(PlainEnum::new(parent, variants, features)?), + schema_type: EnumSchemaType::Plain(PlainEnum::new(parent, variants_without_skipped, features)?), schema_as, schema_references: Vec::new(), bound, @@ -919,7 +929,7 @@ impl<'e> EnumSchema<'e> { if parent.attributes.has_deprecated() { enum_features.push(Feature::Deprecated(true.into())) } - let mut mixed_enum = MixedEnum::new(parent, variants, enum_features)?; + let mut mixed_enum = MixedEnum::new(parent, variants_without_skipped, enum_features)?; let schema_references = std::mem::take(&mut mixed_enum.schema_references); Ok(Self { schema_type: EnumSchemaType::Mixed(mixed_enum), diff --git a/utoipa-gen/src/component/schema/enums.rs b/utoipa-gen/src/component/schema/enums.rs index 59a8b2da..8fa50c5a 100644 --- a/utoipa-gen/src/component/schema/enums.rs +++ b/utoipa-gen/src/component/schema/enums.rs @@ -45,7 +45,7 @@ pub struct PlainEnum<'e> { impl<'e> PlainEnum<'e> { pub fn new( root: &'e Root, - variants: &Punctuated, + variants_without_skipped: Vec<(&'e Variant, SerdeValue)>, mut features: Vec, ) -> Result { #[cfg(feature = "repr")] @@ -58,21 +58,7 @@ impl<'e> PlainEnum<'e> { let description = pop_feature!(features => Feature::Description(_) as Option); let container_rules = serde::parse_container(root.attributes)?; - let variants_iter = variants - .iter() - .map(|variant| match serde::parse_value(&variant.attrs) { - Ok(variant_rules) => Ok((variant, variant_rules)), - Err(diagnostics) => Err(diagnostics), - }) - .collect::, Diagnostics>>()? - .into_iter() - .filter_map(|(variant, variant_rules)| { - if variant_rules.skip { - None - } else { - Some((variant, variant_rules)) - } - }); + let variants_iter = variants_without_skipped.into_iter(); let enum_variant = match repr_type_path { Some(repr_type_path) => PlainEnumRepr::Repr( @@ -247,7 +233,7 @@ pub struct MixedEnum<'p> { impl<'p> MixedEnum<'p> { pub fn new( root: &'p Root, - variants: &Punctuated, + variants_without_skipped: Vec<(&'p Variant, SerdeValue)>, mut features: Vec, ) -> Result { let attributes = root.attributes; @@ -257,58 +243,35 @@ impl<'p> MixedEnum<'p> { let description = pop_feature!(features => Feature::Description(_) as Option); let discriminator = pop_feature!(features => Feature::Discriminator(_)); - let variants = variants - .iter() - .map(|variant| match serde::parse_value(&variant.attrs) { - Ok(variant_rules) => Ok((variant, variant_rules)), - Err(diagnostics) => Err(diagnostics), - }) - .collect::, Diagnostics>>()? + let variants = variants_without_skipped .into_iter() - .filter_map(|(variant, variant_rules)| { - if variant_rules.skip { - None - } else { - let variant_features = match &variant.fields { - Fields::Named(_) => { - match variant - .attrs - .parse_features::() - { - Ok(features) => features.into_inner().unwrap_or_default(), - Err(diagnostics) => return Some(Err(diagnostics)), - } - } - Fields::Unnamed(_) => { - match variant - .attrs - .parse_features::() - { - Ok(features) => features.into_inner().unwrap_or_default(), - Err(diagnostics) => return Some(Err(diagnostics)), - } - } - Fields::Unit => { - let parse_unit_features = - features::parse_schema_features_with(&variant.attrs, |input| { - Ok(parse_features!( - input as Title, - Rename, - Example, - Examples, - Deprecated - )) - }); - - match parse_unit_features { - Ok(features) => features.unwrap_or_default(), - Err(diagnostics) => return Some(Err(diagnostics)), - } - } - }; - - Some(Ok((variant, variant_rules, variant_features))) - } + .map(|(variant, variant_rules)| { + let variant_features = match &variant.fields { + Fields::Named(_) => variant + .attrs + .parse_features::()? + .into_inner() + .unwrap_or_default(), + Fields::Unnamed(_) => variant + .attrs + .parse_features::()? + .into_inner() + .unwrap_or_default(), + Fields::Unit => { + features::parse_schema_features_with(&variant.attrs, |input| { + Ok(parse_features!( + input as Title, + Rename, + Example, + Examples, + Deprecated + )) + })? + .unwrap_or_default() + } + }; + + Ok((variant, variant_rules, variant_features)) }) .collect::, Diagnostics>>()?; @@ -499,7 +462,13 @@ impl MixedEnumContent { generics: root.generics, }; - let tokens_with_schema_references = match &serde_container.enum_repr { + let enum_repr = if variant_serde_rules.untagged { + &SerdeEnumRepr::Untagged + } else { + &serde_container.enum_repr + }; + + let tokens_with_schema_references = match enum_repr { SerdeEnumRepr::ExternallyTagged => { let (enum_features, variant_features) = MixedEnumContent::split_enum_features(variant_features); @@ -596,7 +565,13 @@ impl MixedEnumContent { generics: root.generics, }; - let tokens_with_schema_reference = match &serde_container.enum_repr { + let enum_repr = if variant_serde_rules.untagged { + &SerdeEnumRepr::Untagged + } else { + &serde_container.enum_repr + }; + + let tokens_with_schema_reference = match enum_repr { SerdeEnumRepr::ExternallyTagged => { let (enum_features, variant_features) = MixedEnumContent::split_enum_features(variant_features); @@ -682,7 +657,13 @@ impl MixedEnumContent { ); let name = renamed.unwrap_or(Cow::Owned(name)); - match &serde_container.enum_repr { + let enum_repr = if variant_serde_rules.untagged { + &SerdeEnumRepr::Untagged + } else { + &serde_container.enum_repr + }; + + match enum_repr { SerdeEnumRepr::ExternallyTagged => EnumSchema::::new(name.as_ref()) .features(variant_features) .to_token_stream(), diff --git a/utoipa-gen/src/component/serde.rs b/utoipa-gen/src/component/serde.rs index e20c6136..1a83a1df 100644 --- a/utoipa-gen/src/component/serde.rs +++ b/utoipa-gen/src/component/serde.rs @@ -29,6 +29,7 @@ pub struct SerdeValue { pub rename: Option, pub default: bool, pub flatten: bool, + pub untagged: bool, pub skip_serializing_if: bool, pub double_option: bool, } @@ -67,6 +68,7 @@ impl SerdeValue { .unwrap_or(false); } TokenTree::Ident(ident) if ident == "flatten" => value.flatten = true, + TokenTree::Ident(ident) if ident == "untagged" => value.untagged = true, TokenTree::Ident(ident) if ident == "rename" => { if let Some((literal, _)) = parse_next_lit_str(next) { value.rename = Some(literal) @@ -241,6 +243,9 @@ pub fn parse_value(attributes: &[Attribute]) -> Result if value.flatten { acc.flatten = value.flatten; } + if value.untagged { + acc.untagged = value.untagged; + } if value.default { acc.default = value.default; } diff --git a/utoipa-gen/src/lib.rs b/utoipa-gen/src/lib.rs index 3c7dffd5..9828afe6 100644 --- a/utoipa-gen/src/lib.rs +++ b/utoipa-gen/src/lib.rs @@ -486,8 +486,9 @@ static CONFIG: once_cell::sync::Lazy = /// * `content = "..."` Supported at the container level, allows [adjacently-tagged enums](https://serde.rs/enum-representations.html#adjacently-tagged). /// This attribute requires that a `tag` is present, otherwise serde will trigger a compile-time /// failure. -/// * `untagged` Supported at the container level. Allows [untagged -/// enum representation](https://serde.rs/enum-representations.html#untagged). +/// * `untagged` Supported at the container level for [untagged enum +/// representation](https://serde.rs/enum-representations.html#untagged) and at the [variant +/// level](https://serde.rs/variant-attrs.html#untagged) for untagged variants. /// * `default` Supported at the container level and field level according to [serde attributes]. /// * `deny_unknown_fields` Supported at the container level. /// * `flatten` Supported at the field level. diff --git a/utoipa-gen/tests/schema_derive_test.rs b/utoipa-gen/tests/schema_derive_test.rs index 459fbea8..53267b18 100644 --- a/utoipa-gen/tests/schema_derive_test.rs +++ b/utoipa-gen/tests/schema_derive_test.rs @@ -1,7 +1,7 @@ use std::{borrow::Cow, cell::RefCell, collections::HashMap, marker::PhantomData}; use insta::assert_json_snapshot; -use serde::Serialize; +use serde::{Deserialize, Serialize}; use serde_json::Value; use utoipa::openapi::{Object, ObjectBuilder}; use utoipa::{OpenApi, ToSchema}; @@ -1283,6 +1283,778 @@ fn derive_mixed_enum_with_ref_serde_untagged_named_fields() { assert_json_snapshot!(value); } +#[test] +fn derive_mixed_enum_serde_partially_untagged() { + #[derive(Serialize)] + enum Foo { + One, + #[serde(untagged)] + Two(String), + } + + let value: Value = api_doc! { + #[derive(Serialize)] + enum Foo { + One, + #[serde(untagged)] + Two(String), + } + }; + + assert_eq!(serde_json::to_string(&Foo::One).unwrap(), r#""One""#); + assert_eq!( + serde_json::to_string(&Foo::Two("baz".into())).unwrap(), + r#""baz""# + ); + + assert_json_snapshot!(value); +} + +#[test] +fn derive_mixed_enum_serde_partially_internally_tagged() { + #[derive(Serialize)] + #[serde(tag = "type")] + enum Foo { + One, + #[serde(untagged)] + Two(String), + } + + let value: Value = api_doc! { + #[derive(Serialize)] + #[serde(tag = "type")] + enum Foo { + One, + #[serde(untagged)] + Two(String), + } + }; + + assert_eq!( + serde_json::to_string(&Foo::One).unwrap(), + r#"{"type":"One"}"# + ); + assert_eq!( + serde_json::to_string(&Foo::Two("baz".into())).unwrap(), + r#""baz""# + ); + + assert_json_snapshot!(value); +} + +#[test] +fn derive_mixed_enum_serde_partially_adjacently_tagged() { + #[derive(Serialize)] + #[serde(tag = "type", content = "content")] + enum Foo { + One, + #[serde(untagged)] + Two(String), + } + + let value: Value = api_doc! { + #[derive(Serialize)] + #[serde(tag = "type", content = "content")] + enum Foo { + One, + #[serde(untagged)] + Two(String), + } + }; + + assert_eq!( + serde_json::to_string(&Foo::One).unwrap(), + r#"{"type":"One"}"# + ); + assert_eq!( + serde_json::to_string(&Foo::Two("baz".into())).unwrap(), + r#""baz""# + ); + + assert_json_snapshot!(value); +} + +#[test] +fn derive_mixed_enum_serde_partially_untagged_named_fields() { + #[derive(Serialize)] + enum Foo { + One { + n: i32, + }, + #[serde(untagged)] + Two { + m: i32, + }, + } + + let value: Value = api_doc! { + #[derive(Serialize)] + enum Foo { + One { n: i32 }, + #[serde(untagged)] + Two { m: i32 }, + } + }; + + assert_eq!( + serde_json::to_string(&Foo::One { n: 3 }).unwrap(), + r#"{"One":{"n":3}}"# + ); + assert_eq!( + serde_json::to_string(&Foo::Two { m: 3 }).unwrap(), + r#"{"m":3}"# + ); + + assert_json_snapshot!(value); +} + +#[test] +fn derive_mixed_enum_serde_partially_internally_tagged_named_fields() { + #[derive(Serialize)] + #[serde(tag = "type")] + enum Foo { + One { + n: i32, + }, + #[serde(untagged)] + Two { + m: i32, + }, + } + + let value: Value = api_doc! { + #[derive(Serialize)] + #[serde(tag = "type")] + enum Foo { + One { n: i32 }, + #[serde(untagged)] + Two { m: i32 }, + } + }; + + assert_eq!( + serde_json::to_string(&Foo::One { n: 3 }).unwrap(), + r#"{"type":"One","n":3}"# + ); + assert_eq!( + serde_json::to_string(&Foo::Two { m: 3 }).unwrap(), + r#"{"m":3}"# + ); + + assert_json_snapshot!(value); +} + +#[test] +fn derive_mixed_enum_serde_partially_adjacently_tagged_named_fields() { + #[derive(Serialize)] + #[serde(tag = "type", content = "content")] + enum Foo { + One { + n: i32, + }, + #[serde(untagged)] + Two { + m: i32, + }, + } + + let value: Value = api_doc! { + #[derive(Serialize)] + #[serde(tag = "type", content = "content")] + enum Foo { + One { n: i32 }, + #[serde(untagged)] + Two { m: i32 }, + } + }; + + assert_eq!( + serde_json::to_string(&Foo::One { n: 3 }).unwrap(), + r#"{"type":"One","content":{"n":3}}"# + ); + assert_eq!( + serde_json::to_string(&Foo::Two { m: 3 }).unwrap(), + r#"{"m":3}"# + ); + + assert_json_snapshot!(value); +} + +#[test] +fn derive_mixed_enum_serde_partially_untagged_unit_variant() { + #[derive(Serialize)] + enum Foo { + One { + n: i32, + }, + #[serde(untagged)] + Two, + } + + let value: Value = api_doc! { + #[derive(Serialize)] + enum Foo { + One { n: i32 }, + #[serde(untagged)] + Two, + } + }; + + assert_eq!( + serde_json::to_string(&Foo::One { n: 3 }).unwrap(), + r#"{"One":{"n":3}}"# + ); + assert_eq!(serde_json::to_string(&Foo::Two).unwrap(), r#"null"#); + + assert_json_snapshot!(value); +} + +#[test] +fn derive_mixed_enum_serde_partially_internally_tagged_unit_variant() { + #[derive(Serialize)] + #[serde(tag = "type")] + enum Foo { + One { + n: i32, + }, + #[serde(untagged)] + Two, + } + + let value: Value = api_doc! { + #[derive(Serialize)] + #[serde(tag = "type")] + enum Foo { + One { n: i32 }, + #[serde(untagged)] + Two, + } + }; + + assert_eq!( + serde_json::to_string(&Foo::One { n: 3 }).unwrap(), + r#"{"type":"One","n":3}"# + ); + assert_eq!(serde_json::to_string(&Foo::Two).unwrap(), r#"null"#); + + assert_json_snapshot!(value); +} + +#[test] +fn derive_mixed_enum_serde_partially_adjacently_tagged_unit_variant() { + #[derive(Serialize)] + #[serde(tag = "type", content = "content")] + enum Foo { + One { + n: i32, + }, + #[serde(untagged)] + Two, + } + + let value: Value = api_doc! { + #[derive(Serialize)] + #[serde(tag = "type", content = "content")] + enum Foo { + One { n: i32 }, + #[serde(untagged)] + Two, + } + }; + + assert_eq!( + serde_json::to_string(&Foo::One { n: 3 }).unwrap(), + r#"{"type":"One","content":{"n":3}}"# + ); + assert_eq!(serde_json::to_string(&Foo::Two).unwrap(), r#"null"#); + + assert_json_snapshot!(value); +} + +#[test] +fn derive_mixed_enum_with_ref_serde_partially_untagged_named_fields() { + #[derive(Serialize, ToSchema)] + struct Bar { + name: String, + age: u32, + } + + #[derive(Serialize)] + enum Foo { + One { + n: i32, + }, + #[serde(untagged)] + Two { + bar: Bar, + }, + } + + let value: Value = api_doc! { + #[derive(Serialize)] + enum Foo { + One { n: i32 }, + #[serde(untagged)] + Two { bar: Bar }, + } + }; + + assert_eq!( + serde_json::to_string(&Foo::One { n: 3 }).unwrap(), + r#"{"One":{"n":3}}"# + ); + assert_eq!( + serde_json::to_string(&Foo::Two { + bar: Bar { + name: "baz".into(), + age: 13 + } + }) + .unwrap(), + r#"{"bar":{"name":"baz","age":13}}"# + ); + + assert_json_snapshot!(value); +} + +#[test] +fn derive_mixed_enum_with_ref_serde_partially_internally_tagged_named_fields() { + #[derive(Serialize, ToSchema)] + struct Bar { + name: String, + age: u32, + } + + #[derive(Serialize)] + #[serde(tag = "type")] + enum Foo { + One { + n: i32, + }, + #[serde(untagged)] + Two { + bar: Bar, + }, + } + + let value: Value = api_doc! { + #[derive(Serialize)] + #[serde(tag = "type")] + enum Foo { + One { n: i32 }, + #[serde(untagged)] + Two { bar: Bar }, + } + }; + + assert_eq!( + serde_json::to_string(&Foo::One { n: 3 }).unwrap(), + r#"{"type":"One","n":3}"# + ); + assert_eq!( + serde_json::to_string(&Foo::Two { + bar: Bar { + name: "baz".into(), + age: 13 + } + }) + .unwrap(), + r#"{"bar":{"name":"baz","age":13}}"# + ); + + assert_json_snapshot!(value); +} + +#[test] +fn derive_mixed_enum_with_ref_serde_partially_adjacently_tagged_named_fields() { + #[derive(Serialize, ToSchema)] + struct Bar { + name: String, + age: u32, + } + + #[derive(Serialize)] + #[serde(tag = "type", content = "content")] + enum Foo { + One { + n: i32, + }, + #[serde(untagged)] + Two { + bar: Bar, + }, + } + + let value: Value = api_doc! { + #[derive(Serialize)] + #[serde(tag = "type", content = "content")] + enum Foo { + One { n: i32 }, + #[serde(untagged)] + Two { bar: Bar }, + } + }; + + assert_eq!( + serde_json::to_string(&Foo::One { n: 3 }).unwrap(), + r#"{"type":"One","content":{"n":3}}"# + ); + assert_eq!( + serde_json::to_string(&Foo::Two { + bar: Bar { + name: "baz".into(), + age: 13 + } + }) + .unwrap(), + r#"{"bar":{"name":"baz","age":13}}"# + ); + + assert_json_snapshot!(value); +} + +#[test] +fn derive_mixed_enum_with_enum_ref_serde_partially_untagged_named_fields() { + #[derive(Serialize, ToSchema)] + enum Bar { + Two { m: String }, + Three { o: u64 }, + } + + #[derive(Serialize)] + enum Foo { + One { + n: i32, + }, + #[serde(untagged)] + Other(Bar), + } + + let bar_value: Value = api_doc! { + #[derive(Serialize)] + enum Bar { + Two { m: String }, + Three { o: u64 }, + } + }; + let foo_value: Value = api_doc! { + #[derive(Serialize)] + enum Foo { + One { n: i32 }, + #[serde(untagged)] + Other(Bar), + } + }; + + assert_eq!( + serde_json::to_string(&Foo::One { n: 3 }).unwrap(), + r#"{"One":{"n":3}}"# + ); + assert_eq!( + serde_json::to_string(&Foo::Other(Bar::Two { m: "baz".into() })).unwrap(), + r#"{"Two":{"m":"baz"}}"# + ); + + assert_json_snapshot!(bar_value); + assert_json_snapshot!(foo_value); +} + +#[test] +fn derive_mixed_enum_with_enum_ref_serde_partially_internally_tagged_named_fields() { + #[derive(Serialize, ToSchema)] + enum Bar { + Two { m: String }, + Three { o: u64 }, + } + + #[derive(Serialize)] + #[serde(tag = "type")] + enum Foo { + One { + n: i32, + }, + #[serde(untagged)] + Other(Bar), + } + + let bar_value: Value = api_doc! { + #[derive(Serialize)] + enum Bar { + Two { m: String }, + Three { o: u64 }, + } + }; + let foo_value: Value = api_doc! { + #[derive(Serialize)] + #[serde(tag = "type")] + enum Foo { + One { n: i32 }, + #[serde(untagged)] + Other(Bar), + } + }; + + assert_eq!( + serde_json::to_string(&Foo::One { n: 3 }).unwrap(), + r#"{"type":"One","n":3}"# + ); + assert_eq!( + serde_json::to_string(&Foo::Other(Bar::Two { m: "baz".into() })).unwrap(), + r#"{"Two":{"m":"baz"}}"# + ); + + assert_json_snapshot!(bar_value); + assert_json_snapshot!(foo_value); +} + +#[test] +fn derive_mixed_enum_with_enum_ref_serde_partially_adjacently_tagged_named_fields() { + #[derive(Serialize, ToSchema)] + enum Bar { + Two { m: String }, + Three { o: u64 }, + } + + #[derive(Serialize)] + #[serde(tag = "type", content = "content")] + enum Foo { + One { + n: i32, + }, + #[serde(untagged)] + Other(Bar), + } + + let bar_value: Value = api_doc! { + #[derive(Serialize)] + enum Bar { + Two { m: String }, + Three { o: u64 }, + } + }; + let foo_value: Value = api_doc! { + #[derive(Serialize)] + #[serde(tag = "type", content = "content")] + enum Foo { + One { n: i32 }, + #[serde(untagged)] + Other(Bar), + } + }; + + assert_eq!( + serde_json::to_string(&Foo::One { n: 3 }).unwrap(), + r#"{"type":"One","content":{"n":3}}"# + ); + assert_eq!( + serde_json::to_string(&Foo::Other(Bar::Two { m: "baz".into() })).unwrap(), + r#"{"Two":{"m":"baz"}}"# + ); + + assert_json_snapshot!(bar_value); + assert_json_snapshot!(foo_value); +} + +#[test] +fn derive_unit_variants_serde_partially_untagged() { + #[derive(Serialize)] + enum Foo { + TaggedOne, + #[serde(untagged)] + UntaggedTwo, + } + + let value: Value = api_doc! { + #[derive(Serialize)] + enum Foo { + TaggedOne, + #[serde(untagged)] + UntaggedTwo, + } + }; + + assert_eq!( + serde_json::to_string(&Foo::TaggedOne).unwrap(), + r#""TaggedOne""# + ); + assert_eq!(serde_json::to_string(&Foo::UntaggedTwo).unwrap(), r#"null"#); + + assert_json_snapshot!(value); +} + +#[test] +fn derive_unit_variants_serde_mix_skip_untagged() { + #[derive(Serialize)] + enum Foo { + NormalOne, + #[serde(skip)] + SkipTwo(u8), + #[serde(untagged)] + UntaggedThree, + #[serde(untagged)] + UntaggedFour, + #[serde(skip, untagged)] + SkipUntaggedFive, + } + + let value: Value = api_doc! { + #[derive(Serialize)] + enum Foo { + NormalOne, + #[serde(skip)] + SkipTwo(u8), + #[serde(untagged)] + UntaggedThree, + #[serde(untagged)] + UntaggedFour, + #[serde(skip, untagged)] + SkipUntaggedFive, + } + }; + + assert_eq!( + serde_json::to_string(&Foo::NormalOne).unwrap(), + r#""NormalOne""# + ); + assert!(serde_json::to_string(&Foo::SkipTwo(42)).is_err()); + assert_eq!( + serde_json::to_string(&Foo::UntaggedThree).unwrap(), + r#"null"# + ); + assert!(serde_json::to_string(&Foo::SkipUntaggedFive).is_err()); + + assert_json_snapshot!(value); +} + +#[test] +fn derive_unit_variants_serde_skip_non_unit() { + #[derive(Serialize)] + enum Foo { + One, + Two, + #[serde(skip)] + Three(u8), + } + + let value: Value = api_doc! { + #[derive(Serialize)] + enum Foo { + One, + Two, + #[serde(skip)] + Three(u8), + } + }; + + assert_eq!(serde_json::to_string(&Foo::One).unwrap(), r#""One""#); + assert!(serde_json::to_string(&Foo::Three(42)).is_err()); + + assert_json_snapshot!(value); +} + +#[test] +fn derive_mixed_enum_serde_partially_untagged_partially_renamed() { + #[derive(Serialize, Deserialize)] + enum Foo { + #[serde(rename = "First")] + One, + #[serde(untagged)] + Two(usize), + } + + let value: Value = api_doc! { + #[derive(Serialize)] + enum Foo { + #[serde(rename = "First")] + One, + #[serde(untagged)] + Two(usize), + } + }; + + assert_eq!(serde_json::to_string(&Foo::One).unwrap(), "\"First\""); + assert_eq!(serde_json::to_string(&Foo::Two(5)).unwrap(), "5"); + assert!(matches!( + serde_json::from_str("\"First\"").unwrap(), + Foo::One + )); + assert!(matches!(serde_json::from_str("5").unwrap(), Foo::Two(5))); + + assert_json_snapshot!(value); +} + +#[test] +fn derive_mixed_enum_serde_partially_internally_tagged_partially_renamed() { + #[derive(Serialize, Deserialize)] + #[serde(tag = "type")] + enum Foo { + #[serde(rename = "First")] + One, + #[serde(untagged)] + Two(usize), + } + + let value: Value = api_doc! { + #[derive(Serialize)] + #[serde(tag = "type")] + enum Foo { + #[serde(rename = "First")] + One, + #[serde(untagged)] + Two(usize), + } + }; + + assert_eq!( + serde_json::to_string(&Foo::One).unwrap(), + r#"{"type":"First"}"# + ); + assert_eq!(serde_json::to_string(&Foo::Two(5)).unwrap(), "5"); + assert!(matches!( + serde_json::from_str(r#"{"type":"First"}"#).unwrap(), + Foo::One + )); + assert!(matches!(serde_json::from_str("5").unwrap(), Foo::Two(5))); + + assert_json_snapshot!(value); +} + +#[test] +fn derive_mixed_enum_serde_partially_adjacently_tagged_partially_renamed() { + #[derive(Serialize, Deserialize)] + #[serde(tag = "type", content = "content")] + enum Foo { + #[serde(rename = "First")] + One, + #[serde(untagged)] + Two(usize), + } + + let value: Value = api_doc! { + #[derive(Serialize)] + #[serde(tag = "type", content = "content")] + enum Foo { + #[serde(rename = "First")] + One, + #[serde(untagged)] + Two(usize), + } + }; + + assert_eq!( + serde_json::to_string(&Foo::One).unwrap(), + r#"{"type":"First"}"# + ); + assert_eq!(serde_json::to_string(&Foo::Two(5)).unwrap(), "5"); + assert!(matches!( + serde_json::from_str(r#"{"type":"First"}"#).unwrap(), + Foo::One + )); + assert!(matches!(serde_json::from_str("5").unwrap(), Foo::Two(5))); + + assert_json_snapshot!(value); +} + #[test] fn derive_mixed_enum_with_ref_serde_untagged_named_fields_rename_all() { #[derive(Serialize, ToSchema)] diff --git a/utoipa-gen/tests/snapshots/schema_derive_test__derive_mixed_enum_serde_partially_adjacently_tagged.snap b/utoipa-gen/tests/snapshots/schema_derive_test__derive_mixed_enum_serde_partially_adjacently_tagged.snap new file mode 100644 index 00000000..822da25b --- /dev/null +++ b/utoipa-gen/tests/snapshots/schema_derive_test__derive_mixed_enum_serde_partially_adjacently_tagged.snap @@ -0,0 +1,25 @@ +--- +source: utoipa-gen/tests/schema_derive_test.rs +expression: value +--- +{ + "oneOf": [ + { + "properties": { + "type": { + "enum": [ + "One" + ], + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + }, + { + "type": "string" + } + ] +} diff --git a/utoipa-gen/tests/snapshots/schema_derive_test__derive_mixed_enum_serde_partially_adjacently_tagged_named_fields.snap b/utoipa-gen/tests/snapshots/schema_derive_test__derive_mixed_enum_serde_partially_adjacently_tagged_named_fields.snap new file mode 100644 index 00000000..cba5a6cd --- /dev/null +++ b/utoipa-gen/tests/snapshots/schema_derive_test__derive_mixed_enum_serde_partially_adjacently_tagged_named_fields.snap @@ -0,0 +1,47 @@ +--- +source: utoipa-gen/tests/schema_derive_test.rs +expression: value +--- +{ + "oneOf": [ + { + "properties": { + "content": { + "properties": { + "n": { + "format": "int32", + "type": "integer" + } + }, + "required": [ + "n" + ], + "type": "object" + }, + "type": { + "enum": [ + "One" + ], + "type": "string" + } + }, + "required": [ + "content", + "type" + ], + "type": "object" + }, + { + "properties": { + "m": { + "format": "int32", + "type": "integer" + } + }, + "required": [ + "m" + ], + "type": "object" + } + ] +} diff --git a/utoipa-gen/tests/snapshots/schema_derive_test__derive_mixed_enum_serde_partially_adjacently_tagged_partially_renamed.snap b/utoipa-gen/tests/snapshots/schema_derive_test__derive_mixed_enum_serde_partially_adjacently_tagged_partially_renamed.snap new file mode 100644 index 00000000..29a54fa7 --- /dev/null +++ b/utoipa-gen/tests/snapshots/schema_derive_test__derive_mixed_enum_serde_partially_adjacently_tagged_partially_renamed.snap @@ -0,0 +1,26 @@ +--- +source: utoipa-gen/tests/schema_derive_test.rs +expression: value +--- +{ + "oneOf": [ + { + "properties": { + "type": { + "enum": [ + "First" + ], + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + }, + { + "minimum": 0, + "type": "integer" + } + ] +} diff --git a/utoipa-gen/tests/snapshots/schema_derive_test__derive_mixed_enum_serde_partially_adjacently_tagged_unit_variant.snap b/utoipa-gen/tests/snapshots/schema_derive_test__derive_mixed_enum_serde_partially_adjacently_tagged_unit_variant.snap new file mode 100644 index 00000000..723a917a --- /dev/null +++ b/utoipa-gen/tests/snapshots/schema_derive_test__derive_mixed_enum_serde_partially_adjacently_tagged_unit_variant.snap @@ -0,0 +1,39 @@ +--- +source: utoipa-gen/tests/schema_derive_test.rs +expression: value +--- +{ + "oneOf": [ + { + "properties": { + "content": { + "properties": { + "n": { + "format": "int32", + "type": "integer" + } + }, + "required": [ + "n" + ], + "type": "object" + }, + "type": { + "enum": [ + "One" + ], + "type": "string" + } + }, + "required": [ + "content", + "type" + ], + "type": "object" + }, + { + "default": null, + "type": "null" + } + ] +} diff --git a/utoipa-gen/tests/snapshots/schema_derive_test__derive_mixed_enum_serde_partially_internally_tagged.snap b/utoipa-gen/tests/snapshots/schema_derive_test__derive_mixed_enum_serde_partially_internally_tagged.snap new file mode 100644 index 00000000..822da25b --- /dev/null +++ b/utoipa-gen/tests/snapshots/schema_derive_test__derive_mixed_enum_serde_partially_internally_tagged.snap @@ -0,0 +1,25 @@ +--- +source: utoipa-gen/tests/schema_derive_test.rs +expression: value +--- +{ + "oneOf": [ + { + "properties": { + "type": { + "enum": [ + "One" + ], + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + }, + { + "type": "string" + } + ] +} diff --git a/utoipa-gen/tests/snapshots/schema_derive_test__derive_mixed_enum_serde_partially_internally_tagged_named_fields.snap b/utoipa-gen/tests/snapshots/schema_derive_test__derive_mixed_enum_serde_partially_internally_tagged_named_fields.snap new file mode 100644 index 00000000..2676bf09 --- /dev/null +++ b/utoipa-gen/tests/snapshots/schema_derive_test__derive_mixed_enum_serde_partially_internally_tagged_named_fields.snap @@ -0,0 +1,39 @@ +--- +source: utoipa-gen/tests/schema_derive_test.rs +expression: value +--- +{ + "oneOf": [ + { + "properties": { + "n": { + "format": "int32", + "type": "integer" + }, + "type": { + "enum": [ + "One" + ], + "type": "string" + } + }, + "required": [ + "n", + "type" + ], + "type": "object" + }, + { + "properties": { + "m": { + "format": "int32", + "type": "integer" + } + }, + "required": [ + "m" + ], + "type": "object" + } + ] +} diff --git a/utoipa-gen/tests/snapshots/schema_derive_test__derive_mixed_enum_serde_partially_internally_tagged_partially_renamed.snap b/utoipa-gen/tests/snapshots/schema_derive_test__derive_mixed_enum_serde_partially_internally_tagged_partially_renamed.snap new file mode 100644 index 00000000..29a54fa7 --- /dev/null +++ b/utoipa-gen/tests/snapshots/schema_derive_test__derive_mixed_enum_serde_partially_internally_tagged_partially_renamed.snap @@ -0,0 +1,26 @@ +--- +source: utoipa-gen/tests/schema_derive_test.rs +expression: value +--- +{ + "oneOf": [ + { + "properties": { + "type": { + "enum": [ + "First" + ], + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + }, + { + "minimum": 0, + "type": "integer" + } + ] +} diff --git a/utoipa-gen/tests/snapshots/schema_derive_test__derive_mixed_enum_serde_partially_internally_tagged_unit_variant.snap b/utoipa-gen/tests/snapshots/schema_derive_test__derive_mixed_enum_serde_partially_internally_tagged_unit_variant.snap new file mode 100644 index 00000000..a8d05796 --- /dev/null +++ b/utoipa-gen/tests/snapshots/schema_derive_test__derive_mixed_enum_serde_partially_internally_tagged_unit_variant.snap @@ -0,0 +1,31 @@ +--- +source: utoipa-gen/tests/schema_derive_test.rs +expression: value +--- +{ + "oneOf": [ + { + "properties": { + "n": { + "format": "int32", + "type": "integer" + }, + "type": { + "enum": [ + "One" + ], + "type": "string" + } + }, + "required": [ + "n", + "type" + ], + "type": "object" + }, + { + "default": null, + "type": "null" + } + ] +} diff --git a/utoipa-gen/tests/snapshots/schema_derive_test__derive_mixed_enum_serde_partially_untagged.snap b/utoipa-gen/tests/snapshots/schema_derive_test__derive_mixed_enum_serde_partially_untagged.snap new file mode 100644 index 00000000..e92f82b1 --- /dev/null +++ b/utoipa-gen/tests/snapshots/schema_derive_test__derive_mixed_enum_serde_partially_untagged.snap @@ -0,0 +1,17 @@ +--- +source: utoipa-gen/tests/schema_derive_test.rs +expression: value +--- +{ + "oneOf": [ + { + "enum": [ + "One" + ], + "type": "string" + }, + { + "type": "string" + } + ] +} diff --git a/utoipa-gen/tests/snapshots/schema_derive_test__derive_mixed_enum_serde_partially_untagged_named_fields.snap b/utoipa-gen/tests/snapshots/schema_derive_test__derive_mixed_enum_serde_partially_untagged_named_fields.snap new file mode 100644 index 00000000..db5c1e05 --- /dev/null +++ b/utoipa-gen/tests/snapshots/schema_derive_test__derive_mixed_enum_serde_partially_untagged_named_fields.snap @@ -0,0 +1,40 @@ +--- +source: utoipa-gen/tests/schema_derive_test.rs +expression: value +--- +{ + "oneOf": [ + { + "properties": { + "One": { + "properties": { + "n": { + "format": "int32", + "type": "integer" + } + }, + "required": [ + "n" + ], + "type": "object" + } + }, + "required": [ + "One" + ], + "type": "object" + }, + { + "properties": { + "m": { + "format": "int32", + "type": "integer" + } + }, + "required": [ + "m" + ], + "type": "object" + } + ] +} diff --git a/utoipa-gen/tests/snapshots/schema_derive_test__derive_mixed_enum_serde_partially_untagged_partially_renamed.snap b/utoipa-gen/tests/snapshots/schema_derive_test__derive_mixed_enum_serde_partially_untagged_partially_renamed.snap new file mode 100644 index 00000000..97d1311b --- /dev/null +++ b/utoipa-gen/tests/snapshots/schema_derive_test__derive_mixed_enum_serde_partially_untagged_partially_renamed.snap @@ -0,0 +1,18 @@ +--- +source: utoipa-gen/tests/schema_derive_test.rs +expression: value +--- +{ + "oneOf": [ + { + "enum": [ + "First" + ], + "type": "string" + }, + { + "minimum": 0, + "type": "integer" + } + ] +} diff --git a/utoipa-gen/tests/snapshots/schema_derive_test__derive_mixed_enum_serde_partially_untagged_unit_variant.snap b/utoipa-gen/tests/snapshots/schema_derive_test__derive_mixed_enum_serde_partially_untagged_unit_variant.snap new file mode 100644 index 00000000..eb408a01 --- /dev/null +++ b/utoipa-gen/tests/snapshots/schema_derive_test__derive_mixed_enum_serde_partially_untagged_unit_variant.snap @@ -0,0 +1,32 @@ +--- +source: utoipa-gen/tests/schema_derive_test.rs +expression: value +--- +{ + "oneOf": [ + { + "properties": { + "One": { + "properties": { + "n": { + "format": "int32", + "type": "integer" + } + }, + "required": [ + "n" + ], + "type": "object" + } + }, + "required": [ + "One" + ], + "type": "object" + }, + { + "default": null, + "type": "null" + } + ] +} diff --git a/utoipa-gen/tests/snapshots/schema_derive_test__derive_mixed_enum_with_enum_ref_serde_partially_adjacently_tagged_named_fields-2.snap b/utoipa-gen/tests/snapshots/schema_derive_test__derive_mixed_enum_with_enum_ref_serde_partially_adjacently_tagged_named_fields-2.snap new file mode 100644 index 00000000..a170dc31 --- /dev/null +++ b/utoipa-gen/tests/snapshots/schema_derive_test__derive_mixed_enum_with_enum_ref_serde_partially_adjacently_tagged_named_fields-2.snap @@ -0,0 +1,38 @@ +--- +source: utoipa-gen/tests/schema_derive_test.rs +expression: foo_value +--- +{ + "oneOf": [ + { + "properties": { + "content": { + "properties": { + "n": { + "format": "int32", + "type": "integer" + } + }, + "required": [ + "n" + ], + "type": "object" + }, + "type": { + "enum": [ + "One" + ], + "type": "string" + } + }, + "required": [ + "content", + "type" + ], + "type": "object" + }, + { + "$ref": "#/components/schemas/Bar" + } + ] +} diff --git a/utoipa-gen/tests/snapshots/schema_derive_test__derive_mixed_enum_with_enum_ref_serde_partially_adjacently_tagged_named_fields.snap b/utoipa-gen/tests/snapshots/schema_derive_test__derive_mixed_enum_with_enum_ref_serde_partially_adjacently_tagged_named_fields.snap new file mode 100644 index 00000000..586ea587 --- /dev/null +++ b/utoipa-gen/tests/snapshots/schema_derive_test__derive_mixed_enum_with_enum_ref_serde_partially_adjacently_tagged_named_fields.snap @@ -0,0 +1,48 @@ +--- +source: utoipa-gen/tests/schema_derive_test.rs +expression: bar_value +--- +{ + "oneOf": [ + { + "properties": { + "Two": { + "properties": { + "m": { + "type": "string" + } + }, + "required": [ + "m" + ], + "type": "object" + } + }, + "required": [ + "Two" + ], + "type": "object" + }, + { + "properties": { + "Three": { + "properties": { + "o": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "o" + ], + "type": "object" + } + }, + "required": [ + "Three" + ], + "type": "object" + } + ] +} diff --git a/utoipa-gen/tests/snapshots/schema_derive_test__derive_mixed_enum_with_enum_ref_serde_partially_internally_tagged_named_fields-2.snap b/utoipa-gen/tests/snapshots/schema_derive_test__derive_mixed_enum_with_enum_ref_serde_partially_internally_tagged_named_fields-2.snap new file mode 100644 index 00000000..bd825d28 --- /dev/null +++ b/utoipa-gen/tests/snapshots/schema_derive_test__derive_mixed_enum_with_enum_ref_serde_partially_internally_tagged_named_fields-2.snap @@ -0,0 +1,30 @@ +--- +source: utoipa-gen/tests/schema_derive_test.rs +expression: foo_value +--- +{ + "oneOf": [ + { + "properties": { + "n": { + "format": "int32", + "type": "integer" + }, + "type": { + "enum": [ + "One" + ], + "type": "string" + } + }, + "required": [ + "n", + "type" + ], + "type": "object" + }, + { + "$ref": "#/components/schemas/Bar" + } + ] +} diff --git a/utoipa-gen/tests/snapshots/schema_derive_test__derive_mixed_enum_with_enum_ref_serde_partially_internally_tagged_named_fields.snap b/utoipa-gen/tests/snapshots/schema_derive_test__derive_mixed_enum_with_enum_ref_serde_partially_internally_tagged_named_fields.snap new file mode 100644 index 00000000..586ea587 --- /dev/null +++ b/utoipa-gen/tests/snapshots/schema_derive_test__derive_mixed_enum_with_enum_ref_serde_partially_internally_tagged_named_fields.snap @@ -0,0 +1,48 @@ +--- +source: utoipa-gen/tests/schema_derive_test.rs +expression: bar_value +--- +{ + "oneOf": [ + { + "properties": { + "Two": { + "properties": { + "m": { + "type": "string" + } + }, + "required": [ + "m" + ], + "type": "object" + } + }, + "required": [ + "Two" + ], + "type": "object" + }, + { + "properties": { + "Three": { + "properties": { + "o": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "o" + ], + "type": "object" + } + }, + "required": [ + "Three" + ], + "type": "object" + } + ] +} diff --git a/utoipa-gen/tests/snapshots/schema_derive_test__derive_mixed_enum_with_enum_ref_serde_partially_untagged_named_fields-2.snap b/utoipa-gen/tests/snapshots/schema_derive_test__derive_mixed_enum_with_enum_ref_serde_partially_untagged_named_fields-2.snap new file mode 100644 index 00000000..d1c1e5a2 --- /dev/null +++ b/utoipa-gen/tests/snapshots/schema_derive_test__derive_mixed_enum_with_enum_ref_serde_partially_untagged_named_fields-2.snap @@ -0,0 +1,31 @@ +--- +source: utoipa-gen/tests/schema_derive_test.rs +expression: foo_value +--- +{ + "oneOf": [ + { + "properties": { + "One": { + "properties": { + "n": { + "format": "int32", + "type": "integer" + } + }, + "required": [ + "n" + ], + "type": "object" + } + }, + "required": [ + "One" + ], + "type": "object" + }, + { + "$ref": "#/components/schemas/Bar" + } + ] +} diff --git a/utoipa-gen/tests/snapshots/schema_derive_test__derive_mixed_enum_with_enum_ref_serde_partially_untagged_named_fields.snap b/utoipa-gen/tests/snapshots/schema_derive_test__derive_mixed_enum_with_enum_ref_serde_partially_untagged_named_fields.snap new file mode 100644 index 00000000..586ea587 --- /dev/null +++ b/utoipa-gen/tests/snapshots/schema_derive_test__derive_mixed_enum_with_enum_ref_serde_partially_untagged_named_fields.snap @@ -0,0 +1,48 @@ +--- +source: utoipa-gen/tests/schema_derive_test.rs +expression: bar_value +--- +{ + "oneOf": [ + { + "properties": { + "Two": { + "properties": { + "m": { + "type": "string" + } + }, + "required": [ + "m" + ], + "type": "object" + } + }, + "required": [ + "Two" + ], + "type": "object" + }, + { + "properties": { + "Three": { + "properties": { + "o": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "o" + ], + "type": "object" + } + }, + "required": [ + "Three" + ], + "type": "object" + } + ] +} diff --git a/utoipa-gen/tests/snapshots/schema_derive_test__derive_mixed_enum_with_ref_serde_partially_adjacently_tagged_named_fields.snap b/utoipa-gen/tests/snapshots/schema_derive_test__derive_mixed_enum_with_ref_serde_partially_adjacently_tagged_named_fields.snap new file mode 100644 index 00000000..eb5f10d8 --- /dev/null +++ b/utoipa-gen/tests/snapshots/schema_derive_test__derive_mixed_enum_with_ref_serde_partially_adjacently_tagged_named_fields.snap @@ -0,0 +1,46 @@ +--- +source: utoipa-gen/tests/schema_derive_test.rs +expression: value +--- +{ + "oneOf": [ + { + "properties": { + "content": { + "properties": { + "n": { + "format": "int32", + "type": "integer" + } + }, + "required": [ + "n" + ], + "type": "object" + }, + "type": { + "enum": [ + "One" + ], + "type": "string" + } + }, + "required": [ + "content", + "type" + ], + "type": "object" + }, + { + "properties": { + "bar": { + "$ref": "#/components/schemas/Bar" + } + }, + "required": [ + "bar" + ], + "type": "object" + } + ] +} diff --git a/utoipa-gen/tests/snapshots/schema_derive_test__derive_mixed_enum_with_ref_serde_partially_internally_tagged_named_fields.snap b/utoipa-gen/tests/snapshots/schema_derive_test__derive_mixed_enum_with_ref_serde_partially_internally_tagged_named_fields.snap new file mode 100644 index 00000000..e7514289 --- /dev/null +++ b/utoipa-gen/tests/snapshots/schema_derive_test__derive_mixed_enum_with_ref_serde_partially_internally_tagged_named_fields.snap @@ -0,0 +1,38 @@ +--- +source: utoipa-gen/tests/schema_derive_test.rs +expression: value +--- +{ + "oneOf": [ + { + "properties": { + "n": { + "format": "int32", + "type": "integer" + }, + "type": { + "enum": [ + "One" + ], + "type": "string" + } + }, + "required": [ + "n", + "type" + ], + "type": "object" + }, + { + "properties": { + "bar": { + "$ref": "#/components/schemas/Bar" + } + }, + "required": [ + "bar" + ], + "type": "object" + } + ] +} diff --git a/utoipa-gen/tests/snapshots/schema_derive_test__derive_mixed_enum_with_ref_serde_partially_untagged_named_fields.snap b/utoipa-gen/tests/snapshots/schema_derive_test__derive_mixed_enum_with_ref_serde_partially_untagged_named_fields.snap new file mode 100644 index 00000000..fcc25bca --- /dev/null +++ b/utoipa-gen/tests/snapshots/schema_derive_test__derive_mixed_enum_with_ref_serde_partially_untagged_named_fields.snap @@ -0,0 +1,39 @@ +--- +source: utoipa-gen/tests/schema_derive_test.rs +expression: value +--- +{ + "oneOf": [ + { + "properties": { + "One": { + "properties": { + "n": { + "format": "int32", + "type": "integer" + } + }, + "required": [ + "n" + ], + "type": "object" + } + }, + "required": [ + "One" + ], + "type": "object" + }, + { + "properties": { + "bar": { + "$ref": "#/components/schemas/Bar" + } + }, + "required": [ + "bar" + ], + "type": "object" + } + ] +} diff --git a/utoipa-gen/tests/snapshots/schema_derive_test__derive_unit_variants_serde_mix_skip_untagged.snap b/utoipa-gen/tests/snapshots/schema_derive_test__derive_unit_variants_serde_mix_skip_untagged.snap new file mode 100644 index 00000000..e3f60c08 --- /dev/null +++ b/utoipa-gen/tests/snapshots/schema_derive_test__derive_unit_variants_serde_mix_skip_untagged.snap @@ -0,0 +1,22 @@ +--- +source: utoipa-gen/tests/schema_derive_test.rs +expression: value +--- +{ + "oneOf": [ + { + "enum": [ + "NormalOne" + ], + "type": "string" + }, + { + "default": null, + "type": "null" + }, + { + "default": null, + "type": "null" + } + ] +} diff --git a/utoipa-gen/tests/snapshots/schema_derive_test__derive_unit_variants_serde_partially_untagged.snap b/utoipa-gen/tests/snapshots/schema_derive_test__derive_unit_variants_serde_partially_untagged.snap new file mode 100644 index 00000000..efcd6f5b --- /dev/null +++ b/utoipa-gen/tests/snapshots/schema_derive_test__derive_unit_variants_serde_partially_untagged.snap @@ -0,0 +1,18 @@ +--- +source: utoipa-gen/tests/schema_derive_test.rs +expression: value +--- +{ + "oneOf": [ + { + "enum": [ + "TaggedOne" + ], + "type": "string" + }, + { + "default": null, + "type": "null" + } + ] +} diff --git a/utoipa-gen/tests/snapshots/schema_derive_test__derive_unit_variants_serde_skip_non_unit.snap b/utoipa-gen/tests/snapshots/schema_derive_test__derive_unit_variants_serde_skip_non_unit.snap new file mode 100644 index 00000000..10789e44 --- /dev/null +++ b/utoipa-gen/tests/snapshots/schema_derive_test__derive_unit_variants_serde_skip_non_unit.snap @@ -0,0 +1,11 @@ +--- +source: utoipa-gen/tests/schema_derive_test.rs +expression: value +--- +{ + "enum": [ + "One", + "Two" + ], + "type": "string" +}