diff --git a/Cargo.toml b/Cargo.toml index cc75ced..199e11e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "jtd" -version = "0.2.0" +version = "0.2.1" description = "A Rust implementation of JSON Type Definition" authors = ["JSON Type Definition Contributors"] edition = "2018" diff --git a/src/schema.rs b/src/schema.rs index 2d43118..9dbe570 100644 --- a/src/schema.rs +++ b/src/schema.rs @@ -110,10 +110,25 @@ impl Schema { } fn validate_with_root(&self, root: Option<&Self>) -> Result<(), ValidateError> { - if root.is_none() && !self.definitions.is_empty() { + // If root is non-None, then self is not the root schema. We should + // therefore not tolerate definitions being placed on this schema. + if root.is_some() && !self.definitions.is_empty() { return Err(ValidateError::NonRootDefinitions); } + // This root variable is the one we will use for recursive calls to + // validate_with_root. + // + // If we are at the top-level call of validate_with_root (invoked by the + // public validate method) wherein root is None, then root will be + // Some(self) for the recursive calls, since we ourselves are the root. + let root = root.or(Some(self)); + + // Validate each definition, if any. + for sub_schema in self.definitions.values() { + sub_schema.validate_with_root(root)?; + } + match &self.form { form::Form::Empty | form::Form::Type(_) => {} form::Form::Enum(form::Enum { values, .. }) => { @@ -122,7 +137,9 @@ impl Schema { } } form::Form::Ref(form::Ref { definition, .. }) => { - if !root.unwrap_or(&self).definitions.contains_key(definition) { + // This unwrap is safe because the assignment to root above + // guarantees root will be non-None. + if !root.unwrap().definitions.contains_key(definition) { return Err(ValidateError::NoSuchDefinition(definition.clone())); } } diff --git a/src/validator.rs b/src/validator.rs index fed16a2..f71f12b 100644 --- a/src/validator.rs +++ b/src/validator.rs @@ -403,11 +403,13 @@ mod tests { .unwrap(); for (name, test_case) in test_cases { - let schema = test_case + let schema: Schema = test_case .schema .try_into() .expect(&format!("parsing schema: {}", name)); + schema.validate().expect(&format!("validating schema: {}", name)); + let validator = Validator { max_depth: None, max_errors: None,