use secrecy::{ExposeSecret, SecretString};
use crate::error::{MktError, Result};
pub fn resolve_token(
provider: &str,
env_var_name: &str,
config_value: Option<&str>,
) -> Result<SecretString> {
if let Ok(token) = std::env::var(env_var_name) {
if !token.is_empty() {
return Ok(SecretString::from(token));
}
}
if let Some(token) = config_value {
if !token.is_empty() {
return Ok(SecretString::from(token.to_owned()));
}
}
Err(MktError::auth_error(
provider,
&format!("No access token found. Set {env_var_name} or configure it in your profile."),
))
}
pub fn validate_token(token: &SecretString) -> bool {
!token.expose_secret().is_empty()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[allow(clippy::expect_used)]
fn resolve_from_config_value() {
let key = "MKT_TEST_TOKEN_DEFINITELY_NOT_SET_98765";
let result = resolve_token("test", key, Some("config-token"));
let token = result.expect("should resolve");
assert_eq!(token.expose_secret(), "config-token");
}
#[test]
#[allow(clippy::panic)]
fn missing_token_returns_auth_error() {
let key = "MKT_TEST_TOKEN_DEFINITELY_NOT_SET_11111";
let result = resolve_token("test", key, None);
let Err(e) = result else {
panic!("expected auth error");
};
assert!(e.to_string().contains("No access token"));
}
#[test]
fn empty_config_value_returns_error() {
let key = "MKT_TEST_TOKEN_DEFINITELY_NOT_SET_22222";
let result = resolve_token("test", key, Some(""));
assert!(result.is_err());
}
#[test]
fn env_var_resolution_with_existing_var() {
let result = resolve_token("test", "HOME", None);
assert!(result.is_ok());
}
#[test]
fn validate_non_empty_token() {
let token = SecretString::from("valid".to_owned());
assert!(validate_token(&token));
}
#[test]
fn validate_empty_token() {
let token = SecretString::from(String::new());
assert!(!validate_token(&token));
}
}