use super::{Bitget, BitgetOptions};
use ccxt_core::config::{ProxyConfig, RetryPolicy};
use ccxt_core::types::default_type::{DefaultSubType, DefaultType};
use ccxt_core::{ExchangeConfig, Result};
use serde_json::Value;
use std::collections::HashMap;
use std::time::Duration;
#[derive(Debug, Clone)]
pub struct BitgetBuilder {
config: ExchangeConfig,
options: BitgetOptions,
}
impl Default for BitgetBuilder {
fn default() -> Self {
Self::new()
}
}
impl BitgetBuilder {
pub fn new() -> Self {
Self {
config: ExchangeConfig {
id: "bitget".to_string(),
name: "Bitget".to_string(),
..Default::default()
},
options: BitgetOptions::default(),
}
}
pub fn api_key(mut self, key: impl Into<String>) -> Self {
self.config.api_key = Some(ccxt_core::SecretString::new(key));
self
}
pub fn secret(mut self, secret: impl Into<String>) -> Self {
self.config.secret = Some(ccxt_core::SecretString::new(secret));
self
}
pub fn passphrase(mut self, passphrase: impl Into<String>) -> Self {
self.config.password = Some(ccxt_core::SecretString::new(passphrase));
self
}
pub fn sandbox(mut self, enabled: bool) -> Self {
self.config.sandbox = enabled;
self.options.testnet = enabled;
self
}
pub fn product_type(mut self, product_type: impl Into<String>) -> Self {
self.options.product_type = product_type.into();
self
}
pub fn default_type(mut self, default_type: impl Into<DefaultType>) -> Self {
self.options.default_type = default_type.into();
self
}
pub fn default_sub_type(mut self, sub_type: DefaultSubType) -> Self {
self.options.default_sub_type = Some(sub_type);
self
}
pub fn timeout(mut self, timeout: Duration) -> Self {
self.config.timeout = timeout;
self
}
pub fn timeout_secs(mut self, seconds: u64) -> Self {
self.config.timeout = Duration::from_secs(seconds);
self
}
pub fn connect_timeout(mut self, timeout: Duration) -> Self {
self.config.connect_timeout = timeout;
self
}
pub fn connect_timeout_secs(mut self, seconds: u64) -> Self {
self.config.connect_timeout = Duration::from_secs(seconds);
self
}
pub fn retry_policy(mut self, policy: RetryPolicy) -> Self {
self.config.retry_policy = Some(policy);
self
}
pub fn recv_window(mut self, millis: u64) -> Self {
self.options.recv_window = millis;
self
}
pub fn enable_rate_limit(mut self, enabled: bool) -> Self {
self.config.enable_rate_limit = enabled;
self
}
pub fn proxy(mut self, proxy: ProxyConfig) -> Self {
self.config.proxy = Some(proxy);
self
}
pub fn proxy_url(mut self, url: impl Into<String>) -> Self {
self.config.proxy = Some(ProxyConfig::new(url));
self
}
pub fn verbose(mut self, enabled: bool) -> Self {
self.config.verbose = enabled;
self
}
pub fn option(mut self, key: impl Into<String>, value: Value) -> Self {
self.config.options.insert(key.into(), value);
self
}
pub fn options(mut self, options: HashMap<String, Value>) -> Self {
self.config.options.extend(options);
self
}
#[cfg(test)]
pub fn get_config(&self) -> &ExchangeConfig {
&self.config
}
#[cfg(test)]
pub fn get_options(&self) -> &BitgetOptions {
&self.options
}
pub fn build(self) -> Result<Bitget> {
Bitget::new_with_options(self.config, self.options)
}
}
#[cfg(test)]
mod tests {
#![allow(clippy::disallowed_methods)]
use super::*;
#[test]
fn test_builder_default() {
let builder = BitgetBuilder::new();
assert_eq!(builder.config.id, "bitget");
assert_eq!(builder.config.name, "Bitget");
assert!(!builder.config.sandbox);
assert_eq!(builder.options.product_type, "spot");
}
#[test]
fn test_builder_api_key() {
let builder = BitgetBuilder::new().api_key("test-key");
assert_eq!(
builder.config.api_key.as_ref().map(|s| s.expose_secret()),
Some("test-key")
);
}
#[test]
fn test_builder_secret() {
let builder = BitgetBuilder::new().secret("test-secret");
assert_eq!(
builder.config.secret.as_ref().map(|s| s.expose_secret()),
Some("test-secret")
);
}
#[test]
fn test_builder_passphrase() {
let builder = BitgetBuilder::new().passphrase("test-passphrase");
assert_eq!(
builder.config.password.as_ref().map(|s| s.expose_secret()),
Some("test-passphrase")
);
}
#[test]
fn test_builder_sandbox() {
let builder = BitgetBuilder::new().sandbox(true);
assert!(builder.config.sandbox);
assert!(builder.options.testnet);
}
#[test]
fn test_builder_product_type() {
let builder = BitgetBuilder::new().product_type("umcbl");
assert_eq!(builder.options.product_type, "umcbl");
}
#[test]
fn test_builder_default_type() {
let builder = BitgetBuilder::new().default_type(DefaultType::Swap);
assert_eq!(builder.options.default_type, DefaultType::Swap);
}
#[test]
fn test_builder_default_type_from_string() {
let builder = BitgetBuilder::new().default_type("futures");
assert_eq!(builder.options.default_type, DefaultType::Futures);
}
#[test]
fn test_builder_default_sub_type() {
let builder = BitgetBuilder::new().default_sub_type(DefaultSubType::Inverse);
assert_eq!(
builder.options.default_sub_type,
Some(DefaultSubType::Inverse)
);
}
#[test]
fn test_builder_default_type_and_sub_type() {
let builder = BitgetBuilder::new()
.default_type(DefaultType::Swap)
.default_sub_type(DefaultSubType::Linear);
assert_eq!(builder.options.default_type, DefaultType::Swap);
assert_eq!(
builder.options.default_sub_type,
Some(DefaultSubType::Linear)
);
}
#[test]
fn test_builder_timeout() {
let builder = BitgetBuilder::new().timeout(Duration::from_secs(60));
assert_eq!(builder.config.timeout, Duration::from_secs(60));
}
#[test]
fn test_builder_connect_timeout() {
let builder = BitgetBuilder::new().connect_timeout(Duration::from_secs(15));
assert_eq!(builder.config.connect_timeout, Duration::from_secs(15));
}
#[test]
fn test_builder_connect_timeout_secs() {
let builder = BitgetBuilder::new().connect_timeout_secs(20);
assert_eq!(builder.config.connect_timeout, Duration::from_secs(20));
}
#[test]
fn test_builder_recv_window() {
let builder = BitgetBuilder::new().recv_window(10000);
assert_eq!(builder.options.recv_window, 10000);
}
#[test]
fn test_builder_chaining() {
let builder = BitgetBuilder::new()
.api_key("key")
.secret("secret")
.passphrase("pass")
.sandbox(true)
.timeout(Duration::from_secs(30))
.recv_window(5000)
.product_type("spot")
.default_type(DefaultType::Swap)
.default_sub_type(DefaultSubType::Linear);
assert_eq!(
builder.config.api_key.as_ref().map(|s| s.expose_secret()),
Some("key")
);
assert_eq!(
builder.config.secret.as_ref().map(|s| s.expose_secret()),
Some("secret")
);
assert_eq!(
builder.config.password.as_ref().map(|s| s.expose_secret()),
Some("pass")
);
assert!(builder.config.sandbox);
assert_eq!(builder.config.timeout, Duration::from_secs(30));
assert_eq!(builder.options.recv_window, 5000);
assert_eq!(builder.options.product_type, "spot");
assert_eq!(builder.options.default_type, DefaultType::Swap);
assert_eq!(
builder.options.default_sub_type,
Some(DefaultSubType::Linear)
);
}
#[test]
fn test_builder_build() {
let result = BitgetBuilder::new().build();
assert!(result.is_ok());
let bitget = result.unwrap();
assert_eq!(bitget.id(), "bitget");
assert_eq!(bitget.name(), "Bitget");
}
#[test]
fn test_builder_build_with_credentials() {
let result = BitgetBuilder::new()
.api_key("test-key")
.secret("test-secret")
.passphrase("test-passphrase")
.build();
assert!(result.is_ok());
}
}