valico 3.1.0

JSON Schema validator and JSON coercer
Documentation
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);
                    }
                }
            }
        },
    )
}