From 5b4db296d5249cb7affc309c3c21e6c1248368e5 Mon Sep 17 00:00:00 2001
From: Georgy Moshkin <gmoshkin@picodata.io>
Date: Fri, 10 Nov 2023 20:44:15 +0300
Subject: [PATCH] test: add tests to check instance & replicaset structs match
 their space formats

---
 src/instance.rs   | 17 +++++++++++++++++
 src/replicaset.rs | 14 ++++++++++++++
 src/storage.rs    |  2 +-
 src/util.rs       | 42 ++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 74 insertions(+), 1 deletion(-)

diff --git a/src/instance.rs b/src/instance.rs
index 138c192be1..b81899e1ad 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 0e5c4f421e..2be5958629 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 fd1f114a03..a374682df0 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 c64a570da8..53c5512fb0 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)]
-- 
GitLab