use crate::common::helpers::{
Context, ValidateWithContext, validate_optional_url, validate_required_string,
};
use crate::v2::spec::Spec;
use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
pub struct XML {
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub namespace: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub prefix: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub attribute: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub wrapped: Option<bool>,
#[serde(flatten)]
#[serde(with = "crate::common::extensions")]
#[serde(skip_serializing_if = "Option::is_none")]
pub extensions: Option<BTreeMap<String, serde_json::Value>>,
}
impl ValidateWithContext<Spec> for XML {
fn validate_with_context(&self, ctx: &mut Context<Spec>, path: String) {
if let Some(name) = &self.name {
validate_required_string(name, ctx, format!("{path}.name"));
}
validate_optional_url(&self.namespace, ctx, format!("{path}.namespace"));
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::validation::Options;
#[test]
fn serialize() {
assert_eq!(
serde_json::to_string(&XML::default()).unwrap(),
"{}",
"empty object"
);
assert_eq!(
serde_json::to_value(XML {
name: Some("name".to_owned()),
namespace: Some("https://example.com/schema/sample".to_owned()),
prefix: Some("sample".to_owned()),
attribute: Some(true),
wrapped: Some(true),
extensions: {
let mut map = BTreeMap::new();
map.insert("x-internal-id".to_owned(), serde_json::Value::Null);
Some(map)
},
})
.unwrap(),
serde_json::json!({
"name": "name",
"namespace": "https://example.com/schema/sample",
"prefix": "sample",
"attribute": true,
"wrapped": true,
"x-internal-id": null,
}),
"all fields"
);
}
#[test]
fn deserialize() {
assert_eq!(
serde_json::from_value::<XML>(serde_json::json!({})).unwrap(),
XML::default(),
"empty object"
);
assert_eq!(
serde_json::from_value::<XML>(serde_json::json!({
"name": "name",
"namespace": "https://example.com/schema/sample",
"prefix": "sample",
"attribute": true,
"wrapped": true,
"x-internal-id": null,
}))
.unwrap(),
XML {
name: Some("name".to_owned()),
namespace: Some("https://example.com/schema/sample".to_owned()),
prefix: Some("sample".to_owned()),
attribute: Some(true),
wrapped: Some(true),
extensions: {
let mut map = BTreeMap::new();
map.insert("x-internal-id".to_owned(), serde_json::Value::Null);
Some(map)
},
},
"all fields"
);
}
#[test]
fn validate() {
let spec = Spec::default();
let mut ctx = Context::new(&spec, Options::new());
XML {
name: Some("name".to_owned()),
namespace: Some("https://example.com/schema/sample".to_owned()),
prefix: Some("sample".to_owned()),
attribute: Some(true),
wrapped: Some(true),
extensions: None,
}
.validate_with_context(&mut ctx, "xml".to_owned());
assert!(ctx.errors.is_empty(), "no errors: {:?}", ctx.errors);
XML {
namespace: Some("https://example.com/schema/sample".to_owned()),
..Default::default()
}
.validate_with_context(&mut ctx, "xml".to_owned());
assert!(ctx.errors.is_empty(), "no errors: {:?}", ctx.errors);
XML {
name: Some("".to_owned()),
namespace: Some("foo-bar".to_owned()),
..Default::default()
}
.validate_with_context(&mut ctx, "xml".to_owned());
assert_eq!(
ctx.errors,
vec![
"xml.name: must not be empty",
"xml.namespace: must be a valid URL, found `foo-bar`",
],
"invalid URL and empty name: {:?}",
ctx.errors
);
}
}