209 lines
8.1 KiB
Rust
209 lines
8.1 KiB
Rust
use dever_runtime::wire::{self, document, json::Json, serde_json};
|
|
|
|
#[test]
|
|
fn proven_fragments_keep_exact_counts_when_nested() {
|
|
for count in [0, 1, document::MAX_VALUES - 2, document::MAX_VALUES - 1] {
|
|
let values = vec![7i64; count];
|
|
let proven = Json::encode_proven(&values, count + 1, 1).unwrap();
|
|
let parsed = Json::parse(proven.as_str()).unwrap();
|
|
assert_eq!(Json::array(&[proven]), Json::array(&[parsed]));
|
|
}
|
|
let value = Json::encode_proven(&(), 1, 0).unwrap();
|
|
let mut wrapped = value;
|
|
for _ in 0..document::MAX_DEPTH {
|
|
wrapped = Json::array(&[wrapped]).unwrap();
|
|
}
|
|
assert!(Json::array(&[wrapped]).is_err());
|
|
}
|
|
|
|
#[test]
|
|
fn typed_output_counts_values_and_response_envelope() {
|
|
let maximum = vec![0i64; document::MAX_VALUES - 1];
|
|
let encoded = Json::encode(&maximum).unwrap();
|
|
assert_eq!(encoded.as_str(), serde_json::to_string(&maximum).unwrap());
|
|
assert!(Json::encode(&vec![0i64; document::MAX_VALUES]).is_err());
|
|
assert!(wire::response(&vec![0i64; document::MAX_VALUES - 4]).is_ok());
|
|
assert!(wire::response(&vec![0i64; document::MAX_VALUES - 3]).is_err());
|
|
}
|
|
|
|
#[test]
|
|
fn response_fragments_keep_the_envelope_and_its_budgets() {
|
|
for source in ["null", "[1e9999,-0]", r#"{"text":"\u96ea"}"#] {
|
|
let value = Json::parse(source).unwrap();
|
|
assert_eq!(
|
|
wire::response_with(|output| output.json(&value)).unwrap(),
|
|
format!("{{\"code\":0,\"message\":\"ok\",\"data\":{source}}}")
|
|
);
|
|
}
|
|
for count in [document::MAX_VALUES - 4, document::MAX_VALUES - 3] {
|
|
let values = vec![0; count];
|
|
let value = Json::encode(&values).unwrap();
|
|
let output = wire::response_with(|output| output.json(&value));
|
|
assert_eq!(output.is_ok(), count == document::MAX_VALUES - 4);
|
|
assert_eq!(output.is_ok(), wire::response(&values).is_ok());
|
|
}
|
|
let prefix = wire::response_with(|output| output.value(""))
|
|
.unwrap()
|
|
.len();
|
|
let value = Json::string(&"x".repeat(document::MAX_BYTES - prefix)).unwrap();
|
|
assert_eq!(
|
|
wire::response_with(|output| output.json(&value))
|
|
.unwrap()
|
|
.len(),
|
|
document::MAX_BYTES
|
|
);
|
|
let value = Json::string(&"x".repeat(document::MAX_BYTES - prefix + 1)).unwrap();
|
|
assert!(wire::response_with(|output| output.json(&value)).is_err());
|
|
}
|
|
|
|
#[test]
|
|
fn raw_subtrees_consume_the_outer_depth_and_value_budgets() {
|
|
let nested = "[".repeat(document::MAX_DEPTH) + &"]".repeat(document::MAX_DEPTH);
|
|
let typed: serde_json::Value = serde_json::from_str(&nested).unwrap();
|
|
assert_eq!(Json::encode(&typed).unwrap().as_str(), nested);
|
|
assert!(Json::encode(&vec![typed]).is_err());
|
|
for raw in [
|
|
Json::parse(&nested).unwrap(),
|
|
serde_json::from_str(&nested).unwrap(),
|
|
] {
|
|
assert_eq!(
|
|
Json::encode_with(|output| output.json(&raw))
|
|
.unwrap()
|
|
.as_str(),
|
|
nested
|
|
);
|
|
assert!(Json::array(&[raw]).is_err());
|
|
}
|
|
let maximum = Json::encode(&vec![0i64; document::MAX_VALUES - 1]).unwrap();
|
|
assert!(Json::encode_with(|output| output.json(&maximum)).is_ok());
|
|
assert!(Json::array(&[maximum]).is_err());
|
|
let allowed = Json::encode(&vec![0i64; document::MAX_VALUES - 2]).unwrap();
|
|
assert!(Json::array(&[allowed]).is_ok());
|
|
}
|
|
|
|
#[test]
|
|
fn raw_output_keeps_spelling_and_rejects_invalid_object_keys() {
|
|
let source = r#" {"雪": [1e9999, -0, "\u96ea"]} "#;
|
|
let raw = Json::parse(source).unwrap();
|
|
assert_eq!(
|
|
Json::array(&[raw]).unwrap().as_str(),
|
|
format!("[{}]", source.trim())
|
|
);
|
|
let duplicate =
|
|
serde_json::value::RawValue::from_string(r#"{"a":1,"\u0061":2}"#.into()).unwrap();
|
|
assert!(Json::encode(&duplicate).is_err());
|
|
let surrogate = serde_json::value::RawValue::from_string(r#""\ud800""#.into()).unwrap();
|
|
assert!(Json::encode(&surrogate).is_err());
|
|
}
|
|
|
|
#[test]
|
|
fn raw_arrays_match_serde_for_empty_and_mixed_inputs() {
|
|
let sources = [" null ", " [1e9999,-0] ", r#" {"雪":"\u96ea"} "#, " [] "];
|
|
for count in [0, 1, 4, 16] {
|
|
let sources: Vec<_> = sources.into_iter().cycle().take(count).collect();
|
|
let reference: Vec<Box<serde_json::value::RawValue>> = sources
|
|
.iter()
|
|
.map(|source| serde_json::from_str(source).unwrap())
|
|
.collect();
|
|
for values in [
|
|
sources
|
|
.iter()
|
|
.map(|source| Json::parse(source).unwrap())
|
|
.collect::<Vec<_>>(),
|
|
reference
|
|
.iter()
|
|
.cloned()
|
|
.map(Json::from_validated_raw)
|
|
.collect(),
|
|
] {
|
|
let encoded = Json::array(&values).unwrap();
|
|
assert_eq!(encoded.as_str(), serde_json::to_string(&reference).unwrap());
|
|
assert_eq!(
|
|
Json::array(std::slice::from_ref(&encoded))
|
|
.unwrap()
|
|
.as_str(),
|
|
format!("[{}]", encoded.as_str())
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn validated_raw_transfers_its_original_allocation_into_text() {
|
|
let source = r#"{"huge":1e9999,"text":"\u96ea"}"#;
|
|
let raw: Box<serde_json::value::RawValue> = serde_json::from_str(source).unwrap();
|
|
let allocation = raw.get().as_ptr();
|
|
let value = Json::from_validated_raw(raw);
|
|
assert_eq!(value.as_str().as_ptr(), allocation);
|
|
let text = value.into_text();
|
|
assert_eq!(text.as_ptr(), allocation);
|
|
assert_eq!(text, source);
|
|
}
|
|
|
|
#[test]
|
|
fn raw_arrays_enforce_combined_value_and_separator_budgets() {
|
|
let mut values = vec![Json::null().unwrap(); document::MAX_VALUES - 1];
|
|
assert!(Json::array(&values).is_ok());
|
|
values.push(Json::null().unwrap());
|
|
assert!(Json::array(&values).is_err());
|
|
for extra in [0, 1] {
|
|
let values = [
|
|
Json::integer(0).unwrap(),
|
|
Json::string(&"x".repeat(document::MAX_BYTES - 6 + extra)).unwrap(),
|
|
];
|
|
let encoded = Json::array(&values);
|
|
if extra == 0 {
|
|
let encoded = encoded.unwrap();
|
|
assert_eq!(encoded.as_str().len(), document::MAX_BYTES);
|
|
assert!(Json::array(&[encoded]).is_err());
|
|
} else {
|
|
assert!(encoded.is_err());
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn dynamic_output_keeps_byte_limits_and_counts_empty_containers() {
|
|
let allowed = vec!["x".repeat(document::MAX_BYTES - 4)];
|
|
assert_eq!(
|
|
Json::encode(&allowed).unwrap().as_str().len(),
|
|
document::MAX_BYTES
|
|
);
|
|
assert!(Json::encode(&vec!["x".repeat(document::MAX_BYTES - 3)]).is_err());
|
|
assert!(Json::encode(&vec![Vec::<i64>::new(); document::MAX_VALUES - 1]).is_ok());
|
|
assert!(Json::encode(&vec![Vec::<i64>::new(); document::MAX_VALUES]).is_err());
|
|
}
|
|
|
|
#[test]
|
|
fn validated_fragments_combine_with_serde_fields_and_keep_reusable_budgets() {
|
|
let fragment = Json::parse(" \n{\"雪\":[1e9999,-0,\"\\u96ea\"]}\t ").unwrap();
|
|
let nested = Json::encode_with(|output| {
|
|
output.object(|output| {
|
|
output.field_encoded("\"a\\\"雪\":", |output| output.json(&fragment))?;
|
|
output.field("b", false, |output| output.value(&vec![Some("雪\n"), None]))
|
|
})
|
|
})
|
|
.unwrap();
|
|
assert_eq!(
|
|
nested.as_str(),
|
|
"{\"a\\\"雪\":{\"雪\":[1e9999,-0,\"\\u96ea\"]},\"b\":[\"雪\\n\",null]}"
|
|
);
|
|
assert_eq!(
|
|
Json::array(std::slice::from_ref(&nested)).unwrap().as_str(),
|
|
format!("[{}]", nested.as_str())
|
|
);
|
|
assert_eq!(fragment.as_str(), " \n{\"雪\":[1e9999,-0,\"\\u96ea\"]}\t ");
|
|
let allowed =
|
|
Json::parse(&("[".repeat(document::MAX_DEPTH - 1) + &"]".repeat(document::MAX_DEPTH - 1)))
|
|
.unwrap();
|
|
let full = Json::array(&[allowed]).unwrap();
|
|
assert!(Json::array(&[full]).is_err());
|
|
let full =
|
|
Json::encode_with(|output| output.value(&vec![0; document::MAX_VALUES - 1])).unwrap();
|
|
assert!(Json::array(&[full]).is_err());
|
|
let allowed = Json::string(&"x".repeat(document::MAX_BYTES - 4)).unwrap();
|
|
let full = Json::array(&[allowed]).unwrap();
|
|
assert_eq!(full.as_str().len(), document::MAX_BYTES);
|
|
assert!(Json::array(&[full]).is_err());
|
|
}
|