etopay_sdk/core/
share.rs

1//! The share module provides functionality for dealing with shares of the user wallet mnemonic.
2
3use super::Sdk;
4use crate::error::Result;
5use crate::share::Share;
6use log::info;
7
8impl Sdk {
9    /// Get/download the recovery share.
10    ///
11    /// # Returns
12    ///
13    /// The recovery share, or `None` if none exists.
14    ///
15    /// # Error
16    ///
17    /// Returns error if the user is not initialized.
18    pub async fn get_recovery_share(&self) -> Result<Option<Share>> {
19        info!("Getting recovery share");
20        let Some(active_user) = &self.active_user else {
21            return Err(crate::Error::UserNotInitialized);
22        };
23        Ok(active_user.wallet_manager.get_recovery_share())
24    }
25
26    /// Set/upload the recovery share.
27    ///
28    /// # Arguments
29    ///
30    /// * `share` - The recovery share to upload.
31    ///
32    /// # Error
33    ///
34    /// Returns error if the user is not initialized.
35    pub async fn set_recovery_share(&mut self, share: Share) -> Result<()> {
36        info!("Setting recovery share");
37        let Some(active_user) = &mut self.active_user else {
38            return Err(crate::Error::UserNotInitialized);
39        };
40        active_user.wallet_manager.set_recovery_share(Some(share));
41        Ok(())
42    }
43}
44
45#[cfg(test)]
46mod tests {
47    use crate::core::core_testing_utils::handle_error_test_cases;
48    use crate::{
49        core::Sdk,
50        error::Result,
51        share::Share,
52        testing_utils::{USERNAME, set_config},
53        wallet_manager::MockWalletManager,
54    };
55    use mockall::predicate::eq;
56    use rstest::rstest;
57    use secrecy::ExposeSecret;
58
59    fn example_share() -> String {
60        Share::mock_share().to_string().expose_secret().to_owned()
61    }
62
63    #[rstest]
64    #[case::success(Ok(example_share()))]
65    #[case::user_init_error(Err(crate::Error::UserNotInitialized))]
66    #[tokio::test]
67    async fn test_get_recovery_share(#[case] expected: Result<String>) {
68        // Arrange
69        let (_srv, config, _cleanup) = set_config().await;
70        let mut sdk = Sdk::new(config).unwrap();
71
72        match &expected {
73            Ok(_) => {
74                let mut mock_wallet_manager = MockWalletManager::new();
75                mock_wallet_manager
76                    .expect_get_recovery_share()
77                    .once()
78                    .returning(|| Some(Share::mock_share()));
79                sdk.active_user = Some(crate::types::users::ActiveUser {
80                    username: USERNAME.into(),
81                    wallet_manager: Box::new(mock_wallet_manager),
82                    mnemonic_derivation_options: Default::default(),
83                });
84            }
85            Err(error) => {
86                handle_error_test_cases(error, &mut sdk, 0, 0).await;
87            }
88        }
89
90        // Act
91        let response = sdk.get_recovery_share().await;
92
93        // Assert
94        match expected {
95            Ok(resp) => {
96                assert_eq!(response.unwrap().unwrap().to_string().expose_secret(), resp);
97            }
98            Err(ref expected_err) => {
99                assert_eq!(response.err().unwrap().to_string(), expected_err.to_string());
100            }
101        }
102    }
103
104    #[rstest]
105    #[case::success(Ok(()))]
106    #[case::user_init_error(Err(crate::Error::UserNotInitialized))]
107    #[tokio::test]
108    async fn test_set_recovery_share(#[case] expected: Result<()>) {
109        // Arrange
110        let (_srv, config, _cleanup) = set_config().await;
111        let mut sdk = Sdk::new(config).unwrap();
112
113        match &expected {
114            Ok(_) => {
115                let mut mock_wallet_manager = MockWalletManager::new();
116                mock_wallet_manager
117                    .expect_set_recovery_share()
118                    .once()
119                    .with(eq(Some(Share::mock_share())))
120                    .returning(|_share| ());
121                sdk.active_user = Some(crate::types::users::ActiveUser {
122                    username: USERNAME.into(),
123                    wallet_manager: Box::new(mock_wallet_manager),
124                    mnemonic_derivation_options: Default::default(),
125                });
126            }
127            Err(error) => {
128                handle_error_test_cases(error, &mut sdk, 0, 0).await;
129            }
130        }
131
132        // Act
133        let response = sdk.set_recovery_share(Share::mock_share()).await;
134
135        // Assert
136        match expected {
137            Ok(()) => response.unwrap(),
138            Err(ref expected_err) => {
139                assert_eq!(response.err().unwrap().to_string(), expected_err.to_string());
140            }
141        }
142    }
143}