#![allow(
clippy::indexing_slicing,
reason = "unwraps and indexing are allowed anywhere in tests"
)]
use std::assert_matches;
use super::{Base, CiExactLen, CiMaxLen, Warning};
use crate::{
json,
schema::{self, v211, Integrity},
warning, FromSchema as _,
};
const VALID: &str = r#"{
"currency": "EUR",
"elements": [
{"price_components": [{"price": 0.25, "step_size": 1, "type": "ENERGY"}]}
],
"id": "ID",
"last_updated": "2024-01-01T00:00:00Z"
}"#;
fn build_tariff<'buf>(doc: &json::Document<'buf>) -> v211::Tariff<'buf> {
v211::build_tariff(doc).ignore_warnings()
}
fn id<'a, 'buf>(tariff: &'a v211::Tariff<'buf>) -> &'a schema::Str<'buf> {
let Integrity::Ok(id) = &tariff.id else {
panic!("the id should be built: {:?}", tariff.id);
};
id
}
fn all_warnings(warnings: &warning::Set<Warning>) -> Vec<&Warning> {
warnings.path_map().into_values().flatten().collect()
}
#[test]
fn printable_string_lowers_cleanly() {
let doc = json::parse(VALID.into()).unwrap();
let tariff = build_tariff(&doc);
let (value, warnings) = CiMaxLen::<36>::from_schema(id(&tariff))
.unwrap()
.into_parts();
assert_eq!(&*value, "ID");
assert!(all_warnings(&warnings).is_empty());
}
#[test]
fn max_len_exceeded_warns() {
let src = VALID.replace(r#""id": "ID""#, r#""id": "hello""#);
let doc = json::parse(src.as_str().into()).unwrap();
let tariff = build_tariff(&doc);
let (value, warnings) = CiMaxLen::<3>::from_schema(id(&tariff))
.unwrap()
.into_parts();
assert_eq!(&*value, "hello");
assert_matches!(
all_warnings(&warnings)[..],
[Warning::InvalidLengthMax { length: 3 }]
);
}
#[test]
fn exact_len_match_lowers_cleanly() {
let src = VALID.replace(r#""id": "ID""#, r#""id": "abc""#);
let doc = json::parse(src.as_str().into()).unwrap();
let tariff = build_tariff(&doc);
let (value, warnings) = CiExactLen::<3>::from_schema(id(&tariff))
.unwrap()
.into_parts();
assert_eq!(&*value, "abc");
assert!(all_warnings(&warnings).is_empty());
}
#[test]
fn exact_len_mismatch_warns() {
let src = VALID.replace(r#""id": "ID""#, r#""id": "hello""#);
let doc = json::parse(src.as_str().into()).unwrap();
let tariff = build_tariff(&doc);
let (value, warnings) = CiExactLen::<3>::from_schema(id(&tariff))
.unwrap()
.into_parts();
assert_eq!(&*value, "hello");
assert_matches!(
all_warnings(&warnings)[..],
[Warning::InvalidLengthExact { length: 3 }]
);
}
#[test]
fn escape_sequence_warns() {
let src = VALID.replace(r#""id": "ID""#, r#""id": "a\tb""#);
let doc = json::parse(src.as_str().into()).unwrap();
let tariff = build_tariff(&doc);
let (_value, warnings) = Base::from_schema(id(&tariff)).unwrap().into_parts();
assert_matches!(all_warnings(&warnings)[..], [Warning::ContainsEscapeCodes]);
}
#[test]
fn literal_control_character_warns() {
let src = VALID.replace(r#""id": "ID""#, "\"id\": \"a\tb\"");
let doc = json::parse(src.as_str().into()).unwrap();
let tariff = build_tariff(&doc);
let (_value, warnings) = Base::from_schema(id(&tariff)).unwrap().into_parts();
assert_matches!(
all_warnings(&warnings)[..],
[Warning::ContainsNonPrintableASCII]
);
}
#[test]
fn escape_decoding_to_non_printable_warns_both() {
let src = VALID.replace(r#""id": "ID""#, r#""id": "a\u0020b""#);
let doc = json::parse(src.as_str().into()).unwrap();
let tariff = build_tariff(&doc);
let (_value, warnings) = Base::from_schema(id(&tariff)).unwrap().into_parts();
assert_matches!(
all_warnings(&warnings)[..],
[
Warning::ContainsEscapeCodes,
Warning::ContainsNonPrintableASCII
]
);
}