2024-04-15 22:35:27 +02:00
|
|
|
use std::str::from_utf8;
|
|
|
|
|
|
|
|
use macroconf::config;
|
2024-07-25 12:54:33 +02:00
|
|
|
use miniconf::{
|
|
|
|
Error::Traversal,
|
|
|
|
IntoKeys, JsonCoreSlash, Path,
|
2024-08-16 18:14:56 +02:00
|
|
|
Traversal::{Access, TooLong},
|
2024-07-25 12:54:33 +02:00
|
|
|
Tree, TreeKey,
|
|
|
|
};
|
2024-08-16 20:59:05 +02:00
|
|
|
use rstest::*;
|
2024-05-13 22:01:08 +02:00
|
|
|
use serde::{Deserialize, Serialize};
|
2024-04-15 22:35:27 +02:00
|
|
|
|
|
|
|
#[config]
|
2024-05-13 22:01:08 +02:00
|
|
|
#[derive(Debug, Clone, Copy, Serialize, Deserialize, Tree)]
|
|
|
|
struct SubConfig {
|
2024-04-15 22:35:27 +02:00
|
|
|
skipped: i32,
|
2024-08-16 18:14:56 +02:00
|
|
|
#[config(min)]
|
2024-04-15 22:35:27 +02:00
|
|
|
min: i32,
|
2024-08-16 18:14:56 +02:00
|
|
|
#[config(max)]
|
2024-04-15 22:35:27 +02:00
|
|
|
max: i32,
|
2024-08-16 18:14:56 +02:00
|
|
|
#[config(default = "0")]
|
2024-04-15 22:35:27 +02:00
|
|
|
default: i32,
|
|
|
|
/// This is a description
|
|
|
|
description: i32,
|
|
|
|
}
|
|
|
|
|
2024-05-13 22:01:08 +02:00
|
|
|
#[config]
|
|
|
|
#[derive(Debug, Clone, Copy, Tree)]
|
|
|
|
struct Config {
|
2024-07-25 12:54:33 +02:00
|
|
|
#[tree(depth = 2)]
|
2024-05-13 22:01:08 +02:00
|
|
|
sub_config: SubConfig,
|
|
|
|
}
|
|
|
|
|
2024-08-18 17:37:53 +02:00
|
|
|
/// Config with default derive and default field
|
|
|
|
#[config]
|
|
|
|
#[derive(Default)]
|
|
|
|
struct _DefaultConfig {
|
|
|
|
#[config(default)]
|
|
|
|
field: i32,
|
|
|
|
}
|
|
|
|
|
2024-08-16 20:59:05 +02:00
|
|
|
#[rstest]
|
|
|
|
#[case(0, ["skipped"])]
|
|
|
|
#[case(1, ["min"])]
|
|
|
|
#[case(2, ["max"])]
|
|
|
|
#[case(3, ["default"])]
|
|
|
|
#[case(4, ["description"])]
|
|
|
|
fn key<const N: usize>(#[case] id: usize, #[case] field: [&str; N]) {
|
|
|
|
assert_eq!(
|
|
|
|
SubConfig::traverse_by_key(field.into_keys(), |index, name, _len| {
|
|
|
|
assert_eq!((id, Some(field[field.len() - 1])), (index, name));
|
|
|
|
Ok::<_, ()>(())
|
|
|
|
}),
|
|
|
|
Ok(1)
|
|
|
|
);
|
2024-04-15 22:35:27 +02:00
|
|
|
}
|
|
|
|
|
2024-08-16 20:59:05 +02:00
|
|
|
#[rstest]
|
|
|
|
#[case(["skipped", "value"], Err(Traversal(TooLong(1))))]
|
|
|
|
#[case(["min", "value"], Ok(2))]
|
|
|
|
#[case(["max", "value"], Ok(2))]
|
|
|
|
#[case(["default", "value"], Ok(2))]
|
|
|
|
#[case(["description", "value"], Ok(2))]
|
|
|
|
#[case(["min", "min"], Ok(2))]
|
|
|
|
#[case(["max", "max"], Ok(2))]
|
|
|
|
#[case(["default", "default"], Ok(2))]
|
|
|
|
#[case(["description", "description"], Ok(2))]
|
|
|
|
fn sub_keys<const N: usize>(
|
|
|
|
#[case] fields: [&str; N],
|
|
|
|
#[case] expected: Result<usize, miniconf::Error<()>>,
|
|
|
|
) {
|
2024-04-15 22:35:27 +02:00
|
|
|
assert_eq!(
|
2024-08-16 20:59:05 +02:00
|
|
|
SubConfig::traverse_by_key(fields.into_keys(), |_, _, _| Ok::<_, ()>(())),
|
|
|
|
expected
|
2024-07-25 12:54:33 +02:00
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
SubConfig::traverse_by_key(["skipped"].into_keys(), |_, _, _| Ok::<_, ()>(())),
|
2024-04-15 22:35:27 +02:00
|
|
|
Ok(1)
|
|
|
|
);
|
|
|
|
for field in ["min", "max", "default", "description"] {
|
|
|
|
assert_eq!(
|
2024-07-25 12:54:33 +02:00
|
|
|
SubConfig::traverse_by_key([field, "value"].into_keys(), |_, _, _| Ok::<_, ()>(())),
|
2024-04-15 22:35:27 +02:00
|
|
|
Ok(2)
|
|
|
|
);
|
|
|
|
assert_eq!(
|
2024-07-25 12:54:33 +02:00
|
|
|
SubConfig::traverse_by_key([field, field].into_keys(), |_, _, _| Ok::<_, ()>(())),
|
2024-04-15 22:35:27 +02:00
|
|
|
Ok(2)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-16 20:59:05 +02:00
|
|
|
#[fixture]
|
|
|
|
#[once]
|
|
|
|
fn sub_config() -> SubConfig {
|
|
|
|
SubConfig {
|
2024-04-15 22:35:27 +02:00
|
|
|
skipped: 1,
|
2024-05-13 22:01:08 +02:00
|
|
|
min: __SubConfigMin::new(2),
|
|
|
|
max: __SubConfigMax::new(3),
|
|
|
|
default: __SubConfigDefault::new(4),
|
|
|
|
description: __SubConfigDescription::new(5),
|
2024-04-15 22:35:27 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-16 20:59:05 +02:00
|
|
|
#[rstest]
|
|
|
|
#[case("/skipped", "1")]
|
|
|
|
#[case("/min", "2")]
|
|
|
|
#[case("/min/value", "2")]
|
|
|
|
#[case("/min/min", "-2147483648")]
|
|
|
|
#[case("/max", "3")]
|
|
|
|
#[case("/max/value", "3")]
|
|
|
|
#[case("/max/max", "2147483647")]
|
|
|
|
#[case("/default", "4")]
|
|
|
|
#[case("/default/value", "4")]
|
|
|
|
#[case("/default/default", "0")]
|
|
|
|
#[case("/description", "5")]
|
|
|
|
#[case("/description/value", "5")]
|
|
|
|
#[case("/description/description", "\"This is a description\"")]
|
|
|
|
fn serialize(sub_config: &SubConfig, #[case] path: &str, #[case] expected: &str) {
|
|
|
|
let mut buffer = [0u8; 32];
|
|
|
|
let len = sub_config.get_json(path, &mut buffer).unwrap();
|
|
|
|
assert_eq!(from_utf8(&buffer[..len]), Ok(expected));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[rstest]
|
|
|
|
#[case("/skipped", Ok(2))]
|
|
|
|
#[case("/min", Ok(2))]
|
|
|
|
#[case("/min/value", Ok(2))]
|
|
|
|
#[case("/max", Ok(2))]
|
|
|
|
#[case("/max/value", Ok(2))]
|
|
|
|
#[case("/default", Ok(2))]
|
|
|
|
#[case("/default/value", Ok(2))]
|
|
|
|
#[case("/description", Ok(2))]
|
|
|
|
#[case("/description/value", Ok(2))]
|
|
|
|
#[case("/min/min", Err(Traversal(Access(1, "Cannot write limits"))))]
|
|
|
|
#[case("/max/max", Err(Traversal(Access(1, "Cannot write limits"))))]
|
|
|
|
#[case("/default/default", Err(Traversal(Access(1, "Cannot write limits"))))]
|
|
|
|
#[case(
|
|
|
|
"/description/description",
|
|
|
|
Err(Traversal(Access(1, "Cannot write limits")))
|
|
|
|
)]
|
|
|
|
fn deserialize(
|
|
|
|
#[case] path: &str,
|
|
|
|
#[case] expected: Result<usize, miniconf::Error<serde_json_core::de::Error>>,
|
|
|
|
) {
|
2024-05-13 22:01:08 +02:00
|
|
|
let mut config = SubConfig {
|
2024-04-15 22:35:27 +02:00
|
|
|
skipped: 0,
|
2024-05-13 22:01:08 +02:00
|
|
|
min: __SubConfigMin::new(0),
|
|
|
|
max: __SubConfigMax::new(0),
|
|
|
|
default: __SubConfigDefault::new(0),
|
|
|
|
description: __SubConfigDescription::new(0),
|
2024-04-15 22:35:27 +02:00
|
|
|
};
|
|
|
|
|
2024-08-16 20:59:05 +02:00
|
|
|
let res = config.set_json(path, b"10");
|
|
|
|
assert_eq!(res, expected);
|
2024-04-15 22:35:27 +02:00
|
|
|
}
|
2024-05-13 22:01:08 +02:00
|
|
|
|
|
|
|
#[test]
|
2024-08-16 20:59:05 +02:00
|
|
|
fn config_paths() {
|
2024-05-13 22:01:08 +02:00
|
|
|
let control = vec![
|
|
|
|
"/sub_config/skipped".to_owned(),
|
|
|
|
"/sub_config/min/value".to_owned(),
|
|
|
|
"/sub_config/min/min".to_owned(),
|
|
|
|
"/sub_config/max/value".to_owned(),
|
|
|
|
"/sub_config/max/max".to_owned(),
|
|
|
|
"/sub_config/default/value".to_owned(),
|
|
|
|
"/sub_config/default/default".to_owned(),
|
|
|
|
"/sub_config/description/value".to_owned(),
|
|
|
|
"/sub_config/description/description".to_owned(),
|
|
|
|
];
|
2024-07-25 12:54:33 +02:00
|
|
|
let paths: Vec<String> = Config::nodes::<Path<String, '/'>>()
|
|
|
|
.filter_map(|path| path.ok().map(|(n, _)| n.0))
|
2024-05-13 22:01:08 +02:00
|
|
|
.collect();
|
|
|
|
assert_eq!(paths, control);
|
|
|
|
}
|