From c70030bca8bfc977d3bc515b7cb35b6d2aded0e9 Mon Sep 17 00:00:00 2001
From: librelois <elois@ifee.fr>
Date: Tue, 24 Dec 2019 00:45:01 +0100
Subject: [PATCH] [tests] dubp-indexes: add unit tests

---
 lib/dubp/indexes/src/cindex/v11.rs |  58 ++++++++++++++-
 lib/dubp/indexes/src/iindex.rs     |  41 ++++++++++-
 lib/dubp/indexes/src/iindex/v11.rs |  50 ++++++++++++-
 lib/dubp/indexes/src/lib.rs        | 112 ++++++++++++++++++++++++++++-
 lib/dubp/indexes/src/mindex/v11.rs |  55 +++++++++++++-
 lib/dubp/indexes/src/sindex/v11.rs |  62 +++++++++++++++-
 6 files changed, 371 insertions(+), 7 deletions(-)

diff --git a/lib/dubp/indexes/src/cindex/v11.rs b/lib/dubp/indexes/src/cindex/v11.rs
index a42933eb..1ea406ad 100644
--- a/lib/dubp/indexes/src/cindex/v11.rs
+++ b/lib/dubp/indexes/src/cindex/v11.rs
@@ -22,7 +22,7 @@ use dup_crypto::keys::{PubKey, Sig};
 /// CINDEX datas
 pub type CIndexV11 = Index<(PubKey, PubKey), CIndexV11Line>;
 
-#[derive(Clone, Copy, Debug)]
+#[derive(Clone, Copy, Debug, PartialEq)]
 /// CINDEX line
 pub struct CIndexV11Line {
     op: IndexLineOp,
@@ -55,3 +55,59 @@ impl MergeIndexLine for CIndexV11Line {
             .map(|v| self.replayable_on.replace(v));
     }
 }
