use std::time::Duration;
use ezcapsolver::{ClientConfig, ClientConfigBuilder, PollingConfig};
#[test]
fn an_empty_builder_matches_default_configuration() {
let builder: ClientConfigBuilder = ClientConfig::builder();
assert_eq!(builder.build(), ClientConfig::default());
}
#[test]
fn builder_settings_match_existing_configuration_methods() {
let user_agent = "my-app/1.0".to_owned();
let config = ClientConfig::builder()
.client_key("test-client-key")
.timeout(Duration::from_secs(60))
.sync_timeout(Duration::from_secs(240))
.polling(PollingConfig::new(Duration::from_secs(5), 24))
.app_id(42)
.proxy("http://127.0.0.1:8080".to_owned())
.user_agent(&user_agent)
.build();
let expected = ClientConfig::default()
.with_client_key("test-client-key")
.with_timeout(Duration::from_secs(60))
.with_sync_timeout(Duration::from_secs(240))
.with_polling(PollingConfig::new(Duration::from_secs(5), 24))
.with_app_id(42)
.with_proxy("http://127.0.0.1:8080")
.with_user_agent(user_agent);
assert_eq!(config, expected);
}
#[test]
fn optional_setters_preserve_defaults_and_explicit_zero() {
let client_key: Option<String> = None;
let proxy: Option<String> = None;
let user_agent: Option<String> = None;
let config = ClientConfig::builder()
.maybe_client_key(client_key)
.maybe_proxy(proxy)
.maybe_user_agent(user_agent)
.maybe_timeout(None)
.maybe_sync_timeout(None)
.maybe_polling(None)
.maybe_app_id(Some(0))
.build();
assert_eq!(config, ClientConfig::default().with_app_id(0));
let config = ClientConfig::builder()
.maybe_client_key(Some("test-client-key"))
.maybe_proxy(Some("http://127.0.0.1:8080"))
.maybe_user_agent(Some("my-app/1.0"))
.maybe_app_id(None)
.build();
assert_eq!(
config,
ClientConfig::default()
.with_client_key("test-client-key")
.with_proxy("http://127.0.0.1:8080")
.with_user_agent("my-app/1.0")
);
}
#[test]
fn builder_configuration_debug_output_redacts_credentials() {
let config = ClientConfig::builder()
.client_key("secret-client-key")
.proxy("http://user:secret-password@127.0.0.1:8080")
.build();
let output = format!("{config:?}");
assert!(!output.contains("secret-client-key"));
assert!(!output.contains("secret-password"));
assert!(output.contains("[REDACTED]"));
}
#[cfg(any(feature = "async", feature = "blocking"))]
#[test]
fn clients_accept_builder_configuration() -> ezcapsolver::Result<()> {
let config = ClientConfig::builder()
.client_key("test-client-key")
.timeout(Duration::from_secs(60))
.app_id(42)
.build();
#[cfg(feature = "async")]
assert_eq!(
ezcapsolver::AsyncEzCapSolverClient::with_config(config.clone())?.config(),
&config
);
#[cfg(feature = "blocking")]
assert_eq!(
ezcapsolver::EzCapSolverClient::with_config(config.clone())?.config(),
&config
);
Ok(())
}
#[cfg(any(feature = "async", feature = "blocking"))]
#[test]
fn invalid_builder_settings_are_rejected_during_client_creation() {
let configurations = [
ClientConfig::builder().timeout(Duration::ZERO).build(),
ClientConfig::builder().sync_timeout(Duration::ZERO).build(),
ClientConfig::builder()
.polling(PollingConfig::new(Duration::ZERO, 1))
.build(),
ClientConfig::builder()
.polling(PollingConfig::new(Duration::from_secs(1), 0))
.build(),
];
for config in configurations {
let config = config.with_client_key("test-client-key");
#[cfg(feature = "async")]
assert!(matches!(
ezcapsolver::AsyncEzCapSolverClient::with_config(config.clone()),
Err(ezcapsolver::Error::Message(message))
if message.starts_with("invalid client configuration")
));
#[cfg(feature = "blocking")]
assert!(matches!(
ezcapsolver::EzCapSolverClient::with_config(config.clone()),
Err(ezcapsolver::Error::Message(message))
if message.starts_with("invalid client configuration")
));
}
}
#[test]
fn base_urls_are_configurable_and_default_to_the_service() {
let defaults = ClientConfig::default();
assert_eq!(defaults.async_base_url, ezcapsolver::DEFAULT_ASYNC_BASE_URL);
assert_eq!(defaults.sync_base_url, ezcapsolver::DEFAULT_SYNC_BASE_URL);
let overridden =
ClientConfig::default().with_base_urls("http://127.0.0.1:1", "http://127.0.0.1:2");
assert_eq!(overridden.async_base_url, "http://127.0.0.1:1");
assert_eq!(overridden.sync_base_url, "http://127.0.0.1:2");
let one_sided = ClientConfig::default().with_base_urls("http://127.0.0.1:1", "");
assert_eq!(one_sided.async_base_url, "http://127.0.0.1:1");
assert_eq!(one_sided.sync_base_url, ezcapsolver::DEFAULT_SYNC_BASE_URL);
let built = ClientConfig::builder()
.async_base_url("http://gateway.internal")
.build();
assert_eq!(built.async_base_url, "http://gateway.internal");
}
#[test]
fn debug_output_shows_endpoints_without_leaking_credentials() {
let rendered = format!(
"{:?}",
ClientConfig::default()
.with_client_key("secret-client-key")
.with_base_urls("http://gateway.internal", "http://sync.internal")
);
assert!(rendered.contains("http://gateway.internal"));
assert!(rendered.contains("http://sync.internal"));
assert!(!rendered.contains("secret-client-key"));
}