use super::*;
use ic_principal::Principal;
use proptest::array::uniform20;
use proptest::collection::vec as pvec;
use proptest::prelude::*;
proptest! {
#[test]
fn tuple_roundtrip(x in any::<u64>(), y in uniform20(any::<u8>())) {
let tuple = (x, y);
let bytes = tuple.to_bytes();
prop_assert_eq!(bytes.len(), 28);
prop_assert_eq!(tuple, Storable::from_bytes(bytes));
}
#[test]
fn tuple_with_three_elements_fixed_size_roundtrip(x in any::<u64>(), y in uniform20(any::<u8>()), z in uniform20(any::<u8>())) {
let tuple = (x, y, z);
let bytes = tuple.to_bytes();
prop_assert_eq!(bytes.len(), 48);
prop_assert_eq!(tuple, Storable::from_bytes(bytes));
}
#[test]
fn tuple_with_three_unbounded_elements_roundtrip(v1 in pvec(any::<u8>(), 0..4), v2 in pvec(any::<u8>(), 0..8), v3 in pvec(any::<u8>(), 0..12)) {
let tuple = (v1, v2, v3);
assert_eq!(tuple, Storable::from_bytes(tuple.to_bytes()));
}
#[test]
fn tuple_with_three_elements_bounded_and_unbounded_roundtrip(x in pvec(any::<u8>(), 4..5), y in any::<u64>(), z in pvec(any::<u8>(), 12..13)) {
let tuple = (x, y, z);
let tuple_copy = tuple.clone();
let bytes = tuple_copy.to_bytes();
prop_assert_eq!(bytes.len(), 26);
prop_assert_eq!(tuple, Storable::from_bytes(bytes));
}
#[test]
fn tuple_variable_width_u8_roundtrip(x in any::<u64>(), v in pvec(any::<u8>(), 0..40)) {
let bytes = Blob::<48>::try_from(&v[..]).unwrap();
let tuple = (x, bytes);
prop_assert_eq!(tuple, Storable::from_bytes(tuple.to_bytes()));
}
#[test]
fn tuple_with_three_elements_variable_width_u8_roundtrip(x in any::<u64>(), v1 in pvec(any::<u8>(), 0..40), v2 in pvec(any::<u8>(), 0..80)) {
let v1_bytes = Blob::<40>::try_from(&v1[..]).unwrap();
let v2_bytes = Blob::<80>::try_from(&v2[..]).unwrap();
let tuple = (x, v1_bytes, v2_bytes);
prop_assert_eq!(tuple, Storable::from_bytes(tuple.to_bytes()));
}
#[test]
fn tuple_variable_width_u16_roundtrip(x in any::<u64>(), v in pvec(any::<u8>(), 0..40)) {
let bytes = Blob::<300>::try_from(&v[..]).unwrap();
let tuple = (x, bytes);
prop_assert_eq!(tuple, Storable::from_bytes(tuple.to_bytes()));
}
#[test]
fn tuple_with_three_elements_variable_width_u16_roundtrip(x in any::<u64>(), v1 in pvec(any::<u8>(), 0..40), v2 in pvec(any::<u8>(), 0..80)) {
let v1_bytes = Blob::<300>::try_from(&v1[..]).unwrap();
let v2_bytes = Blob::<300>::try_from(&v2[..]).unwrap();
let tuple = (x, v1_bytes, v2_bytes);
prop_assert_eq!(tuple, Storable::from_bytes(tuple.to_bytes()));
}
#[test]
fn f64_roundtrip(v in any::<f64>()) {
prop_assert_eq!(v, Storable::from_bytes(v.to_bytes()));
}
#[test]
fn f32_roundtrip(v in any::<f32>()) {
prop_assert_eq!(v, Storable::from_bytes(v.to_bytes()));
}
#[test]
fn optional_f64_roundtrip(v in proptest::option::of(any::<f64>())) {
prop_assert_eq!(v, Storable::from_bytes(v.to_bytes()));
}
#[test]
fn optional_string_roundtrip(v in proptest::option::of(any::<String>())) {
prop_assert_eq!(v.clone(), Storable::from_bytes(v.to_bytes()));
}
#[test]
fn optional_tuple_roundtrip(v in proptest::option::of((any::<u64>(), uniform20(any::<u8>())))) {
prop_assert_eq!(v, Storable::from_bytes(v.to_bytes()));
}
#[test]
fn optional_tuple_with_three_elements_roundtrip(v in proptest::option::of((any::<u64>(), uniform20(any::<u8>()), uniform20(any::<u8>())))) {
prop_assert_eq!(v, Storable::from_bytes(v.to_bytes()));
}
#[test]
fn optional_tuple_with_three_unbounded_elements_roundtrip(v in proptest::option::of((pvec(any::<u8>(), 0..4), pvec(any::<u8>(), 0..8), pvec(any::<u8>(), 0..12)))) {
prop_assert_eq!(v.clone(), Storable::from_bytes(v.to_bytes()));
}
#[test]
fn optional_tuple_variable_width_u8_roundtrip(v in proptest::option::of((any::<u64>(), pvec(any::<u8>(), 0..40)))) {
let v = v.map(|(n, bytes)| (n, Blob::<48>::try_from(&bytes[..]).unwrap()));
prop_assert_eq!(v, Storable::from_bytes(v.to_bytes()));
}
#[test]
fn optional_tuple_with_three_elements_variable_width_u8_roundtrip(v in proptest::option::of((any::<u64>(), pvec(any::<u8>(), 0..40), pvec(any::<u8>(), 0..80)))) {
let v = v.map(|(n, bytes_1, bytes_2)| (n, Blob::<40>::try_from(&bytes_1[..]).unwrap(), Blob::<80>::try_from(&bytes_2[..]).unwrap()));
prop_assert_eq!(v, Storable::from_bytes(v.to_bytes()));
}
#[test]
fn optional_tuple_with_three_elements_bounded_and_unbounded_roundtrip(v in proptest::option::of((any::<u64>(), pvec(any::<u8>(), 0..40), pvec(any::<u8>(), 0..80)))) {
prop_assert_eq!(v.clone(), Storable::from_bytes(v.to_bytes()));
}
#[test]
fn principal_roundtrip(mut bytes in pvec(any::<u8>(), 0..=28), tag in proptest::prop_oneof![Just(1),Just(2),Just(3),Just(4),Just(7)]) {
bytes.push(tag);
let principal = Principal::from_slice(bytes.as_slice());
prop_assert_eq!(principal, Storable::from_bytes(principal.to_bytes()));
}
}
#[test]
#[should_panic(expected = "expected an element with length <= 1 bytes, but found 4")]
fn to_bytes_checked_element_too_long_panics() {
struct X;
impl Storable for X {
fn to_bytes(&self) -> Cow<'_, [u8]> {
Cow::Borrowed(&[1, 2, 3, 4])
}
fn into_bytes(self) -> Vec<u8> {
self.to_bytes().into_owned()
}
fn from_bytes(_: Cow<[u8]>) -> Self {
unimplemented!();
}
const BOUND: Bound = Bound::Bounded {
max_size: 1,
is_fixed_size: false,
};
}
X.to_bytes_checked();
}
#[test]
fn to_bytes_checked_unbounded_element_no_panic() {
struct X;
impl Storable for X {
fn to_bytes(&self) -> Cow<'_, [u8]> {
Cow::Borrowed(&[1, 2, 3, 4])
}
fn into_bytes(self) -> Vec<u8> {
self.to_bytes().into_owned()
}
fn from_bytes(_: Cow<[u8]>) -> Self {
unimplemented!();
}
const BOUND: Bound = Bound::Unbounded;
}
assert_eq!(X.to_bytes_checked(), Cow::Borrowed(&[1, 2, 3, 4]));
}
#[test]
fn to_bytes_checked_element_correct_size_no_panic() {
struct X;
impl Storable for X {
fn to_bytes(&self) -> Cow<'_, [u8]> {
Cow::Borrowed(&[1, 2, 3, 4])
}
fn into_bytes(self) -> Vec<u8> {
self.to_bytes().into_owned()
}
fn from_bytes(_: Cow<[u8]>) -> Self {
unimplemented!();
}
const BOUND: Bound = Bound::Bounded {
max_size: 4,
is_fixed_size: false,
};
}
assert_eq!(X.to_bytes_checked(), Cow::Borrowed(&[1, 2, 3, 4]));
}
#[test]
#[should_panic(expected = "expected a fixed-size element with length 5 bytes, but found 4")]
fn to_bytes_checked_fixed_element_wrong_size_panics() {
struct X;
impl Storable for X {
fn to_bytes(&self) -> Cow<'_, [u8]> {
Cow::Borrowed(&[1, 2, 3, 4])
}
fn into_bytes(self) -> Vec<u8> {
self.to_bytes().into_owned()
}
fn from_bytes(_: Cow<[u8]>) -> Self {
unimplemented!();
}
const BOUND: Bound = Bound::Bounded {
max_size: 5,
is_fixed_size: true,
};
}
X.to_bytes_checked();
}
#[test]
fn to_bytes_checked_fixed_element_correct_size_no_panic() {
struct X;
impl Storable for X {
fn to_bytes(&self) -> Cow<'_, [u8]> {
Cow::Borrowed(&[1, 2, 3, 4, 5])
}
fn into_bytes(self) -> Vec<u8> {
self.to_bytes().into_owned()
}
fn from_bytes(_: Cow<[u8]>) -> Self {
unimplemented!();
}
const BOUND: Bound = Bound::Bounded {
max_size: 5,
is_fixed_size: true,
};
}
assert_eq!(X.to_bytes_checked(), Cow::Borrowed(&[1, 2, 3, 4, 5]));
}
#[test]
fn storable_for_bool() {
assert!(!bool::from_bytes(false.to_bytes()));
assert!(bool::from_bytes(true.to_bytes()));
}
#[test]
fn tuple_with_three_elements_test_bound() {
assert_eq!(<(u64, u64, u64)>::BOUND.max_size(), 24);
assert!(<(u64, u64, u64)>::BOUND.is_fixed_size());
assert_eq!(<(u64, u64, Blob<8>)>::BOUND.max_size(), 24);
assert!(!<(u64, u64, Blob<8>)>::BOUND.is_fixed_size());
assert_eq!(<(Blob<8>, u64, u64)>::BOUND.max_size(), 26);
assert!(!<(Blob<8>, u64, u64)>::BOUND.is_fixed_size());
assert_eq!(<(u64, Blob<8>, u64)>::BOUND.max_size(), 26);
assert!(!<(u64, Blob<8>, u64)>::BOUND.is_fixed_size());
assert_eq!(<(Blob<8>, Blob<8>, u64)>::BOUND.max_size(), 27);
assert!(!<(Blob<8>, Blob<8>, u64)>::BOUND.is_fixed_size());
assert_eq!(<(Blob<8>, u64, Blob<8>)>::BOUND.max_size(), 26);
assert!(!<(Blob<8>, u64, Blob<8>)>::BOUND.is_fixed_size());
assert_eq!(<(u64, Blob<8>, Blob<8>)>::BOUND.max_size(), 26);
assert!(!<(u64, Blob<8>, Blob<8>)>::BOUND.is_fixed_size());
assert_eq!(<(Blob<8>, Blob<8>, Blob<8>)>::BOUND.max_size(), 27);
assert!(!<(Blob<8>, Blob<8>, Blob<8>)>::BOUND.is_fixed_size());
assert_eq!(<(Blob<8>, Blob<8>, String)>::BOUND, Bound::Unbounded);
assert_eq!(<(Blob<8>, String, Blob<8>)>::BOUND, Bound::Unbounded);
assert_eq!(<(String, Blob<8>, Blob<8>)>::BOUND, Bound::Unbounded);
assert_eq!(<(String, String, Blob<8>)>::BOUND, Bound::Unbounded);
assert_eq!(<(String, Blob<8>, String)>::BOUND, Bound::Unbounded);
assert_eq!(<(Blob<8>, String, String)>::BOUND, Bound::Unbounded);
assert_eq!(<(String, String, String)>::BOUND, Bound::Unbounded);
}