#![cfg(feature = "test-utils")]
use xchecker::logging::{
Logger, init_tracing, log_phase_complete, log_phase_error, log_phase_start, phase_span,
};
use xchecker::test_support;
#[test]
fn test_tracing_initialization() {
let result = init_tracing(false);
assert!(result.is_ok() || result.is_err()); }
#[test]
fn test_verbose_tracing_initialization() {
let result = init_tracing(true);
assert!(result.is_ok() || result.is_err()); }
#[test]
fn test_logger_with_structured_context() {
let mut logger = Logger::new(true);
logger.set_spec_id("integration-test-spec".to_string());
logger.set_phase("requirements".to_string());
logger.set_runner_mode("native".to_string());
assert_eq!(logger.spec_id(), Some("integration-test-spec"));
assert_eq!(logger.phase(), Some("requirements"));
assert_eq!(logger.runner_mode(), Some("native"));
logger.info("Starting phase execution");
logger.warn("Warning during execution");
logger.error("Error occurred");
}
#[test]
fn test_phase_span_usage() {
let span = phase_span("test-spec", "design", "wsl");
let _guard = span.enter();
log_phase_start("test-spec", "design", "wsl");
log_phase_complete("test-spec", "design", 1500);
}
#[test]
fn test_phase_logging_functions() {
log_phase_start("spec-123", "tasks", "auto");
log_phase_complete("spec-123", "tasks", 2000);
log_phase_error("spec-123", "tasks", "timeout", 5000);
}
#[test]
fn test_logger_without_context() {
let logger = Logger::new(false);
logger.info("Message without context");
logger.warn("Warning without context");
logger.error("Error without context");
}
#[test]
fn test_verbose_mode_with_context() {
let mut logger = Logger::new(true);
logger.set_spec_id("verbose-test".to_string());
logger.set_phase("review".to_string());
logger.set_runner_mode("native".to_string());
logger.verbose("Verbose message with context");
logger.info("Info message with context");
}
#[test]
fn test_compact_mode() {
let logger = Logger::new(false);
assert!(!logger.is_verbose());
logger.info("Compact info message");
}
#[test]
fn test_duration_tracking() {
let mut logger = Logger::new(true);
logger.set_spec_id("duration-test".to_string());
logger.set_phase("fixup".to_string());
logger.set_runner_mode("wsl".to_string());
std::thread::sleep(std::time::Duration::from_millis(10));
let elapsed = logger.total_elapsed();
assert!(elapsed.as_millis() >= 10);
logger.info("Message with duration");
}
#[test]
fn test_logging_redacts_github_tokens() {
let mut logger = Logger::new(true);
logger.set_spec_id("redaction-test".to_string());
logger.set_phase("requirements".to_string());
logger.set_runner_mode("native".to_string());
let token = test_support::github_pat();
logger.verbose(&format!("Found token: {}", token));
logger.info(&format!("Using token: {}", token));
logger.warn(&format!("Exposed token: {}", token));
logger.error(&format!("Error with token: {}", token));
}
#[test]
fn test_logging_redacts_aws_keys() {
let logger = Logger::new(false);
let aws_key = test_support::aws_access_key_id();
let aws_secret = test_support::aws_secret_access_key();
logger.info(&format!("AWS access key: {}", aws_key));
logger.error(&format!("Failed with {}", aws_secret));
}
#[test]
fn test_logging_redacts_bearer_tokens() {
let logger = Logger::new(false);
let bearer_token = test_support::bearer_token();
logger.info(&format!("Authorization: {}", bearer_token));
logger.error(&format!("Auth failed with {}", bearer_token));
}
#[test]
fn test_logging_excludes_environment_variables() {
let logger = Logger::new(true);
logger.info("Config: API_KEY=secret123");
logger.warn("Found: DATABASE_PASSWORD=mypassword");
logger.error("Error: SECRET_TOKEN=abc123");
}
#[test]
fn test_phase_error_logging_redacts_secrets() {
let github_token = test_support::github_pat();
let aws_key = test_support::aws_access_key_id();
log_phase_error(
"test-spec",
"requirements",
&format!("Failed with token {}", github_token),
1000,
);
log_phase_error(
"test-spec",
"design",
&format!("AWS key {} exposed", aws_key),
2000,
);
}
#[test]
fn test_error_context_redaction() {
let mut logger = Logger::new(false);
logger.set_spec_id("error-context-test".to_string());
logger.set_phase("tasks".to_string());
logger.set_runner_mode("wsl".to_string());
logger.error("Authentication failed with API_KEY=secret123");
logger.error(&format!(
"Connection error: {}",
test_support::bearer_token()
));
}
#[test]
fn test_verbose_logging_with_secrets() {
let logger = Logger::new(true);
let token = test_support::github_pat();
logger.verbose_fmt(format_args!("Processing with token: {}", token));
}
#[test]
fn test_no_secrets_in_normal_logs() {
let logger = Logger::new(true);
logger.info("Processing file test.txt");
logger.verbose("Completed in 1.5 seconds");
logger.warn("File size exceeds recommended limit");
logger.error("File not found: /path/to/file");
}
#[test]
fn test_multiple_log_levels_with_redaction() {
let mut logger = Logger::new(true);
logger.set_spec_id("multi-level-test".to_string());
logger.set_phase("review".to_string());
logger.set_runner_mode("auto".to_string());
let token = test_support::github_pat();
let secret_message = format!("Token: {}", token);
logger.verbose(&secret_message);
logger.info(&secret_message);
logger.warn(&secret_message);
logger.error(&secret_message);
}
#[test]
fn test_slack_token_redaction() {
let logger = Logger::new(false);
let slack_bot = test_support::slack_bot_token();
let slack_user = test_support::slack_user_token();
logger.info(&format!("Slack webhook: {}", slack_bot));
logger.error(&format!("Slack error with {}", slack_user));
}
#[test]
fn test_redaction_preserves_safe_content() {
let logger = Logger::new(true);
let safe_messages = vec![
"Processing completed successfully",
"File count: 42",
"Duration: 1.5 seconds",
"Status: OK",
"Path: /home/user/project",
];
for message in safe_messages {
logger.info(message);
logger.verbose(message);
}
}