+
+#[cfg(test)]
+mod tests {
+
+    use super::*;
+    use dubp_common_doc::{BlockHash, BlockNumber};
+    use dup_crypto::hashs::Hash;
+
+    #[test]
+    fn test_iindex_merge_2_lines() {
+        let mut line1 = CIndexV11Line {
+            op: IndexLineOp(true),
+            issuer: PubKey::default(),
+            receiver: PubKey::default(),
+            created_on: Some(Blockstamp::default()),
+            written_on: Some(Blockstamp::default()),
+            sig: None,
+            expires_on: Some(5),
+            expired_on: 0,
+            chainable_on: Some(1),
+            replayable_on: Some(2),
+        };
+        let b2 = Blockstamp {
+            id: BlockNumber(2),
+            hash: BlockHash(Hash::default()),
+        };
+        let line2 = CIndexV11Line {
+            op: IndexLineOp(false),
+            issuer: PubKey::default(),
+            receiver: PubKey::default(),
+            created_on: None,
+            written_on: Some(b2),
+            sig: None,
+            expires_on: Some(7),
+            expired_on: 0,
+            chainable_on: Some(3),
+            replayable_on: Some(4),
+        };
+        line1.merge_index_line(line2);
+        assert_eq!(
+            line1,
+            CIndexV11Line {
+                op: IndexLineOp(false),
+                issuer: PubKey::default(),
+                receiver: PubKey::default(),
+                created_on: Some(Blockstamp::default()),
+                written_on: Some(b2),
+                sig: None,
+                expires_on: Some(7),
+                expired_on: 0,
+                chainable_on: Some(3),
+                replayable_on: Some(4),
+            }
+        )
+    }
+}
diff --git a/lib/dubp/indexes/src/iindex.rs b/lib/dubp/indexes/src/iindex.rs
index ce8e1110..d7ac763e 100644
--- a/lib/dubp/indexes/src/iindex.rs
+++ b/lib/dubp/indexes/src/iindex.rs
@@ -25,7 +25,7 @@ use std::str::FromStr;
 
 const USERNAME_MAX_LEN: usize = 100;
 
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, Default, PartialEq)]
 /// Identity username
 pub struct Username {
     chars: UsernameChars,
@@ -41,6 +41,17 @@ impl Debug for Username {
 #[derive(Copy, Clone)]
 struct UsernameChars([char; USERNAME_MAX_LEN]);
 
+impl PartialEq for UsernameChars {
+    fn eq(&self, other: &Self) -> bool {
+        for i in 0..USERNAME_MAX_LEN {
+            if self.0[i] != other.0[i] {
+                return false;
+            }
+        }
+        true
+    }
+}
+
 impl AsMut<[char]> for UsernameChars {
     fn as_mut(&mut self) -> &mut [char] {
         &mut self.0[..]
@@ -67,7 +78,7 @@ impl ToString for Username {
 }
 
 /// Error when parsing username
-#[derive(Clone, Copy, Debug)]
+#[derive(Clone, Copy, Debug, PartialEq)]
 pub enum ParseUsernameErr {
     /// username too long
     UsernameTooLong,
@@ -95,3 +106,29 @@ impl FromStr for Username {
         })
     }
 }
+
+#[cfg(test)]
+mod tests {
+
+    use super::*;
+
+    #[test]
+    fn test_username() {
+        let too_long_str = ".............................................................................................................................";
+        assert_eq!(
+            Username::from_str(too_long_str),
+            Err(ParseUsernameErr::UsernameTooLong)
+        );
+
+        let username = Username::from_str("toto").expect("fail to parse username");
+        assert_eq!(username.to_string(), String::from("toto"));
+        assert_ne!(username, Username::default());
+    }
+
+    #[test]
+    fn test_default_username() {
+        let default_username = Username::default();
+        println!("default_username={:?}", default_username);
+        assert_eq!(default_username.to_string(), String::default())
+    }
+}
diff --git a/lib/dubp/indexes/src/iindex/v11.rs b/lib/dubp/indexes/src/iindex/v11.rs
index 1856376c..b80aa132 100644
--- a/lib/dubp/indexes/src/iindex/v11.rs
+++ b/lib/dubp/indexes/src/iindex/v11.rs
@@ -24,7 +24,7 @@ use dup_crypto::keys::{PubKey, Sig};
 /// IINDEX datas
 pub type IIndexV11 = Index<PubKey, IIndexV11Line>;
 
-#[derive(Clone, Copy, Debug)]
+#[derive(Clone, Copy, Debug, PartialEq)]
 /// IINDEX line
 ///
 /// computed fields :
@@ -54,3 +54,51 @@ impl MergeIndexLine for IIndexV11Line {
         index_line.kick.map(|v| self.kick.replace(v));
     }
 }
+
+#[cfg(test)]
+mod tests {
+
+    use super::*;
+    use std::str::FromStr;
+
+    #[test]
+    fn test_iindex_merge_2_lines() {
+        let mut line1 = IIndexV11Line {
+            op: IndexLineOp(true),
+            uid: Some(Username::from_str("toto").expect("wrong username")),
+            r#pub: PubKey::default(),
+            hash: Some(Hash::default()),
+            sig: None,
+            created_on: Some(Blockstamp::default()),
+            written_on: Blockstamp::default(),
+            member: Some(true),
+            kick: Some(false),
+        };
+        let line2 = IIndexV11Line {
+            op: IndexLineOp(false),
+            uid: None,
+            r#pub: PubKey::default(),
+            hash: None,
+            sig: None,
+            created_on: None,
+            written_on: Blockstamp::default(),
+            member: Some(false),
+            kick: Some(false),
+        };
+        line1.merge_index_line(line2);
+        assert_eq!(
+            line1,
+            IIndexV11Line {
+                op: IndexLineOp(false),
+                uid: Some(Username::from_str("toto").expect("wrong username")),
+                r#pub: PubKey::default(),
+                hash: Some(Hash::default()),
+                sig: None,
+                created_on: Some(Blockstamp::default()),
+                written_on: Blockstamp::default(),
+                member: Some(false),
+                kick: Some(false),
+            }
+        )
+    }
+}
diff --git a/lib/dubp/indexes/src/lib.rs b/lib/dubp/indexes/src/lib.rs
index 4d38a8a4..54bccdb7 100644
--- a/lib/dubp/indexes/src/lib.rs
+++ b/lib/dubp/indexes/src/lib.rs
@@ -41,7 +41,7 @@ use std::hash::Hash;
 /// Stored in a boolean :
 /// CREATE encoded as true
 /// UPDATE encoded as false
-#[derive(Clone, Copy, Debug, Shrinkwrap)]
+#[derive(Clone, Copy, Debug, PartialEq, Shrinkwrap)]
 pub struct IndexLineOp(bool);
 
 /// Generic INDEX
@@ -65,6 +65,17 @@ where
     }
 }
 
