146 lines
4.7 KiB
Rust
146 lines
4.7 KiB
Rust
use dever_runtime::value::{bytes, decimal::Decimal, parse, text};
|
|
|
|
#[test]
|
|
fn byte_sum_matches_checked_add_at_block_and_integer_boundaries() {
|
|
for length in [0, 1, 15, 16, 4095, 4096, 4097, 8193] {
|
|
let values = vec![255; length];
|
|
let sum = length as i64 * 255;
|
|
for initial in [
|
|
i64::MIN,
|
|
-1,
|
|
0,
|
|
i64::MAX - sum,
|
|
i64::MAX - sum + i64::from(length != 0),
|
|
i64::MAX,
|
|
] {
|
|
let expected = values
|
|
.iter()
|
|
.try_fold(initial, |total, value| total.checked_add(i64::from(*value)));
|
|
assert_eq!(
|
|
bytes::checked_sum(&values, initial),
|
|
expected,
|
|
"{length}/{initial}"
|
|
);
|
|
}
|
|
}
|
|
assert_eq!(bytes::checked_sum(&[0; 8193], i64::MAX), Some(i64::MAX));
|
|
}
|
|
|
|
#[test]
|
|
fn unicode_scalar_conversion_and_positions_keep_boundaries() {
|
|
assert_eq!(text::codepoint("🙂"), Some(128578));
|
|
assert_eq!(text::codepoint(""), None);
|
|
assert_eq!(text::codepoint("e\u{301}"), None);
|
|
assert_eq!(text::from_codepoint(0), Some("\0".into()));
|
|
assert_eq!(text::from_codepoint(128578), Some("🙂".into()));
|
|
for value in [-1, 0xd800, 0x110000] {
|
|
assert_eq!(text::from_codepoint(value), None);
|
|
}
|
|
let value = "a雪🙂e\u{301}";
|
|
assert_eq!(text::at(value, 2), Some("🙂".into()));
|
|
assert_eq!(text::slice(value, 1, 3), Some("雪🙂".into()));
|
|
assert_eq!(text::slice(value, 5, 5), Some("".into()));
|
|
assert_eq!(text::slice("", 0, 0), Some("".into()));
|
|
for (start, end) in [(-1, 1), (1, 0), (0, 6), (6, 6), (0, i64::MAX)] {
|
|
assert_eq!(text::slice(value, start, end), None);
|
|
}
|
|
assert_eq!(text::at(value, i64::MAX), None);
|
|
}
|
|
|
|
#[test]
|
|
fn search_counts_scalars_and_empty_separator_has_no_synthetic_edges() {
|
|
assert_eq!(text::index_of("a🙂雪", "雪"), Some(2));
|
|
assert_eq!(text::index_of("雪", ""), Some(0));
|
|
assert_eq!(text::index_of("雪", "x"), None);
|
|
assert_eq!(text::split("a🙂", ""), ["a", "🙂"]);
|
|
assert!(text::split("", "").is_empty());
|
|
assert_eq!(text::split(",a,,", ","), ["", "a", "", ""]);
|
|
}
|
|
|
|
#[test]
|
|
fn float_parsing_uses_the_existing_numeric_and_special_spellings() {
|
|
assert_eq!(parse::float("1.25e2"), Some(125.0));
|
|
assert!(parse::float("NaN").unwrap().is_nan());
|
|
assert_eq!(parse::float("inf"), Some(f64::INFINITY));
|
|
assert_eq!(parse::float("-inf"), Some(f64::NEG_INFINITY));
|
|
assert!(parse::float("-0").unwrap().is_sign_negative());
|
|
for value in [
|
|
"nan", "+inf", "Infinity", " 1", "1 ", "1_000", "", "+", "1e",
|
|
] {
|
|
assert_eq!(parse::float(value), None);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn decimal_text_is_finite_exact_and_normalized() {
|
|
assert_eq!(parse::decimal("1.2300").unwrap().to_string(), "1.23");
|
|
assert_eq!(parse::decimal("-0").unwrap().to_string(), "0");
|
|
assert_eq!(parse::decimal("1e2"), Some(Decimal::from_int(100)));
|
|
for value in [
|
|
"NaN",
|
|
"inf",
|
|
" 1",
|
|
"1 ",
|
|
"1_000",
|
|
"1e9999",
|
|
"12345678901234567890123456789012345",
|
|
] {
|
|
assert_eq!(parse::decimal(value), None, "{value}");
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn decimal_rounding_uses_half_even_and_rejects_invalid_quanta() {
|
|
for (value, places, expected) in [
|
|
("1.25", 1, "1.2"),
|
|
("1.35", 1, "1.4"),
|
|
("-1.25", 1, "-1.2"),
|
|
("250", -2, "200"),
|
|
("5e-6176", 6176, "5e-6176"),
|
|
] {
|
|
assert_eq!(
|
|
Decimal::parse(value).unwrap().round(places),
|
|
Some(Decimal::parse(expected).unwrap()),
|
|
"{value}"
|
|
);
|
|
}
|
|
let value = Decimal::from_int(1);
|
|
for places in [i64::MIN, -6112, 6177, i64::MAX] {
|
|
assert_eq!(value.round(places), None);
|
|
}
|
|
assert_eq!(Decimal::parse("1e6144").unwrap().round(0), None);
|
|
}
|
|
|
|
#[test]
|
|
fn decimal_library_parser_preserves_the_strict_text_contract() {
|
|
// 逐字节插入检查 dec 的词法边界;不能只测普通数值后删除前置扫描。
|
|
for source in [
|
|
"", "0", "-1.25", "+.25", "1E-6176", "1e6144", "NaN", "Infinity",
|
|
] {
|
|
for position in 0..=source.len() {
|
|
for byte in 0..=127u8 {
|
|
let mut text = source.to_owned();
|
|
text.insert(position, char::from(byte));
|
|
let library = Decimal::parse(&text).ok();
|
|
assert_eq!(
|
|
parse::decimal(&text).map(Decimal::to_be_bytes),
|
|
library.map(Decimal::to_be_bytes),
|
|
"{text:?}"
|
|
);
|
|
}
|
|
}
|
|
}
|
|
for text in [
|
|
"12",
|
|
"١٢",
|
|
"1\u{a0}",
|
|
"\u{2003}1",
|
|
"-∞",
|
|
"1.2.3",
|
|
"1e+",
|
|
"++1",
|
|
] {
|
|
assert_eq!(parse::decimal(text), None, "{text:?}");
|
|
}
|
|
}
|