diff --git a/scylla-cql/src/types/deserialize/value.rs b/scylla-cql/src/types/deserialize/value.rs index 519bb5e3ec..bf35485ce6 100644 --- a/scylla-cql/src/types/deserialize/value.rs +++ b/scylla-cql/src/types/deserialize/value.rs @@ -1774,9 +1774,9 @@ pub(super) mod tests { use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; use std::fmt::Debug; - use std::net::{IpAddr, Ipv6Addr}; + use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; - use crate::frame::response::result::{deser_cql_value, ColumnType, CqlValue}; + use crate::frame::response::result::{ColumnType, CqlValue}; use crate::frame::value::{ Counter, CqlDate, CqlDecimal, CqlDuration, CqlTime, CqlTimestamp, CqlTimeuuid, CqlVarint, }; @@ -1807,6 +1807,14 @@ pub(super) mod tests { assert_eq!(decoded_slice, ORIGINAL_BYTES); assert_eq!(decoded_vec, ORIGINAL_BYTES); assert_eq!(decoded_bytes, ORIGINAL_BYTES); + + // ser/de identity + + // Nonempty blob + assert_ser_de_identity(&ColumnType::Blob, &ORIGINAL_BYTES, &mut Bytes::new()); + + // Empty blob + assert_ser_de_identity(&ColumnType::Blob, &(&[] as &[u8]), &mut Bytes::new()); } #[test] @@ -1815,15 +1823,23 @@ pub(super) mod tests { let ascii = make_bytes(ASCII_TEXT.as_bytes()); - let decoded_ascii_str = deserialize::<&str>(&ColumnType::Ascii, &ascii).unwrap(); - let decoded_ascii_string = deserialize::(&ColumnType::Ascii, &ascii).unwrap(); - let decoded_text_str = deserialize::<&str>(&ColumnType::Text, &ascii).unwrap(); - let decoded_text_string = deserialize::(&ColumnType::Text, &ascii).unwrap(); + for typ in [ColumnType::Ascii, ColumnType::Text].iter() { + let decoded_str = deserialize::<&str>(typ, &ascii).unwrap(); + let decoded_string = deserialize::(typ, &ascii).unwrap(); + + assert_eq!(decoded_str, ASCII_TEXT); + assert_eq!(decoded_string, ASCII_TEXT); + + // ser/de identity + + // Empty string + assert_ser_de_identity(typ, &"", &mut Bytes::new()); + assert_ser_de_identity(typ, &"".to_owned(), &mut Bytes::new()); - assert_eq!(decoded_ascii_str, ASCII_TEXT); - assert_eq!(decoded_ascii_string, ASCII_TEXT); - assert_eq!(decoded_text_str, ASCII_TEXT); - assert_eq!(decoded_text_string, ASCII_TEXT); + // Nonempty string + assert_ser_de_identity(typ, &ASCII_TEXT, &mut Bytes::new()); + assert_ser_de_identity(typ, &ASCII_TEXT.to_owned(), &mut Bytes::new()); + } } #[test] @@ -1840,6 +1856,15 @@ pub(super) mod tests { let decoded_text_string = deserialize::(&ColumnType::Text, &unicode).unwrap(); assert_eq!(decoded_text_str, UNICODE_TEXT); assert_eq!(decoded_text_string, UNICODE_TEXT); + + // ser/de identity + + assert_ser_de_identity(&ColumnType::Text, &UNICODE_TEXT, &mut Bytes::new()); + assert_ser_de_identity( + &ColumnType::Text, + &UNICODE_TEXT.to_owned(), + &mut Bytes::new(), + ); } #[test] @@ -1859,6 +1884,12 @@ pub(super) mod tests { let bigint = make_bytes(&[0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]); let decoded_bigint = deserialize::(&ColumnType::BigInt, &bigint).unwrap(); assert_eq!(decoded_bigint, 0x0102030405060708); + + // ser/de identity + assert_ser_de_identity(&ColumnType::TinyInt, &42_i8, &mut Bytes::new()); + assert_ser_de_identity(&ColumnType::SmallInt, &2137_i16, &mut Bytes::new()); + assert_ser_de_identity(&ColumnType::Int, &21372137_i32, &mut Bytes::new()); + assert_ser_de_identity(&ColumnType::BigInt, &0_i64, &mut Bytes::new()); } #[test] @@ -1867,6 +1898,9 @@ pub(super) mod tests { let boolean_bytes = make_bytes(&[boolean as u8]); let decoded_bool = deserialize::(&ColumnType::Boolean, &boolean_bytes).unwrap(); assert_eq!(decoded_bool, boolean); + + // ser/de identity + assert_ser_de_identity(&ColumnType::Boolean, &boolean, &mut Bytes::new()); } } @@ -1879,6 +1913,150 @@ pub(super) mod tests { let double = make_bytes(&[64, 0, 0, 0, 0, 0, 0, 0]); let decoded_double = deserialize::(&ColumnType::Double, &double).unwrap(); assert_eq!(decoded_double, 2.0); + + // ser/de identity + assert_ser_de_identity(&ColumnType::Float, &21.37_f32, &mut Bytes::new()); + assert_ser_de_identity(&ColumnType::Double, &2137.2137_f64, &mut Bytes::new()); + } + + #[test] + fn test_varlen_numbers() { + // varint + assert_ser_de_identity( + &ColumnType::Varint, + &CqlVarint::from_signed_bytes_be_slice(b"Ala ma kota"), + &mut Bytes::new(), + ); + + #[cfg(feature = "num-bigint-03")] + assert_ser_de_identity( + &ColumnType::Varint, + &num_bigint_03::BigInt::from_signed_bytes_be(b"Kot ma Ale"), + &mut Bytes::new(), + ); + + #[cfg(feature = "num-bigint-04")] + assert_ser_de_identity( + &ColumnType::Varint, + &num_bigint_04::BigInt::from_signed_bytes_be(b"Kot ma Ale"), + &mut Bytes::new(), + ); + + // decimal + assert_ser_de_identity( + &ColumnType::Decimal, + &CqlDecimal::from_signed_be_bytes_slice_and_exponent(b"Ala ma kota", 42), + &mut Bytes::new(), + ); + + #[cfg(feature = "bigdecimal-04")] + assert_ser_de_identity( + &ColumnType::Decimal, + &bigdecimal_04::BigDecimal::new( + bigdecimal_04::num_bigint::BigInt::from_signed_bytes_be(b"Ala ma kota"), + 42, + ), + &mut Bytes::new(), + ); + } + + #[test] + fn test_date_time_types() { + // duration + assert_ser_de_identity( + &ColumnType::Duration, + &CqlDuration { + months: 21, + days: 37, + nanoseconds: 42, + }, + &mut Bytes::new(), + ); + + // date + assert_ser_de_identity(&ColumnType::Date, &CqlDate(0xbeaf), &mut Bytes::new()); + + #[cfg(feature = "chrono")] + assert_ser_de_identity( + &ColumnType::Date, + &chrono::NaiveDate::from_yo_opt(1999, 99).unwrap(), + &mut Bytes::new(), + ); + + #[cfg(feature = "time")] + assert_ser_de_identity( + &ColumnType::Date, + &time::Date::from_ordinal_date(1999, 99).unwrap(), + &mut Bytes::new(), + ); + + // time + assert_ser_de_identity(&ColumnType::Time, &CqlTime(0xdeed), &mut Bytes::new()); + + #[cfg(feature = "chrono")] + assert_ser_de_identity( + &ColumnType::Time, + &chrono::NaiveTime::from_hms_micro_opt(21, 37, 21, 37).unwrap(), + &mut Bytes::new(), + ); + + #[cfg(feature = "time")] + assert_ser_de_identity( + &ColumnType::Time, + &time::Time::from_hms_micro(21, 37, 21, 37).unwrap(), + &mut Bytes::new(), + ); + + // timestamp + assert_ser_de_identity( + &ColumnType::Timestamp, + &CqlTimestamp(0xceed), + &mut Bytes::new(), + ); + + #[cfg(feature = "chrono")] + assert_ser_de_identity( + &ColumnType::Timestamp, + &chrono::DateTime::::from_timestamp_millis(0xdead_cafe_deaf).unwrap(), + &mut Bytes::new(), + ); + + #[cfg(feature = "time")] + assert_ser_de_identity( + &ColumnType::Timestamp, + &time::OffsetDateTime::from_unix_timestamp(0xdead_cafe).unwrap(), + &mut Bytes::new(), + ); + } + + #[test] + fn test_inet() { + assert_ser_de_identity( + &ColumnType::Inet, + &IpAddr::V4(Ipv4Addr::BROADCAST), + &mut Bytes::new(), + ); + + assert_ser_de_identity( + &ColumnType::Inet, + &IpAddr::V6(Ipv6Addr::LOCALHOST), + &mut Bytes::new(), + ); + } + + #[test] + fn test_uuid() { + assert_ser_de_identity( + &ColumnType::Uuid, + &Uuid::from_u128(0xdead_cafe_deaf_feed_beaf_bead), + &mut Bytes::new(), + ); + + assert_ser_de_identity( + &ColumnType::Timeuuid, + &CqlTimeuuid::from_u128(0xdead_cafe_deaf_feed_beaf_bead), + &mut Bytes::new(), + ); } #[test] @@ -1907,6 +2085,15 @@ pub(super) mod tests { let int = make_bytes(&[]); let decoded_int = deserialize::>>(&ColumnType::Int, &int).unwrap(); assert_eq!(decoded_int, Some(MaybeEmpty::Empty)); + + // ser/de identity + assert_ser_de_identity(&ColumnType::Int, &Some(12321_i32), &mut Bytes::new()); + assert_ser_de_identity(&ColumnType::Double, &None::, &mut Bytes::new()); + assert_ser_de_identity( + &ColumnType::Set(Box::new(ColumnType::Ascii)), + &None::>, + &mut Bytes::new(), + ); } #[test] @@ -1921,6 +2108,40 @@ pub(super) mod tests { assert_eq!(decoded_non_empty, MaybeEmpty::Value(0x01)); } + #[test] + fn test_cql_value() { + assert_ser_de_identity( + &ColumnType::Counter, + &CqlValue::Counter(Counter(765)), + &mut Bytes::new(), + ); + + assert_ser_de_identity( + &ColumnType::Timestamp, + &CqlValue::Timestamp(CqlTimestamp(2136)), + &mut Bytes::new(), + ); + + assert_ser_de_identity(&ColumnType::Boolean, &CqlValue::Empty, &mut Bytes::new()); + + assert_ser_de_identity( + &ColumnType::Text, + &CqlValue::Text("kremówki".to_owned()), + &mut Bytes::new(), + ); + assert_ser_de_identity( + &ColumnType::Ascii, + &CqlValue::Ascii("kremowy".to_owned()), + &mut Bytes::new(), + ); + + assert_ser_de_identity( + &ColumnType::Set(Box::new(ColumnType::Text)), + &CqlValue::Set(vec![CqlValue::Text("Ala ma kota".to_owned())]), + &mut Bytes::new(), + ); + } + #[test] fn test_list_and_set() { let mut collection_contents = BytesMut::new(); @@ -1973,6 +2194,20 @@ pub(super) mod tests { decoded_btree_string, expected_vec_string.into_iter().collect(), ); + + // ser/de identity + assert_ser_de_identity(&list_typ, &vec!["qwik"], &mut Bytes::new()); + assert_ser_de_identity(&set_typ, &vec!["qwik"], &mut Bytes::new()); + assert_ser_de_identity( + &set_typ, + &HashSet::<&str, std::collections::hash_map::RandomState>::from_iter(["qwik"]), + &mut Bytes::new(), + ); + assert_ser_de_identity( + &set_typ, + &BTreeSet::<&str>::from_iter(["qwik"]), + &mut Bytes::new(), + ); } #[test] @@ -2020,7 +2255,21 @@ pub(super) mod tests { decoded_btree_str, expected_str.clone().into_iter().collect(), ); - assert_eq!(decoded_btree_string, expected_string.into_iter().collect(),); + assert_eq!(decoded_btree_string, expected_string.into_iter().collect()); + + // ser/de identity + assert_ser_de_identity( + &typ, + &HashMap::::from_iter([( + -42, "qwik", + )]), + &mut Bytes::new(), + ); + assert_ser_de_identity( + &typ, + &BTreeMap::::from_iter([(-42, "qwik")]), + &mut Bytes::new(), + ); } #[test] @@ -2036,6 +2285,37 @@ pub(super) mod tests { let tup = deserialize::<(i32, &str, Option)>(&typ, &tuple).unwrap(); assert_eq!(tup, (42, "foo", None)); + + // ser/de identity + + // () does not implement SerializeValue, yet it does implement DeserializeValue. + // assert_ser_de_identity(&ColumnType::Tuple(vec![]), &(), &mut Bytes::new()); + + // nonempty, varied tuple + assert_ser_de_identity( + &ColumnType::Tuple(vec![ + ColumnType::List(Box::new(ColumnType::Boolean)), + ColumnType::BigInt, + ColumnType::Uuid, + ColumnType::Inet, + ]), + &( + vec![true, false, true], + 42_i64, + Uuid::from_u128(0xdead_cafe_deaf_feed_beaf_bead), + IpAddr::V6(Ipv6Addr::new(0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11)), + ), + &mut Bytes::new(), + ); + + // nested tuples + assert_ser_de_identity( + &ColumnType::Tuple(vec![ColumnType::Tuple(vec![ColumnType::Tuple(vec![ + ColumnType::Text, + ])])]), + &((("",),),), + &mut Bytes::new(), + ); } #[test] @@ -2105,13 +2385,6 @@ pub(super) mod tests { *buf = v.into(); } - fn make_ip_address(ip: IpAddr) -> Bytes { - match ip { - IpAddr::V4(v4) => make_bytes(&v4.octets()), - IpAddr::V6(v6) => make_bytes(&v6.octets()), - } - } - fn append_bytes(b: &mut impl BufMut, cell: &[u8]) { b.put_i32(cell.len() as i32); b.put_slice(cell); @@ -2127,6 +2400,17 @@ pub(super) mod tests { b.put_i32(-1); } + fn assert_ser_de_identity<'f, T: SerializeValue + DeserializeValue<'f> + PartialEq + Debug>( + typ: &'f ColumnType, + v: &'f T, + buf: &'f mut Bytes, // `buf` must be passed as a reference from outside, because otherwise + // we cannot specify the lifetime for DeserializeValue. + ) { + serialize_to_buf(typ, v, buf); + let deserialized = deserialize::(typ, buf).unwrap(); + assert_eq!(&deserialized, v); + } + /* Errors checks */ #[track_caller]