use crate::parser::{JsonParser, ParserContext};
#[derive(Clone)]
pub(crate) struct JsonConstraintValidator {
max_array_length: Option<usize>,
max_value_string_length: Option<usize>,
object_max_elements: Option<usize>,
max_key_length: Option<usize>,
max_depth: Option<usize>,
}
impl JsonConstraintValidator {
pub(crate) fn new(
array_length: Option<usize>,
string_length: Option<usize>,
object_max_elements: Option<usize>,
max_key_length: Option<usize>,
max_depth: Option<usize>,
) -> Self {
Self {
max_array_length: array_length,
max_value_string_length: string_length,
object_max_elements,
max_key_length,
max_depth,
}
}
pub(crate) fn max_depth_restriction_violated(&self, parser: &ParserContext) -> bool {
if let Some(max_depth) = self.max_depth {
max_depth < parser.recursion()
} else {
false
}
}
pub(crate) fn current_string_above_max_length(
&self,
opened: usize,
current: usize,
parser: &ParserContext,
) -> bool {
let restriction = parser
.enclosing_context()
.and_then(|object| {
if object.is_processing_key() {
self.max_key_length
} else {
self.max_value_string_length
}
})
.unwrap_or_else(|| self.max_value_string_length.unwrap_or(usize::MAX));
let current_string_length = current - opened;
let double_quotes = 1;
let actual_current_string_length = current_string_length
.checked_sub(double_quotes)
.unwrap_or_default();
actual_current_string_length > restriction
}
pub(crate) fn array_max_length_restriction_violated(&self, parser: &ParserContext) -> bool {
let count = parser
.current()
.as_ref()
.and_then(JsonParser::element_count);
if let Some(array_element_count) = count {
array_element_count + 1 > self.max_array_length.unwrap_or(usize::MAX)
} else {
false
}
}
pub(crate) fn object_max_element_count_restriction_violated(
&self,
parser: &ParserContext,
) -> bool {
let count = parser
.current()
.as_ref()
.and_then(JsonParser::element_count);
if let Some(current_object_element_count) = count {
current_object_element_count + 1 > self.object_max_elements.unwrap_or(usize::MAX) - 1
} else {
false
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::parser::{JsonParser, ObjectValue, ParserContext};
#[test]
fn max_depth_restriction_not_violated_when_below_limit() {
let validator = JsonConstraintValidator::new(None, None, None, None, Some(5));
let mut parser = ParserContext::new();
parser.push_parser(JsonParser::Object(ObjectValue::new(false, 0)));
parser.push_parser(JsonParser::Object(ObjectValue::new(false, 0)));
assert!(!validator.max_depth_restriction_violated(&parser));
}
#[test]
fn max_depth_restriction_violated_when_above_limit() {
let validator = JsonConstraintValidator::new(None, None, None, None, Some(2));
let mut parser = ParserContext::new();
parser.push_parser(JsonParser::Object(ObjectValue::new(false, 0)));
parser.push_parser(JsonParser::Object(ObjectValue::new(false, 0)));
parser.push_parser(JsonParser::Object(ObjectValue::new(false, 0)));
assert!(validator.max_depth_restriction_violated(&parser));
}
#[test]
fn max_depth_restriction_not_violated_when_no_limit() {
let validator = JsonConstraintValidator::new(None, None, None, None, None);
let mut parser = ParserContext::new();
parser.push_parser(JsonParser::Object(ObjectValue::new(false, 0)));
parser.push_parser(JsonParser::Object(ObjectValue::new(false, 0)));
assert!(!validator.max_depth_restriction_violated(&parser));
}
#[test]
fn array_max_length_restriction_violated_when_exceeds_limit() {
let validator = JsonConstraintValidator::new(Some(5), None, None, None, None);
let mut parser = ParserContext::new();
parser.push_parser(JsonParser::Array { element_count: 5 });
assert!(validator.array_max_length_restriction_violated(&parser));
}
#[test]
fn object_max_element_count_restriction_violated_when_exceeds_limit() {
let validator = JsonConstraintValidator::new(None, None, Some(3), None, None);
let mut parser = ParserContext::new();
parser.push_parser(JsonParser::Object(ObjectValue::new(false, 3)));
assert!(validator.object_max_element_count_restriction_violated(&parser));
}
#[test]
fn current_string_above_max_length_violates_string_value_constraint() {
let validator = JsonConstraintValidator::new(None, Some(5), None, None, None);
let mut parser = ParserContext::new();
parser.push_parser(JsonParser::Object(ObjectValue::new(false, 0)));
parser.push_parser(JsonParser::String { opened: 0 });
assert!(validator.current_string_above_max_length(0, 10, &parser));
}
#[test]
fn current_string_above_max_length_violates_key_constraint() {
let validator = JsonConstraintValidator::new(None, None, None, Some(5), None);
let mut parser = ParserContext::new();
parser.push_parser(JsonParser::Object(ObjectValue::new(true, 0)));
parser.push_parser(JsonParser::String { opened: 0 });
assert!(validator.current_string_above_max_length(0, 10, &parser));
}
#[test]
fn array_max_length_restriction_not_violated_when_below_limit() {
let validator = JsonConstraintValidator::new(Some(10), None, None, None, None);
let mut parser = ParserContext::new();
parser.push_parser(JsonParser::Array { element_count: 5 });
assert!(!validator.array_max_length_restriction_violated(&parser));
}
}