+impl<ID, IndexLine> Index<ID, IndexLine>
+where
+    ID: Clone + Debug + Eq + Hash,
+    IndexLine: Clone + Debug + MergeIndexLine,
+{
+    /// Get entity state
+    pub fn get_state_by_cloning(&self, entity_id: &ID) -> Option<IndexLine> {
+        self.get_events(entity_id).map(Self::reduce_by_cloning)
+    }
+}
+
 impl<ID, IndexLine> Index<ID, IndexLine>
 where
     ID: Clone + Debug + Eq + Hash,
@@ -138,3 +149,102 @@ pub trait ReduceNotCopyableIndexLines {
         entity_state
     }
 }
+
+#[cfg(test)]
+mod tests {
+
+    use super::*;
+
+    type TestIndex = Index<usize, TestIndexLine>;
+    type TestIndexNotCopyable = Index<usize, TestIndexLineNotCopyable>;
+
+    #[derive(Clone, Copy, Debug, PartialEq)]
+    struct TestIndexLine {
+        op: IndexLineOp,
+        id: usize,
+        field: Option<bool>,
+    }
+
+    impl MergeIndexLine for TestIndexLine {
+        fn merge_index_line(&mut self, index_line: Self) {
+            self.op = index_line.op;
+            index_line.field.map(|v| self.field.replace(v));
+        }
+    }
+
+    #[derive(Clone, Debug, PartialEq)]
+    struct TestIndexLineNotCopyable {
+        op: IndexLineOp,
+        id: usize,
+        field: Option<String>,
+    }
+
+    impl MergeIndexLine for TestIndexLineNotCopyable {
+        fn merge_index_line(&mut self, index_line: Self) {
+            self.op = index_line.op;
+            index_line.field.map(|v| self.field.replace(v));
+        }
+    }
+
+    fn new_test_index() -> TestIndex {
+        let index_lines = vec![
+            TestIndexLine {
+                op: IndexLineOp(true),
+                id: 0,
+                field: Some(true),
+            },
+            TestIndexLine {
+                op: IndexLineOp(false),
+                id: 0,
+                field: None,
+            },
+        ];
+        let mut datas = HashMap::new();
+        datas.insert(0, index_lines);
+        TestIndex { datas }
+    }
+
+    fn new_test_index_not_copyable() -> TestIndexNotCopyable {
+        let index_lines = vec![
+            TestIndexLineNotCopyable {
+                op: IndexLineOp(true),
+                id: 0,
+                field: Some("toto".to_owned()),
+            },
+            TestIndexLineNotCopyable {
+                op: IndexLineOp(false),
+                id: 0,
+                field: None,
+            },
+        ];
+        let mut datas = HashMap::new();
+        datas.insert(0, index_lines);
+        TestIndexNotCopyable { datas }
+    }
+
+    #[test]
+    fn test_reduce_copyable_index() {
+        let index = new_test_index();
+        assert_eq!(
+            Some(TestIndexLine {
+                op: IndexLineOp(false),
+                id: 0,
+                field: Some(true),
+            }),
+            index.get_state(&0)
+        )
+    }
+
+    #[test]
+    fn test_reduce_not_copyable_index() {
+        let index = new_test_index_not_copyable();
+        assert_eq!(
+            Some(TestIndexLineNotCopyable {
+                op: IndexLineOp(false),
+                id: 0,
+                field: Some("toto".to_owned()),
+            }),
+            index.get_state_by_cloning(&0)
+        )
+    }
+}
diff --git a/lib/dubp/indexes/src/mindex/v11.rs b/lib/dubp/indexes/src/mindex/v11.rs
index e975c4cc..81d70b64 100644
--- a/lib/dubp/indexes/src/mindex/v11.rs
+++ b/lib/dubp/indexes/src/mindex/v11.rs
@@ -22,7 +22,7 @@ use dup_crypto::keys::{PubKey, Sig};
 /// MINDEX datas
 pub type MIndexV11 = Index<PubKey, MIndexV11Line>;
 
-#[derive(Clone, Copy, Debug)]
+#[derive(Clone, Copy, Debug, PartialEq)]
 /// MINDEX line
 ///
 /// computed fields :
@@ -57,3 +57,56 @@ impl MergeIndexLine for MIndexV11Line {
             .map(|v| self.chainable_on.replace(v));
     }
 }
