//! PostgreSQL 文档规定的 NUMERIC 分组字节;预期值独立于编码实现。 use super::*; #[test] fn numeric_encoding_matches_protocol_words() { for (text, precision, scale, words) in [ ("0", 5, 2, vec![0, 0, 0, 2]), ("-12.34", 5, 2, vec![2, 0, 0x4000, 2, 12, 3400]), ("0.00001", 5, 5, vec![1, -2, 0, 5, 1000]), ("10000", 5, 0, vec![1, 1, 0, 0, 1]), ("12345678.9012", 12, 4, vec![3, 1, 0, 4, 1234, 5678, 9012]), ( "9999999999999999999999999999999999", 34, 0, vec![ 9, 8, 0, 0, 99, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, ], ), ] { let value = Decimal::parse(text).unwrap(); let expected = words .into_iter() .flat_map(i16::to_be_bytes) .collect::>(); let mut output = BytesMut::new(); encode(value, precision, scale, &mut output).unwrap(); assert_eq!(output.as_ref(), expected, "{text}"); assert_eq!(decode(&output).unwrap(), value); } } #[test] fn native_numeric_preserves_decimal_extremes_and_zero() { for text in [ "0", "-0", "0E-6176", "1E-6176", "1E6111", "-123.456", "1.0000", "9.999999999999999999999999999999999E6144", ] { let value = Decimal::parse(text).unwrap(); let mut output = BytesMut::new(); encode_native(value, &mut output); assert_eq!(decode(&output).unwrap(), value, "{text}"); } for (text, precision, scale) in [("1.001", 5, 2), ("1000", 5, 2), ("1", 35, 0), ("1", 2, 3)] { assert!( encode( Decimal::parse(text).unwrap(), precision, scale, &mut BytesMut::new() ) .is_err() ); } } #[test] fn numeric_decode_rejects_malformed_or_inexact_values() { for words in [ vec![1, 0, 0, 0], vec![-1, 0, 0, 0], vec![1, 0, 0, 0, 10000], vec![0, 0, 0xc000_u16 as i16, 0], vec![0, 0, 0, -1], vec![1, 1537, 0, 0, 1], vec![1, -1545, 0, 0, 1], vec![ 9, 8, 0, 0, 999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, ], ] { let bytes = words .into_iter() .flat_map(i16::to_be_bytes) .collect::>(); assert!(decode(&bytes).is_err(), "{bytes:?}"); } } #[test] #[ignore = "explicit release performance probe"] fn numeric_decode_cost() { use std::{hint::black_box, time::Instant}; println!("\ncase,sample,iterations,elapsed_ns,checksum"); for (name, text) in [ ("zero", "0"), ("fraction", "-1234567890123456789012345.123456789"), ("exponent", "9.999999999999999999999999999999999E6144"), ] { let value = Decimal::parse(text).unwrap(); let mut encoded = BytesMut::new(); encode_native(value, &mut encoded); let expected = decode(&encoded).unwrap(); assert_eq!(expected, value); for _ in 0..100 { black_box(decode(&encoded).unwrap()); } for sample in 0..15 { let started = Instant::now(); let mut decoded = Decimal::ZERO; for _ in 0..100_000 { decoded = black_box(decode(black_box(&encoded)).unwrap()); } let elapsed = started.elapsed().as_nanos(); assert_eq!(decoded, expected); let checksum: u64 = decoded .to_be_bytes() .iter() .map(|byte| u64::from(*byte)) .sum(); println!("numeric_decode_{name},{sample},100000,{elapsed},{checksum}"); } } }