use crate::common::helpers::validate_optional_uri;
use crate::v3_1::spec::Spec;
use crate::validation::{Context, PushError, ValidateWithContext};
use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
pub struct Example {
#[serde(skip_serializing_if = "Option::is_none")]
pub summary: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub value: Option<serde_json::Value>,
#[serde(rename = "externalValue")]
#[serde(skip_serializing_if = "Option::is_none")]
pub external_value: Option<String>,
#[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 Example {
fn validate_with_context(&self, ctx: &mut Context<Spec>, path: String) {
if self.value.is_some() && self.external_value.is_some() {
ctx.error(
path.clone(),
"value and externalValue are mutually exclusive",
);
}
validate_optional_uri(&self.external_value, ctx, format!("{path}.externalValue"));
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::validation::Context;
use crate::validation::Options;
use crate::validation::ValidationErrorsExt;
use serde_json::json;
#[test]
fn xor_value_and_external_errors() {
let spec = Spec::default();
let mut ctx = Context::new(&spec, Options::new());
Example {
value: Some(json!(1)),
external_value: Some("https://example.com/x.json".into()),
..Default::default()
}
.validate_with_context(&mut ctx, "ex".into());
assert!(
ctx.errors.mentions("mutually exclusive"),
"errors: {:?}",
ctx.errors
);
}
#[test]
fn external_value_uri_reference_validated() {
let spec = Spec::default();
for ok in ["./fixtures/example.json", "urn:example:my-example"] {
let mut ctx = Context::new(&spec, Options::new());
Example {
external_value: Some(ok.to_owned()),
..Default::default()
}
.validate_with_context(&mut ctx, "ex".into());
assert!(
ctx.errors.is_empty(),
"uri-reference `{ok}` should pass: {:?}",
ctx.errors
);
}
let mut ctx = Context::new(&spec, Options::new());
Example {
external_value: Some("not a uri".into()),
..Default::default()
}
.validate_with_context(&mut ctx, "ex".into());
assert!(
ctx.errors.mentions("must be a valid URI"),
"errors: {:?}",
ctx.errors
);
}
}