#![forbid(unsafe_code)]
use include_dir::{include_dir, Dir};
pub static FIXTURES: Dir<'static> = include_dir!("$CARGO_MANIFEST_DIR/fixtures");
pub fn fixture_bytes(path: &str) -> Option<&'static [u8]> {
FIXTURES.get_file(path).map(|f| f.contents())
}
pub fn fixture_str(path: &str) -> Option<&'static str> {
FIXTURES.get_file(path).and_then(|f| f.contents_utf8())
}
pub const COMMONMETA_SCHEMA_V1_0: &str = include_str!("../schemas/commonmeta_v1.0.json");
pub fn schema(version: &str) -> Option<&'static str> {
match version {
"1.0" => Some(COMMONMETA_SCHEMA_V1_0),
_ => None,
}
}
#[cfg(test)]
mod tests {
use super::{schema, FIXTURES};
use jsonschema::validator_for;
use serde_json::{json, Value};
#[test]
fn known_version_is_available() {
assert!(schema("1.0").is_some());
}
#[test]
fn unknown_version_is_none() {
assert!(schema("nope").is_none());
}
#[test]
fn embedded_fixtures_are_available() {
use super::{fixture_bytes, fixture_str};
assert!(fixture_str("commonmeta/journal_article.json").is_some());
assert!(fixture_bytes("orcid_xml/0000-0002-0068-716X.xml").is_some());
let commonmeta = FIXTURES.get_dir("commonmeta").expect("commonmeta dir");
assert!(commonmeta.files().count() > 0);
assert!(fixture_str("nope/missing.json").is_none());
}
#[test]
fn all_embedded_commonmeta_fixtures_validate_against_exported_schema() {
let schema_text = schema("1.0").expect("schema 1.0 is embedded");
let schema_json: Value = serde_json::from_str(schema_text).expect("valid schema json");
let defs = schema_json
.get("$defs")
.cloned()
.expect("schema exposes $defs");
let entity_schema = json!({
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$ref": "#/$defs/entity",
"$defs": defs
});
let validator = validator_for(&entity_schema).expect("entity schema compiles for validation");
let commonmeta_dir = FIXTURES.get_dir("commonmeta").expect("commonmeta dir");
let mut validated_count = 0usize;
let mut failures: Vec<String> = Vec::new();
for file in commonmeta_dir.files() {
let path = file.path().to_string_lossy();
if !path.ends_with(".json") {
continue;
}
validated_count += 1;
let text = match file.contents_utf8() {
Some(text) => text,
None => {
failures.push(format!("{path}: fixture is not valid UTF-8"));
continue;
}
};
let instance: Value = match serde_json::from_str(text) {
Ok(value) => value,
Err(err) => {
failures.push(format!("{path}: invalid JSON: {err}"));
continue;
}
};
let details: Vec<String> = validator
.iter_errors(&instance)
.take(5)
.map(|error| format!("{}: {}", error.instance_path, error))
.collect();
if !details.is_empty() {
failures.push(format!("{path}: {}", details.join(" | ")));
}
}
assert!(validated_count > 0, "no commonmeta fixtures found to validate");
assert!(
failures.is_empty(),
"{} fixture(s) failed schema validation:\n{}",
failures.len(),
failures.join("\n")
);
}
}