#![allow(clippy::shadow_unrelated, clippy::unwrap_used)]
use zero_postgres::conversion::ref_row::{
FixedWireSize, I16BE, I32BE, I64BE, LengthPrefixed, U16BE, U32BE, U64BE,
};
use zerocopy::{FromBytes, Immutable, KnownLayout};
#[test]
fn fixed_wire_size_primitives() {
assert_eq!(<i8 as FixedWireSize>::WIRE_SIZE, 1);
assert_eq!(<u8 as FixedWireSize>::WIRE_SIZE, 1);
assert_eq!(<I16BE as FixedWireSize>::WIRE_SIZE, 2);
assert_eq!(<U16BE as FixedWireSize>::WIRE_SIZE, 2);
assert_eq!(<I32BE as FixedWireSize>::WIRE_SIZE, 4);
assert_eq!(<U32BE as FixedWireSize>::WIRE_SIZE, 4);
assert_eq!(<I64BE as FixedWireSize>::WIRE_SIZE, 8);
assert_eq!(<U64BE as FixedWireSize>::WIRE_SIZE, 8);
}
#[test]
fn length_prefixed_wire_size() {
assert_eq!(<LengthPrefixed<I16BE> as FixedWireSize>::WIRE_SIZE, 6);
assert_eq!(<LengthPrefixed<I32BE> as FixedWireSize>::WIRE_SIZE, 8);
assert_eq!(<LengthPrefixed<I64BE> as FixedWireSize>::WIRE_SIZE, 12);
assert_eq!(<LengthPrefixed<U32BE> as FixedWireSize>::WIRE_SIZE, 8);
}
#[test]
fn big_endian_parsing() {
let data: [u8; 4] = [0x12, 0x34, 0x56, 0x78];
let value: &I32BE = FromBytes::ref_from_bytes(&data).unwrap();
assert_eq!(value.get(), 0x12345678);
let data: [u8; 8] = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08];
let value: &I64BE = FromBytes::ref_from_bytes(&data).unwrap();
assert_eq!(value.get(), 0x0102030405060708);
}
#[test]
fn length_prefixed_parsing() {
let mut data = [0u8; 8];
data[0..4].copy_from_slice(&4_i32.to_be_bytes()); data[4..8].copy_from_slice(&42_i32.to_be_bytes());
let prefixed: &LengthPrefixed<I32BE> = FromBytes::ref_from_bytes(&data).unwrap();
assert_eq!(prefixed.len(), 4);
assert!(!prefixed.is_null());
assert_eq!(prefixed.get().get(), 42);
}
#[test]
fn length_prefixed_i64() {
let value: i64 = 0x0102030405060708;
let mut data = [0u8; 12];
data[0..4].copy_from_slice(&8_i32.to_be_bytes()); data[4..12].copy_from_slice(&value.to_be_bytes());
let prefixed: &LengthPrefixed<I64BE> = FromBytes::ref_from_bytes(&data).unwrap();
assert_eq!(prefixed.len(), 8);
assert_eq!(prefixed.get().get(), value);
}
#[test]
fn packed_struct_with_length_prefixed() {
#[derive(Debug, FromBytes, KnownLayout, Immutable)]
#[repr(C, packed)]
struct TestRow {
col1: LengthPrefixed<I32BE>, col2: LengthPrefixed<I64BE>, }
assert_eq!(std::mem::size_of::<TestRow>(), 20);
let mut data = [0u8; 20];
data[0..4].copy_from_slice(&4_i32.to_be_bytes());
data[4..8].copy_from_slice(&42_i32.to_be_bytes());
data[8..12].copy_from_slice(&8_i32.to_be_bytes());
data[12..20].copy_from_slice(&12345_i64.to_be_bytes());
let row: &TestRow = FromBytes::ref_from_bytes(&data).unwrap();
assert_eq!(row.col1.len(), 4);
assert_eq!(row.col1.get().get(), 42);
assert_eq!(row.col2.len(), 8);
assert_eq!(row.col2.get().get(), 12345);
}
#[test]
fn packed_alignment() {
#[derive(Debug, FromBytes, KnownLayout, Immutable)]
#[repr(C, packed)]
struct MixedRow {
a: LengthPrefixed<I16BE>, b: LengthPrefixed<I64BE>, c: LengthPrefixed<I32BE>, }
assert_eq!(std::mem::size_of::<MixedRow>(), 26);
assert_eq!(std::mem::align_of::<MixedRow>(), 1);
}
#[test]
fn unsigned_integers() {
#[derive(Debug, FromBytes, KnownLayout, Immutable)]
#[repr(C, packed)]
struct UnsignedRow {
a: LengthPrefixed<U32BE>,
b: LengthPrefixed<U64BE>,
}
let mut data = [0u8; 20];
data[0..4].copy_from_slice(&4_i32.to_be_bytes());
data[4..8].copy_from_slice(&0xDEADBEEF_u32.to_be_bytes());
data[8..12].copy_from_slice(&8_i32.to_be_bytes());
data[12..20].copy_from_slice(&0xCAFEBABEDEADC0DE_u64.to_be_bytes());
let row: &UnsignedRow = FromBytes::ref_from_bytes(&data).unwrap();
assert_eq!(row.a.get().get(), 0xDEADBEEF);
assert_eq!(row.b.get().get(), 0xCAFEBABEDEADC0DE);
}
#[test]
fn negative_values() {
let mut data = [0u8; 8];
data[0..4].copy_from_slice(&4_i32.to_be_bytes());
data[4..8].copy_from_slice(&(-12345_i32).to_be_bytes());
let prefixed: &LengthPrefixed<I32BE> = FromBytes::ref_from_bytes(&data).unwrap();
assert_eq!(prefixed.get().get(), -12345);
}
#[test]
fn size_validation() {
#[derive(Debug, FromBytes, KnownLayout, Immutable)]
#[repr(C, packed)]
struct TestRow {
a: LengthPrefixed<I32BE>,
b: LengthPrefixed<I64BE>,
}
let data = [0u8; 19];
<TestRow as FromBytes>::ref_from_bytes(&data).unwrap_err();
let data = [0u8; 20];
<TestRow as FromBytes>::ref_from_bytes(&data).unwrap();
}
#[test]
fn simulated_row() {
#[derive(Debug, FromBytes, KnownLayout, Immutable)]
#[repr(C, packed)]
struct UserRow {
id: LengthPrefixed<I64BE>,
age: LengthPrefixed<I32BE>,
score: LengthPrefixed<I64BE>,
}
let mut data = [0u8; 32];
data[0..4].copy_from_slice(&8_i32.to_be_bytes());
data[4..12].copy_from_slice(&1001_i64.to_be_bytes());
data[12..16].copy_from_slice(&4_i32.to_be_bytes());
data[16..20].copy_from_slice(&25_i32.to_be_bytes());
data[20..24].copy_from_slice(&8_i32.to_be_bytes());
data[24..32].copy_from_slice(&9500_i64.to_be_bytes());
let row: &UserRow = FromBytes::ref_from_bytes(&data).unwrap();
assert_eq!(row.id.get().get(), 1001);
assert_eq!(row.age.get().get(), 25);
assert_eq!(row.score.get().get(), 9500);
}