Skip to content

Commit

Permalink
Refactor tests into macro
Browse files Browse the repository at this point in the history
  • Loading branch information
joncinque committed Aug 1, 2023
1 parent 4c2916a commit 59962d7
Show file tree
Hide file tree
Showing 3 changed files with 121 additions and 295 deletions.
117 changes: 117 additions & 0 deletions sdk/program/src/borsh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,3 +171,120 @@ macro_rules! impl_get_instance_packed_len {
}
}
pub(crate) use impl_get_instance_packed_len;

#[cfg(test)]
macro_rules! impl_tests {
($borsh:ident) => {
use {
super::*,
std::{collections::HashMap, mem::size_of},
$borsh::{maybestd::io::ErrorKind, BorshDeserialize, BorshSerialize},
};

type Child = [u8; 64];
type Parent = Vec<Child>;

#[test]
fn unchecked_deserialization() {
let parent = vec![[0u8; 64], [1u8; 64], [2u8; 64]];

// exact size, both work
let mut byte_vec = vec![0u8; 4 + get_packed_len::<Child>() * 3];
let mut bytes = byte_vec.as_mut_slice();
parent.serialize(&mut bytes).unwrap();
let deserialized = Parent::try_from_slice(&byte_vec).unwrap();
assert_eq!(deserialized, parent);
let deserialized = try_from_slice_unchecked::<Parent>(&byte_vec).unwrap();
assert_eq!(deserialized, parent);

// too big, only unchecked works
let mut byte_vec = vec![0u8; 4 + get_packed_len::<Child>() * 10];
let mut bytes = byte_vec.as_mut_slice();
parent.serialize(&mut bytes).unwrap();
let err = Parent::try_from_slice(&byte_vec).unwrap_err();
assert_eq!(err.kind(), ErrorKind::InvalidData);
let deserialized = try_from_slice_unchecked::<Parent>(&byte_vec).unwrap();
assert_eq!(deserialized, parent);
}

#[test]
fn packed_len() {
assert_eq!(get_packed_len::<u64>(), size_of::<u64>());
assert_eq!(get_packed_len::<Child>(), size_of::<u8>() * 64);
}

#[test]
fn instance_packed_len_matches_packed_len() {
let child = [0u8; 64];
assert_eq!(
get_packed_len::<Child>(),
get_instance_packed_len(&child).unwrap(),
);
assert_eq!(
get_packed_len::<u8>(),
get_instance_packed_len(&0u8).unwrap(),
);
assert_eq!(
get_packed_len::<u16>(),
get_instance_packed_len(&0u16).unwrap(),
);
assert_eq!(
get_packed_len::<u32>(),
get_instance_packed_len(&0u32).unwrap(),
);
assert_eq!(
get_packed_len::<u64>(),
get_instance_packed_len(&0u64).unwrap(),
);
assert_eq!(
get_packed_len::<u128>(),
get_instance_packed_len(&0u128).unwrap(),
);
assert_eq!(
get_packed_len::<[u8; 10]>(),
get_instance_packed_len(&[0u8; 10]).unwrap(),
);
assert_eq!(
get_packed_len::<(i8, i16, i32, i64, i128)>(),
get_instance_packed_len(&(i8::MAX, i16::MAX, i32::MAX, i64::MAX, i128::MAX))
.unwrap(),
);
}

#[test]
fn instance_packed_len_with_vec() {
let parent = vec![
[0u8; 64], [1u8; 64], [2u8; 64], [3u8; 64], [4u8; 64], [5u8; 64],
];
assert_eq!(
get_instance_packed_len(&parent).unwrap(),
4 + parent.len() * get_packed_len::<Child>()
);
}

#[test]
fn instance_packed_len_with_varying_sizes_in_hashmap() {
let mut data = HashMap::new();
let key1 = "the first string, it's actually really really long".to_string();
let value1 = "".to_string();
let key2 = "second string, shorter".to_string();
let value2 = "a real value".to_string();
let key3 = "third".to_string();
let value3 = "an even longer value".to_string();
data.insert(key1.clone(), value1.clone());
data.insert(key2.clone(), value2.clone());
data.insert(key3.clone(), value3.clone());
assert_eq!(
get_instance_packed_len(&data).unwrap(),
4 + get_instance_packed_len(&key1).unwrap()
+ get_instance_packed_len(&value1).unwrap()
+ get_instance_packed_len(&key2).unwrap()
+ get_instance_packed_len(&value2).unwrap()
+ get_instance_packed_len(&key3).unwrap()
+ get_instance_packed_len(&value3).unwrap()
);
}
};
}
#[cfg(test)]
pub(crate) use impl_tests;
189 changes: 2 additions & 187 deletions sdk/program/src/borsh0_10.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,191 +12,6 @@ impl_get_instance_packed_len!(borsh);

