#![allow(
clippy::indexing_slicing,
clippy::panic,
clippy::unwrap_used,
reason = "test code with known-structure parsed data"
)]
use std::assert_matches;
use super::{parse, Error, ErrorKind, Location};
use crate::json::{Document, ElemId, Span, Value};
fn parsed(s: &str) -> Document<'_> {
parse(s.into()).unwrap()
}
#[test]
fn null_value() {
let doc = parsed("null");
assert_eq!(doc.root.value(), &Value::Null);
assert_eq!(doc.root.span(), Span::new(0, 4));
assert_eq!(doc.root.id(), ElemId(0));
}
#[test]
fn true_value() {
let doc = parsed("true");
assert_eq!(doc.root.value(), &Value::True);
assert_eq!(doc.root.span(), Span::new(0, 4));
}
#[test]
fn false_value() {
let doc = parsed("false");
assert_eq!(doc.root.value(), &Value::False);
assert_eq!(doc.root.span(), Span::new(0, 5));
}
#[test]
fn string_value() {
let doc = parsed(r#""hello""#);
let Value::String(raw) = doc.root.value() else {
panic!("expected String")
};
assert_eq!(raw.as_unescaped_str(), "hello");
assert_eq!(doc.root.span(), Span::new(0, 7));
}
#[test]
fn string_with_escape() {
let doc = parsed(r#""a\"b""#);
let Value::String(raw) = doc.root.value() else {
panic!("expected String")
};
assert_eq!(raw.as_unescaped_str(), r#"a\"b"#);
}
#[test]
fn string_with_unicode_escape() {
let doc = parsed("\"\\u0022\"");
let Value::String(raw) = doc.root.value() else {
panic!("expected String")
};
assert_eq!(raw.as_unescaped_str(), "\\u0022");
}
#[test]
fn number_integer() {
let doc = parsed("42");
assert_eq!(doc.root.value(), &Value::Number("42"));
assert_eq!(doc.root.span(), Span::new(0, 2));
}
#[test]
fn number_negative() {
let doc = parsed("-7");
assert_eq!(doc.root.value(), &Value::Number("-7"));
}
#[test]
fn number_decimal() {
let doc = parsed("3.14");
assert_eq!(doc.root.value(), &Value::Number("3.14"));
}
#[test]
fn number_exponent() {
let doc = parsed("1e10");
assert_eq!(doc.root.value(), &Value::Number("1e10"));
}
#[test]
fn number_full() {
let doc = parsed("-1.5E+3");
assert_eq!(doc.root.value(), &Value::Number("-1.5E+3"));
}
#[test]
fn array_empty() {
let doc = parsed("[]");
let Value::Array(items) = doc.root.value() else {
panic!("expected Array")
};
assert!(items.is_empty());
assert_eq!(doc.root.span(), Span::new(0, 2));
}
#[test]
fn array_values() {
let doc = parsed("[1, true, null]");
let Value::Array(items) = doc.root.value() else {
panic!("expected Array")
};
assert_eq!(items.len(), 3);
assert_eq!(items[0].value(), &Value::Number("1"));
assert_eq!(items[1].value(), &Value::True);
assert_eq!(items[2].value(), &Value::Null);
}
#[test]
fn object_empty() {
let doc = parsed("{}");
let Value::Object(fields) = doc.root.value() else {
panic!("expected Object")
};
assert!(fields.is_empty());
}
#[test]
fn object_fields() {
let doc = parsed(r#"{"a": 1, "b": false}"#);
let Value::Object(fields) = doc.root.value() else {
panic!("expected Object")
};
assert_eq!(fields.len(), 2);
assert_eq!(fields[0].element().value(), &Value::Number("1"));
assert_eq!(fields[1].element().value(), &Value::False);
}
#[test]
fn elem_ids_are_sequential_depth_first() {
let doc = parsed(r#"{"a": [10, 20]}"#);
assert_eq!(doc.root.id(), ElemId(0));
let Value::Object(fields) = doc.root.value() else {
panic!()
};
let arr = fields[0].element();
assert_eq!(arr.id(), ElemId(1));
let Value::Array(items) = arr.value() else {
panic!()
};
assert_eq!(items[0].id(), ElemId(2));
assert_eq!(items[1].id(), ElemId(3));
}
#[test]
fn whitespace_is_ignored() {
let doc = parsed(" \n null \t");
assert_eq!(doc.root.value(), &Value::Null);
}
#[test]
fn error_unexpected_char() {
assert_matches!(
parse("x".into()).unwrap_err(),
Error {
byte_offset: 0,
position: Location { line: 0, col: 0 },
kind: ErrorKind::ExpectedStart
}
);
}
#[test]
fn error_unexpected_end() {
assert_matches!(
parse("".into()).unwrap_err(),
Error {
byte_offset: 0,
position: Location { line: 0, col: 0 },
kind: ErrorKind::UnexpectedEOF
}
);
assert_matches!(
parse("[".into()).unwrap_err(),
Error {
byte_offset: 1,
position: Location { line: 0, col: 1 },
kind: ErrorKind::UnexpectedEOF
}
);
assert_matches!(
parse("{".into()).unwrap_err(),
Error {
byte_offset: 1,
position: Location { line: 0, col: 1 },
kind: ErrorKind::UnexpectedEOF
}
);
}
#[test]
fn error_trailing_content() {
assert_matches!(
parse("null x".into()).unwrap_err(),
Error {
byte_offset: 5,
position: Location { line: 0, col: 5 },
kind: ErrorKind::TrailingContent
}
);
}
#[test]
fn full_span_equals_span_when_no_trailing_comma() {
let doc = parsed("42");
assert_eq!(doc.root.full_span(), doc.root.span());
assert_eq!(doc.root.full_span(), Span::new(0, 2));
}
#[test]
fn full_span_array_non_last_includes_comma_and_whitespace() {
let doc = parsed("[1, 2]");
let Value::Array(items) = doc.root.value() else {
panic!("expected Array")
};
assert_eq!(items[0].span(), Span::new(1, 2));
assert_eq!(items[0].full_span(), Span::new(1, 4));
assert_eq!(items[1].span(), Span::new(4, 5));
assert_eq!(items[1].full_span(), Span::new(4, 5));
}
#[test]
fn full_span_object_non_last_field_includes_comma_and_whitespace() {
let doc = parsed(r#"{"a": 1, "b": 2}"#);
let Value::Object(fields) = doc.root.value() else {
panic!("expected Object")
};
assert_eq!(fields[0].element().span(), Span::new(6, 7));
assert_eq!(fields[0].element().full_span(), Span::new(6, 9));
assert_eq!(fields[1].element().span(), Span::new(14, 15));
assert_eq!(fields[1].element().full_span(), Span::new(14, 15));
}
#[test]
fn field_full_span_extends_from_key_start() {
let doc = parsed(r#"{"a": 1, "b": 2}"#);
let Value::Object(fields) = doc.root.value() else {
panic!("expected Object")
};
assert_eq!(fields[0].full_span(), Span::new(1, 9));
assert_eq!(fields[1].full_span(), Span::new(9, 15));
}
#[test]
fn full_span_single_array_item_equals_span() {
let doc = parsed("[42]");
let Value::Array(items) = doc.root.value() else {
panic!("expected Array")
};
assert_eq!(items[0].span(), Span::new(1, 3));
assert_eq!(items[0].full_span(), items[0].span());
}
#[test]
fn full_span_single_object_field_equals_span() {
let doc = parsed(r#"{"a": 1}"#);
let Value::Object(fields) = doc.root.value() else {
panic!("expected Object")
};
assert_eq!(fields[0].element().span(), Span::new(6, 7));
assert_eq!(fields[0].element().full_span(), fields[0].element().span());
assert_eq!(fields[0].full_span(), Span::new(1, 7));
}