proxmox/proxmox-api-macro/tests/updater.rs
Wolfgang Bumiller 7fe84f8e15 api-macro: allow overriding field attributes in the updater
This allows fixing up things such as `skip_serialize_if`
calls like so:

    #[derive(Updater)]
    struct Foo {
        #[serde(skip_serializing_if = "MyType::is_special")]
        #[updater(serde(skip_serializing_if = "Option::is_none"))]
        field: MyType,
    }

Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
2022-05-11 16:00:42 +02:00

158 lines
3.5 KiB
Rust

#![allow(dead_code)]
use serde::{Deserialize, Serialize};
use proxmox_schema::{api, ApiType, Updater, UpdaterType};
// Helpers for type checks:
struct AssertTypeEq<T>(T);
macro_rules! assert_type_eq {
($what:ident, $a:ty, $b:ty) => {
#[allow(dead_code, unreachable_patterns)]
fn $what(have: AssertTypeEq<$a>) {
match have {
AssertTypeEq::<$b>(_) => (),
}
}
};
}
#[api(min_length: 3, max_length: 64)]
#[derive(UpdaterType)]
/// Custom String.
pub struct Custom(String);
assert_type_eq!(
custom_type,
<Custom as UpdaterType>::Updater,
Option<Custom>
);
#[api]
/// An example of a simple struct type.
#[derive(Updater)]
#[serde(rename_all = "kebab-case")]
pub struct Simple {
/// A test string.
one_field: String,
/// Another test value.
#[serde(skip_serializing_if = "Option::is_empty")]
opt: Option<String>,
}
#[test]
fn test_simple() {
pub const TEST_SCHEMA: ::proxmox_schema::Schema = ::proxmox_schema::ObjectSchema::new(
"An example of a simple struct type.",
&[
(
"one-field",
true,
&::proxmox_schema::StringSchema::new("A test string.").schema(),
),
(
"opt",
true,
&::proxmox_schema::StringSchema::new("Another test value.").schema(),
),
],
)
.schema();
assert_eq!(TEST_SCHEMA, SimpleUpdater::API_SCHEMA);
}
#[api(
properties: {
simple: { type: Simple },
},
)]
/// A second struct so we can test flattening.
#[derive(Updater)]
pub struct Complex {
/// An extra field not part of the flattened struct.
extra: String,
#[serde(flatten)]
simple: Simple,
}
#[api(
properties: {
simple: {
type: Simple,
optional: true,
},
},
)]
/// One of the baaaad cases.
#[derive(Updater)]
#[serde(rename_all = "kebab-case")]
pub struct SuperComplex {
/// An extra field.
extra: String,
simple: Simple,
/// A field which should not appear in the updater.
#[updater(skip)]
not_in_updater: String,
/// A custom type with an Updatable implementation.
custom: Custom,
}
#[test]
fn test_super_complex() {
pub const TEST_SCHEMA: ::proxmox_schema::Schema = ::proxmox_schema::ObjectSchema::new(
"One of the baaaad cases.",
&[
("custom", true, &<Option<Custom> as ApiType>::API_SCHEMA),
(
"extra",
true,
&::proxmox_schema::StringSchema::new("An extra field.").schema(),
),
(
"simple",
true,
//&<<Simple as UpdaterType>::Updater as ApiType>::API_SCHEMA,
&SimpleUpdater::API_SCHEMA,
),
],
)
.schema();
assert_eq!(TEST_SCHEMA, SuperComplexUpdater::API_SCHEMA);
}
#[api]
/// A simple string wrapper.
#[derive(Default, Deserialize, Serialize, Updater)]
struct MyType(String);
impl proxmox_schema::UpdaterType for MyType {
type Updater = Option<Self>;
}
impl MyType {
fn should_skip(&self) -> bool {
self.0 == "skipme"
}
}
#[api(
properties: {
more: { type: MyType },
},
)]
/// A struct where we replace serde attributes.
#[derive(Deserialize, Serialize, Updater)]
pub struct WithSerde {
/// Simple string.
data: String,
#[serde(skip_serializing_if = "MyType::should_skip", default)]
#[updater(serde(skip_serializing_if = "Option::is_none"))]
more: MyType,
}