#[cfg(test)]
mod tests {
use {
super::*,
borsh::{maybestd::io::ErrorKind, BorshDeserialize, BorshSchema, BorshSerialize},
std::{collections::HashMap, mem::size_of},
};

#[derive(PartialEq, Eq, Clone, Debug, BorshSerialize, BorshDeserialize, BorshSchema)]
enum TestEnum {
NoValue,
Number(u32),
Struct {
#[allow(dead_code)]
number: u64,
#[allow(dead_code)]
array: [u8; 8],
},
}

// for test simplicity
impl Default for TestEnum {
fn default() -> Self {
Self::NoValue
}
}

#[derive(Default, BorshSerialize, BorshDeserialize, BorshSchema)]
struct TestStruct {
pub array: [u64; 16],
pub number_u128: u128,
pub number_u32: u32,
pub tuple: (u8, u16),
pub enumeration: TestEnum,
pub r#bool: bool,
}

#[derive(Debug, PartialEq, Eq, BorshSerialize, BorshDeserialize, BorshSchema)]
struct Child {
pub data: [u8; 64],
}

#[derive(Debug, PartialEq, Eq, BorshSerialize, BorshDeserialize, BorshSchema)]
struct Parent {
pub data: Vec<Child>,
}

#[test]
fn unchecked_deserialization() {
let data = vec![
Child { data: [0u8; 64] },
Child { data: [1u8; 64] },
Child { data: [2u8; 64] },
];
let parent = Parent { data };

// exact size, both work
let mut byte_vec = vec![0u8; 4 + get_packed_len::<Child>() * 3];
let mut bytes = byte_vec.as_mut_slice();
parent.serialize(&mut bytes).unwrap();
let deserialized = Parent::try_from_slice(&byte_vec).unwrap();
assert_eq!(deserialized, parent);
let deserialized = try_from_slice_unchecked::<Parent>(&byte_vec).unwrap();
assert_eq!(deserialized, parent);

// too big, only unchecked works
let mut byte_vec = vec![0u8; 4 + get_packed_len::<Child>() * 10];
let mut bytes = byte_vec.as_mut_slice();
parent.serialize(&mut bytes).unwrap();
let err = Parent::try_from_slice(&byte_vec).unwrap_err();
assert_eq!(err.kind(), ErrorKind::InvalidData);
let deserialized = try_from_slice_unchecked::<Parent>(&byte_vec).unwrap();
assert_eq!(deserialized, parent);
}

#[test]
fn packed_len() {
assert_eq!(
get_packed_len::<TestEnum>(),
size_of::<u8>() + size_of::<u64>() + u8::BITS as usize
);
assert_eq!(
get_packed_len::<TestStruct>(),
size_of::<u64>() * 16
+ size_of::<bool>()
+ size_of::<u128>()
+ size_of::<u32>()
+ size_of::<u8>()
+ size_of::<u16>()
+ get_packed_len::<TestEnum>()
);
}

#[test]
fn instance_packed_len_matches_packed_len() {
let enumeration = TestEnum::Struct {
number: u64::MAX,
array: [255; 8],
};
assert_eq!(
get_packed_len::<TestEnum>(),
get_instance_packed_len(&enumeration).unwrap(),
);
let test_struct = TestStruct {
enumeration,
..TestStruct::default()
};
assert_eq!(
get_packed_len::<TestStruct>(),
get_instance_packed_len(&test_struct).unwrap(),
);
assert_eq!(
get_packed_len::<u8>(),
get_instance_packed_len(&0u8).unwrap(),
);
assert_eq!(
get_packed_len::<u16>(),
get_instance_packed_len(&0u16).unwrap(),
);
assert_eq!(
get_packed_len::<u32>(),
get_instance_packed_len(&0u32).unwrap(),
);
assert_eq!(
get_packed_len::<u64>(),
get_instance_packed_len(&0u64).unwrap(),
);
assert_eq!(
get_packed_len::<u128>(),
get_instance_packed_len(&0u128).unwrap(),
);
assert_eq!(
get_packed_len::<[u8; 10]>(),
get_instance_packed_len(&[0u8; 10]).unwrap(),
);
assert_eq!(
get_packed_len::<(i8, i16, i32, i64, i128)>(),
get_instance_packed_len(&(i8::MAX, i16::MAX, i32::MAX, i64::MAX, i128::MAX)).unwrap(),
);
}

#[test]
fn instance_packed_len_with_vec() {
let data = vec![
Child { data: [0u8; 64] },
Child { data: [1u8; 64] },
Child { data: [2u8; 64] },
Child { data: [3u8; 64] },
Child { data: [4u8; 64] },
Child { data: [5u8; 64] },
];
let parent = Parent { data };
assert_eq!(
get_instance_packed_len(&parent).unwrap(),
4 + parent.data.len() * get_packed_len::<Child>()
);
}

#[derive(Debug, PartialEq, Eq, BorshSerialize, BorshDeserialize, BorshSchema)]
struct StructWithHashMap {
data: HashMap<String, TestEnum>,
}

#[test]
fn instance_packed_len_with_varying_sizes_in_hashmap() {
let mut data = HashMap::new();
let string1 = "the first string, it's actually really really long".to_string();
let enum1 = TestEnum::NoValue;
let string2 = "second string, shorter".to_string();
let enum2 = TestEnum::Number(u32::MAX);
let string3 = "third".to_string();
let enum3 = TestEnum::Struct {
number: 0,
array: [0; 8],
};
data.insert(string1.clone(), enum1.clone());
data.insert(string2.clone(), enum2.clone());
data.insert(string3.clone(), enum3.clone());
let instance = StructWithHashMap { data };
assert_eq!(
get_instance_packed_len(&instance).unwrap(),
4 + get_instance_packed_len(&string1).unwrap()
+ get_instance_packed_len(&enum1).unwrap()
+ get_instance_packed_len(&string2).unwrap()
+ get_instance_packed_len(&enum2).unwrap()
+ get_instance_packed_len(&string3).unwrap()
+ get_instance_packed_len(&enum3).unwrap()
);
}
use crate::borsh::impl_tests;
impl_tests!(borsh);
}
Loading

0 comments on commit 59962d7

Please sign in to comment.