diff --git a/src/instance.rs b/src/instance.rs index 138c192be17dbe539fbb2c55ebb64fef6d88892a..b81899e1ade64d80c5eede04647543cf7fc8186c 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -603,5 +603,22 @@ mod tests { "tier \"noexistent_tier\" for current instance should exists", ); } +} +#[cfg(test)] +mod test { + use super::*; + use tarantool::tuple::ToTupleBuffer; + + #[test] + fn matches_format() { + let i = Instance::default(); + let tuple_data = i.to_tuple_buffer().unwrap(); + let format = crate::storage::instance_format(); + crate::util::check_tuple_matches_format( + tuple_data.as_ref(), + &format, + "define_instance_fields", + ); + } } diff --git a/src/replicaset.rs b/src/replicaset.rs index 0e5c4f421e671632a525387c1b2f0363967243cd..2be5958629cf983e3664e6800c528d864b5face3 100644 --- a/src/replicaset.rs +++ b/src/replicaset.rs @@ -114,3 +114,17 @@ impl std::fmt::Display for Replicaset { UpToDate = "up-to-date", } } + +#[cfg(test)] +mod tests { + use super::*; + use tarantool::tuple::ToTupleBuffer; + + #[test] + fn matches_format() { + let r = Replicaset::replicaset_for_tests(); + let tuple_data = r.to_tuple_buffer().unwrap(); + let format = Replicaset::format(); + crate::util::check_tuple_matches_format(tuple_data.as_ref(), &format, "Replicaset::format"); + } +} diff --git a/src/storage.rs b/src/storage.rs index fd1f114a035964839df9e8b0fc4e15f4423a5246..a374682df0b47eeda396551922c481ffe7837178 100644 --- a/src/storage.rs +++ b/src/storage.rs @@ -1572,7 +1572,7 @@ macro_rules! define_instance_fields { )+ } - fn instance_format() -> Vec<::tarantool::space::Field> { + pub fn instance_format() -> Vec<::tarantool::space::Field> { vec![ $( ::tarantool::space::Field::from(($name, $tt_ty)), )+ ] diff --git a/src/util.rs b/src/util.rs index c64a570da84a32cad957aa4ea6b5d74f0db8fd39..53c5512fb0d036bbf26b6af5ddd0cfa4f72e7964 100644 --- a/src/util.rs +++ b/src/util.rs @@ -598,6 +598,48 @@ pub(crate) fn effective_user_id() -> UserId { session::euid().expect("infallible in picodata") } +#[cfg(test)] +use tarantool::space::Field; +#[cfg(test)] +#[track_caller] +pub fn check_tuple_matches_format(tuple: &[u8], format: &[Field], what_to_fix: &str) { + use tarantool::space::FieldType; + use tarantool::tuple::Decode; + + let value = rmpv::Value::decode(tuple).unwrap(); + let fields = value.as_array().unwrap(); + assert_eq!( + fields.len(), + format.len(), + "don't forget to update {what_to_fix}!" + ); + + for i in 0..fields.len() { + let field = &fields[i]; + let field_type = format[i].field_type; + let field_name = &format[i].name; + let ok = match field_type { + FieldType::Any => true, + FieldType::Unsigned => field.is_u64(), + FieldType::String => field.is_str(), + FieldType::Number => field.is_number(), + FieldType::Double => field.is_f32() || field.is_f64(), + FieldType::Integer => field.is_i64(), + FieldType::Boolean => field.is_bool(), + FieldType::Varbinary => todo!(), + FieldType::Scalar => todo!(), + FieldType::Decimal | FieldType::Uuid | FieldType::Datetime | FieldType::Interval => { + field.is_ext() + } + FieldType::Array => field.is_array(), + FieldType::Map => field.is_map(), + }; + if !ok { + panic!("expected field '{field_name}' to be {field_type:?}, but got {field:?}"); + } + } +} + //////////////////////////////////////////////////////////////////////////////// /// tests #[cfg(test)]