Skip to main content

smplx_test/
context.rs

1use std::path::PathBuf;
2
3use electrsd::bitcoind::bitcoincore_rpc::Auth;
4
5use smplx_regtest::Regtest;
6use smplx_regtest::client::RegtestClient;
7
8use smplx_sdk::global::set_global_config;
9use smplx_sdk::provider::{
10    ElementsRpc, EsploraProvider, ProviderInfo, ProviderTrait, SimplexProvider, SimplicityNetwork,
11};
12use smplx_sdk::signer::Signer;
13use smplx_sdk::utils::random_mnemonic;
14
15use crate::config::TestConfig;
16use crate::error::TestError;
17use crate::network_utils::NetworkUtils;
18
19#[allow(dead_code)]
20pub struct TestContext {
21    _client: Option<RegtestClient>,
22    // since providers can't be cloned, we need this variable to create new signers
23    _provider_info: ProviderInfo,
24    config: TestConfig,
25    signer: Signer,
26}
27
28impl TestContext {
29    pub fn new(config_path: PathBuf) -> Result<Self, TestError> {
30        let config = TestConfig::from_file(&config_path)?;
31
32        // error is ignored because we assume that all tests use the same verbosity
33        let _ = set_global_config(
34            config
35                .verbosity
36                .expect("This will be set")
37                .try_into()
38                .expect("Validated in CLI"),
39        );
40
41        let (signer, provider_info, client) = Self::setup(&config)?;
42
43        Ok(Self {
44            _client: client,
45            _provider_info: provider_info,
46            config,
47            signer,
48        })
49    }
50
51    pub fn create_signer(&self, mnemonic: &str) -> Signer {
52        let provider: Box<dyn ProviderTrait> = if self._provider_info.elements_url.is_some() {
53            // local regtest or external regtest
54            Box::new(SimplexProvider::new(
55                self._provider_info.esplora_url.clone(),
56                self._provider_info.elements_url.clone().unwrap(),
57                self._provider_info.auth.clone().unwrap(),
58                *self.get_network(),
59            ))
60        } else {
61            // external esplora
62            Box::new(EsploraProvider::new(
63                self._provider_info.esplora_url.clone(),
64                *self.get_network(),
65            ))
66        };
67
68        Signer::new(mnemonic, provider)
69    }
70
71    pub fn random_signer(&self) -> Signer {
72        self.create_signer(random_mnemonic().as_str())
73    }
74
75    pub fn get_default_signer(&self) -> &Signer {
76        &self.signer
77    }
78
79    pub fn get_default_provider(&self) -> &dyn ProviderTrait {
80        self.signer.get_provider()
81    }
82
83    pub fn get_config(&self) -> &TestConfig {
84        &self.config
85    }
86
87    pub fn get_network(&self) -> &SimplicityNetwork {
88        self.signer.get_provider().get_network()
89    }
90
91    pub fn get_network_utils(&self) -> NetworkUtils {
92        assert!(
93            self._client.is_some(),
94            "Network utils only available in Regtest network"
95        );
96
97        let regtest_rpc = ElementsRpc::new(
98            self._provider_info.elements_url.clone().unwrap(),
99            self._provider_info.auth.clone().unwrap(),
100        )
101        .expect("Failed to create rpc client for network utils");
102
103        let network = self.get_network();
104        let esplora = EsploraProvider::new(self._provider_info.esplora_url.clone(), *network);
105
106        NetworkUtils::new(regtest_rpc, esplora)
107    }
108
109    fn setup(config: &TestConfig) -> Result<(Signer, ProviderInfo, Option<RegtestClient>), TestError> {
110        let client: Option<RegtestClient>;
111        let provider_info: ProviderInfo;
112        let signer: Signer;
113
114        match config.esplora.clone() {
115            Some(esplora) => match config.rpc.clone() {
116                Some(rpc) => {
117                    // custom regtest case
118                    let auth = Auth::UserPass(rpc.username, rpc.password);
119                    let provider = Box::new(SimplexProvider::new(
120                        esplora.url.clone(),
121                        rpc.url.clone(),
122                        auth.clone(),
123                        SimplicityNetwork::default_regtest(),
124                    ));
125
126                    provider_info = ProviderInfo {
127                        esplora_url: esplora.url,
128                        elements_url: Some(rpc.url),
129                        auth: Some(auth),
130                    };
131                    signer = Signer::new(config.mnemonic.as_str(), provider);
132                    client = None;
133                }
134                None => {
135                    // external esplora network
136                    let network = match esplora.network.as_str() {
137                        "Liquid" => SimplicityNetwork::Liquid,
138                        "LiquidTestnet" => SimplicityNetwork::LiquidTestnet,
139                        "ElementsRegtest" => SimplicityNetwork::default_regtest(),
140                        other => return Err(TestError::BadNetworkName(other.to_string())),
141                    };
142                    let provider = Box::new(EsploraProvider::new(esplora.url.clone(), network));
143
144                    provider_info = ProviderInfo {
145                        esplora_url: esplora.url,
146                        elements_url: None,
147                        auth: None,
148                    };
149                    signer = Signer::new(config.mnemonic.as_str(), provider);
150                    client = None;
151                }
152            },
153            None => {
154                // simplex inner network
155                let (regtest_client, regtest_signer) = Regtest::from_config(&config.to_regtest_config())?;
156
157                provider_info = ProviderInfo {
158                    esplora_url: regtest_client.esplora_url(),
159                    elements_url: Some(regtest_client.rpc_url()),
160                    auth: Some(regtest_client.auth()),
161                };
162                signer = regtest_signer;
163                client = Some(regtest_client);
164            }
165        }
166
167        Ok((signer, provider_info, client))
168    }
169}
170
171#[cfg(test)]
172mod tests {
173    use std::fs;
174
175    use super::*;
176
177    #[test]
178    fn invalid_network_returns_error() {
179        let config = r#"
180            mnemonic = "exist carry drive collect lend cereal occur much tiger just involve mean"
181            bitcoins = 10000
182
183            [esplora]
184            url = "http://localhost:3000"
185            network = "InvalidNetwork"
186        "#;
187
188        let path = std::env::temp_dir().join("smplx_test_invalid_network.toml");
189        fs::write(&path, config).unwrap();
190
191        let result = TestContext::new(path);
192        let Err(e) = result else {
193            panic!("expected BadNetworkName error")
194        };
195        assert!(
196            matches!(e, TestError::BadNetworkName(ref s) if s == "InvalidNetwork"),
197            "expected BadNetworkName, got: {e}"
198        );
199    }
200}