+
+#[cfg(test)]
+mod tests {
+
+    use super::*;
+
+    #[test]
+    fn test_iindex_merge_2_lines() {
+        let mut line1 = MIndexV11Line {
+            op: IndexLineOp(true),
+            r#pub: PubKey::default(),
+            created_on: Some(Blockstamp::default()),
+            written_on: Blockstamp::default(),
+            expires_on: Some(0),
+            expired_on: None,
+            revokes_on: None,
+            revoked_on: None,
+            leaving: Some(false),
+            revocation: None,
+            chainable_on: Some(0),
+        };
+        let line2 = MIndexV11Line {
+            op: IndexLineOp(false),
+            r#pub: PubKey::default(),
+            created_on: None,
+            written_on: Blockstamp::default(),
+            expires_on: Some(1),
+            expired_on: None,
+            revokes_on: None,
+            revoked_on: None,
+            leaving: None,
+            revocation: None,
+            chainable_on: Some(0),
+        };
+        line1.merge_index_line(line2);
+        assert_eq!(
+            line1,
+            MIndexV11Line {
+                op: IndexLineOp(false),
+                r#pub: PubKey::default(),
+                created_on: Some(Blockstamp::default()),
+                written_on: Blockstamp::default(),
+                expires_on: Some(1),
+                expired_on: None,
+                revokes_on: None,
+                revoked_on: None,
+                leaving: Some(false),
+                revocation: None,
+                chainable_on: Some(0),
+            }
+        )
+    }
+}
diff --git a/lib/dubp/indexes/src/sindex/v11.rs b/lib/dubp/indexes/src/sindex/v11.rs
index ac788d8a..a8a13f46 100644
--- a/lib/dubp/indexes/src/sindex/v11.rs
+++ b/lib/dubp/indexes/src/sindex/v11.rs
@@ -24,7 +24,7 @@ use dup_crypto::hashs::Hash;
 /// SINDEX datas
 pub type SIndexV11 = Index<SourceUniqueIdV10, SIndexV11Line>;
 
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, PartialEq)]
 /// SINDEX line
 ///
 /// computed fields :
@@ -54,3 +54,63 @@ impl MergeIndexLine for SIndexV11Line {
         self.written_on = index_line.written_on;
     }
 }
+
+#[cfg(test)]
+mod tests {
+
+    use super::*;
+    use dubp_common_doc::{BlockHash, BlockNumber};
+    use dubp_user_docs::documents::transaction::{TransactionOutputCondition, UTXOConditionsGroup};
+    use dup_crypto::keys::PubKey;
+
+    #[test]
+    fn test_iindex_merge_2_lines() {
+        let cond = UTXOConditions {
+            origin_str: None,
+            conditions: UTXOConditionsGroup::Single(TransactionOutputCondition::Sig(
+                PubKey::default(),
+            )),
+        };
+        let mut line1 = SIndexV11Line {
+            op: IndexLineOp(true),
+            tx: None,
+            identifier_and_pos: SourceUniqueIdV10::UD(PubKey::default(), BlockNumber(0)),
+            created_on: Some(Blockstamp::default()),
+            amount: TxAmount(10),
+            base: TxBase(0),
+            locktime: 0,
+            conditions: cond.clone(),
+            written_on: Blockstamp::default(),
+        };
+        let b1 = Blockstamp {
+            id: BlockNumber(1),
+            hash: BlockHash(Hash::default()),
+        };
+        let line2 = SIndexV11Line {
+            op: IndexLineOp(false),
+            tx: None,
+            identifier_and_pos: SourceUniqueIdV10::UD(PubKey::default(), BlockNumber(0)),
+            created_on: None,
+            amount: TxAmount(10),
+            base: TxBase(0),
+            locktime: 0,
+            conditions: cond.clone(),
+            written_on: b1,
+        };
+        line1.merge_index_line(line2);
+        assert_eq!(
+            line1,
+            SIndexV11Line {
+                op: IndexLineOp(false),
+                tx: None,
+                identifier_and_pos: SourceUniqueIdV10::UD(PubKey::default(), BlockNumber(0)),
+                created_on: Some(Blockstamp::default()),
+                amount: TxAmount(10),
+                base: TxBase(0),
+                locktime: 0,
+                conditions: cond,
+                written_on: b1,
+            }
+        )
+    }
+}
-- 
GitLab