#[cfg(feature = "sem")]
use miniconf::TreeSchema;
use miniconf::{Internal, SerdeError, Tree, ValueError, json_core, str_leaf};
#[cfg(all(feature = "schema", feature = "sem"))]
use schemars::transform::Transform;
mod common;
use common::*;
#[derive(Tree, Default, PartialEq, Debug)]
struct Inner {
a: i32,
}
#[derive(
Tree,
Default,
PartialEq,
Debug,
strum::EnumString,
strum::AsRefStr,
strum::FromRepr,
strum::EnumDiscriminants,
)]
#[strum_discriminants(derive(serde::Serialize, serde::Deserialize))]
enum Enum {
#[default]
None,
#[strum(serialize = "foo")]
#[strum_discriminants(serde(rename = "foo"))]
#[tree(rename = "foo")]
A(i32),
B(Inner),
}
#[derive(Tree, Default, Debug)]
struct Settings {
#[tree(rename="tag", with=str_leaf, defer=self.enu, typ="Enum")]
_tag: (),
enu: Enum,
}
#[test]
fn enum_switch() {
let mut s = Settings::default();
assert_eq!(s.enu, Enum::None);
set_get(&mut s, "/tag", b"\"foo\"");
assert!(matches!(
json_core::set(&mut s, "/tag", b"\"bar\""),
Err(SerdeError::Value(ValueError::Access(_)))
));
assert_eq!(s.enu, Enum::A(0));
set_get(&mut s, "/enu/foo", b"99");
assert_eq!(s.enu, Enum::A(99));
assert_eq!(
json_core::set(&mut s, "/enu/B/a", b"99"),
Err(ValueError::Absent.into())
);
set_get(&mut s, "/tag", b"\"B\"");
set_get(&mut s, "/enu/B/a", b"8");
assert_eq!(s.enu, Enum::B(Inner { a: 8 }));
assert_eq!(paths::<Settings, 3>(), ["/tag", "/enu/foo", "/enu/B/a",]);
}
#[test]
fn enum_skip() {
struct S;
#[allow(dead_code)]
#[derive(Tree)]
enum E {
A(i32, #[tree(skip)] i32),
#[tree(skip)]
B(S),
C,
D,
}
assert_eq!(paths::<E, 1>(), ["/A"]);
}
#[test]
fn option() {
#[allow(dead_code)]
#[derive(Tree, Copy, Clone, PartialEq, Default, Debug)]
#[tree(flatten)]
enum Option<T> {
#[default]
None,
Some(T),
}
assert_eq!(paths::<Option::<[i32; 1]>, 1>(), ["/0"]);
assert_eq!(paths::<Option::<::core::option::Option<i32>>, 1>(), [""]);
}
#[cfg(feature = "sem")]
#[test]
fn enum_meta() {
#[allow(dead_code)]
#[derive(Tree)]
enum E {
A(i32),
B(Inner),
}
assert!(E::SCHEMA.sem().unwrap().oneof());
let Internal::Named(children) = E::SCHEMA.internal().unwrap() else {
panic!("expected named internal schema");
};
assert_eq!(children[0].name(), "A");
assert_eq!(children[1].name(), "B");
}
#[cfg(all(feature = "schema", feature = "sem"))]
#[test]
fn enum_json_schema_matches_json_value() {
use miniconf::{
json::to_json_value,
json_schema::{AllowAbsent, TreeJsonSchema},
};
#[allow(dead_code)]
#[derive(Tree)]
enum E {
A(i32),
B(Inner),
}
impl Default for E {
fn default() -> Self {
Self::A(0)
}
}
let value = E::A(7);
let json = to_json_value(&value).unwrap();
assert_eq!(json, serde_json::json!({"A": 7}));
let mut schema = TreeJsonSchema::new(Some(&value)).unwrap();
AllowAbsent.transform(&mut schema.root);
jsonschema::validator_for(schema.root.as_value())
.unwrap()
.validate(&json)
.unwrap();
}
#[cfg(all(feature = "schema", feature = "sem"))]
#[test]
fn enum_json_schema_matches_absent_active_variant() {
use miniconf::{
json::to_json_value,
json_schema::{AllowAbsent, TreeJsonSchema},
};
#[allow(dead_code)]
#[derive(Tree)]
enum E {
A(Option<u32>),
B(i32),
}
let value = E::A(None);
let json = to_json_value(&value).unwrap();
assert_eq!(json, serde_json::json!({}));
let mut schema = TreeJsonSchema::new(Some(&value)).unwrap();
AllowAbsent.transform(&mut schema.root);
jsonschema::validator_for(schema.root.as_value())
.unwrap()
.validate(&json)
.unwrap();
}