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:?}"); } }