use serde_json::{from_str, to_string_pretty, to_value, Value};
use std::fs;
use std::io::Read;
use std::path;
use valico::json_schema;
fn visit_specs<F>(dir: &path::Path, cb: F)
where
F: Fn(&path::Path, Value) + Copy,
{
let contents = fs::read_dir(dir).ok().unwrap();
for entry in contents {
let entry = entry.unwrap();
let path = entry.path();
if entry.file_type().unwrap().is_dir() {
visit_specs(&path, cb);
} else {
match fs::File::open(&path) {
Err(_) => continue,
Ok(mut file) => {
let metadata = file.metadata().unwrap();
if metadata.is_file() {
let mut content = String::new();
file.read_to_string(&mut content).ok().unwrap();
let json: Value = from_str(&content).unwrap();
cb(&path, json);
}
}
}
}
}
}
#[test]
fn test_suite() {
let mut content = String::new();
fs::File::open(&path::Path::new("tests/schema/schema.json"))
.ok()
.unwrap()
.read_to_string(&mut content)
.ok()
.unwrap();
let json_v6_schema: Value = from_str(&content).unwrap();
visit_specs(
&path::Path::new("tests/schema/JSON-Schema-Test-Suite/tests/draft6"),
|path, spec_set: Value| {
let spec_set = spec_set.as_array().unwrap();
let exceptions: Vec<(String, String)> = vec![
(
"maxLength.json".to_string(),
"two supplementary Unicode code points is long enough".to_string(),
),
(
"minLength.json".to_string(),
"one supplementary Unicode code point is not long enough".to_string(),
),
(
"refRemote.json".to_string(),
"remote ref invalid".to_string(),
),
(
"refRemote.json".to_string(),
"remote fragment invalid".to_string(),
),
(
"refRemote.json".to_string(),
"ref within ref invalid".to_string(),
),
(
"refRemote.json".to_string(),
"changed scope ref invalid".to_string(),
),
(
"refRemote.json".to_string(),
"base URI change ref invalid".to_string(),
),
(
"refRemote.json".to_string(),
"string is invalid".to_string(),
),
(
"refRemote.json".to_string(),
"object is invalid".to_string(),
),
(
"bignum.json".to_string(),
"a bignum is an integer".to_string(),
),
(
"bignum.json".to_string(),
"a negative bignum is an integer".to_string(),
),
(
"format.json".to_string(),
"an invalid URI Reference".to_string(),
),
(
"format.json".to_string(),
"an invalid URI fragment".to_string(),
),
(
"ecmascript-regex.json".to_string(),
"ECMA 262 has no support for \\Z anchor from .NET".to_string(),
),
];
let group_exceptions: Vec<(String, String)> = vec![
(
"format.json".to_string(),
"validation of JSON-pointers (JSON String Representation)".to_string(),
),
(
"format.json".to_string(),
"format: uri-template".to_string(),
),
];
for spec in spec_set.iter() {
let spec = spec.as_object().unwrap();
let mut scope = json_schema::Scope::new();
scope.compile(json_v6_schema.clone(), true).ok().unwrap();
let spec_desc = spec
.get("description")
.map(|v| v.as_str().unwrap())
.unwrap_or("");
let schema =
match scope.compile_and_return(spec.get("schema").unwrap().clone(), false) {
Ok(schema) => schema,
Err(err) => panic!(
"Error in schema {} {}: {:?}",
path.file_name().unwrap().to_str().unwrap(),
spec.get("description").unwrap().as_str().unwrap(),
err
),
};
let tests = spec.get("tests").unwrap().as_array().unwrap();
for test in tests.iter() {
let test = test.as_object().unwrap();
let description = test.get("description").unwrap().as_str().unwrap();
let data = test.get("data").unwrap();
let valid = test.get("valid").unwrap().as_bool().unwrap();
let state = schema.validate(&data);
if state.is_valid() != valid {
let exception_found = &exceptions[..].contains(&(
path.file_name().unwrap().to_str().unwrap().to_string(),
description.to_string(),
));
let spec_exception_found = &group_exceptions[..].contains(&(
path.file_name().unwrap().to_str().unwrap().to_string(),
spec_desc.to_string(),
));
if !exception_found && !spec_exception_found {
panic!(
"Failure: \"{}\" in \"{}\" -> \"{}\" with state: \n {}",
path.file_name().unwrap().to_str().unwrap(),
spec_desc,
description.to_string(),
to_string_pretty(&to_value(&state).unwrap()).unwrap()
)
}
} else {
println!("test json_schema::test_suite -> {} .. ok", description);
}
}
}
},
)
}