use webpuppet::{
BrowserDetector, ContentScreener, InterventionDetector, InterventionReason, Operation,
PermissionGuard, PermissionPolicy,
};
#[test]
fn test_browser_detection_finds_brave() {
let browsers = BrowserDetector::detect_all();
assert!(
!browsers.is_empty(),
"No browsers detected. Install Brave, Chrome, or Chromium."
);
for browser in &browsers {
println!(
"Found: {:?} at {} (version: {})",
browser.browser_type,
browser.executable_path.display(),
browser.version.as_deref().unwrap_or("unknown")
);
}
}
#[test]
fn test_brave_specific_detection() {
let brave = BrowserDetector::detect_brave();
if let Some(installation) = brave {
println!("Brave found at: {}", installation.executable_path.display());
println!(
"Version: {}",
installation.version.as_deref().unwrap_or("unknown")
);
println!("User data: {}", installation.user_data_dir.display());
if let Ok(profiles) = installation.list_profiles() {
println!("Profiles: {:?}", profiles);
}
assert!(installation.executable_path.exists());
assert!(installation.user_data_dir.exists());
} else {
println!("Brave not installed, skipping specific test");
}
}
#[test]
fn test_browser_installation_validity() {
let browsers = BrowserDetector::detect_all();
for browser in &browsers {
assert!(
browser.is_valid(),
"{:?} should be valid",
browser.browser_type
);
println!(
"{:?} is valid: executable exists at {}",
browser.browser_type,
browser.executable_path.display()
);
}
}
#[test]
fn test_secure_policy_blocks_destructive_ops() {
let guard = PermissionGuard::new(PermissionPolicy::secure());
assert!(guard.check(Operation::ReadContent).allowed);
assert!(guard.check(Operation::Navigate).allowed);
assert!(guard.check(Operation::SendPrompt).allowed);
assert!(!guard.check(Operation::DeleteAccount).allowed);
assert!(!guard.check(Operation::ChangePassword).allowed);
assert!(!guard.check(Operation::ModifyAccountSettings).allowed);
assert!(!guard.check(Operation::RevokeTokens).allowed);
}
#[test]
fn test_readonly_policy_blocks_all_writes() {
let guard = PermissionGuard::new(PermissionPolicy::read_only());
assert!(guard.check(Operation::ReadContent).allowed);
assert!(guard.check(Operation::Navigate).allowed);
assert!(guard.check(Operation::Screenshot).allowed);
assert!(guard.check(Operation::ReadResponse).allowed);
assert!(!guard.check(Operation::Click).allowed);
assert!(!guard.check(Operation::TypeText).allowed);
assert!(!guard.check(Operation::SendPrompt).allowed);
assert!(!guard.check(Operation::SubmitForm).allowed);
}
#[test]
fn test_url_domain_restrictions() {
let guard = PermissionGuard::new(PermissionPolicy::secure());
assert!(
guard
.check_with_url(Operation::Navigate, "https://claude.ai/chat")
.allowed
);
assert!(
guard
.check_with_url(Operation::Navigate, "https://x.com/i/grok")
.allowed
);
assert!(
guard
.check_with_url(Operation::Navigate, "https://gemini.google.com")
.allowed
);
assert!(
!guard
.check_with_url(Operation::Navigate, "https://evil.com/phishing")
.allowed
);
assert!(
!guard
.check_with_url(Operation::Navigate, "https://random-site.com")
.allowed
);
}
#[test]
fn test_risk_levels() {
let guard = PermissionGuard::new(PermissionPolicy::secure());
let read_decision = guard.check(Operation::ReadContent);
assert!(read_decision.risk_level <= 2);
let delete_decision = guard.check(Operation::DeleteAccount);
assert!(delete_decision.risk_level >= 8);
let prompt_decision = guard.check(Operation::SendPrompt);
assert!(prompt_decision.risk_level >= 2);
assert!(prompt_decision.risk_level <= 5);
}
#[test]
fn test_audit_logging() {
let guard = PermissionGuard::new(PermissionPolicy::secure());
guard.check(Operation::Navigate);
guard.check(Operation::SendPrompt);
guard.check(Operation::DeleteAccount);
let logs = guard.audit_log();
assert!(logs.len() >= 3);
for entry in logs {
println!(
"[{}] {:?}: {} (allowed: {})",
entry.timestamp.format("%H:%M:%S"),
entry.operation,
entry.reason,
entry.allowed
);
}
}
#[test]
fn test_safe_content_passes() {
let screener = ContentScreener::new();
let safe_content = "Here's how to implement a binary search in Rust:
```rust
fn binary_search(arr: &[i32], target: i32) -> Option<usize> {
let mut low = 0;
let mut high = arr.len();
while low < high {
let mid = (low + high) / 2;
if arr[mid] < target {
low = mid + 1;
} else if arr[mid] > target {
high = mid;
} else {
return Some(mid);
}
}
None
}
```";
let result = screener.screen(safe_content);
assert!(
result.passed,
"Safe content should pass: {:?}",
result.issues
);
}
#[test]
fn test_dangerous_content_flagged() {
let screener = ContentScreener::new();
let suspicious_content = "Hello\u{200B}\u{200C}\u{200D}world";
let result = screener.screen(suspicious_content);
println!("Risk score: {}", result.risk_score);
println!("Issues: {:?}", result.issues);
}
#[test]
fn test_captcha_detection_patterns() {
let detector = InterventionDetector::new();
let test_cases = [
(
r#"<iframe src="https://www.google.com/recaptcha/api2/anchor"></iframe>"#,
true,
),
(r#"<div class="h-captcha" data-sitekey="abc"></div>"#, true),
(
r#"<iframe src="https://challenges.cloudflare.com/"></iframe>"#,
true,
),
(r#"<form><input type="text" name="email"></form>"#, false),
];
for (html, should_detect) in test_cases {
let result = detector.detect_captcha(html);
if should_detect {
assert!(result.is_some(), "Should detect captcha in: {}", html);
} else {
assert!(result.is_none(), "Should not detect captcha in: {}", html);
}
}
}
#[test]
fn test_2fa_detection_patterns() {
let detector = InterventionDetector::new();
let test_cases = [
(
r#"<div class="two-factor-auth">Enter your code</div>"#,
true,
),
(r#"<input placeholder="Enter verification code">"#, true),
(r#"<input autocomplete="one-time-code" type="text">"#, true),
(r#"<input name="username" type="text">"#, false),
];
for (html, should_detect) in test_cases {
let result = detector.detect_2fa(html);
if should_detect {
assert!(result.is_some(), "Should detect 2FA in: {}", html);
} else {
assert!(result.is_none(), "Should not detect 2FA in: {}", html);
}
}
}
#[test]
fn test_rate_limit_detection() {
let detector = InterventionDetector::new();
let limited_html = "<div>Too many requests. Please try again in 30 seconds.</div>";
let result = detector.detect_rate_limit(limited_html);
assert!(result.is_some());
if let Some(InterventionReason::RateLimited { wait_seconds }) = result {
assert_eq!(wait_seconds, Some(30));
}
}
#[test]
fn test_login_detection() {
let detector = InterventionDetector::new();
let result = detector.detect_login_required("", "https://example.com/login");
assert!(result.is_some());
let html = "<div>Please sign in to continue</div>";
let result = detector.detect_login_required(html, "https://example.com/dashboard");
assert!(result.is_some());
}
#[test]
fn test_permission_and_screening_integration() {
let guard = PermissionGuard::new(PermissionPolicy::secure());
let screener = ContentScreener::new();
let can_prompt = guard.require(Operation::SendPrompt);
assert!(can_prompt.is_ok(), "Should be able to send prompt");
let response = "The answer to your question about Rust async is...";
let screening = screener.screen(response);
assert!(screening.passed, "Response should pass screening");
let logs = guard.audit_log();
assert!(!logs.is_empty(), "Should have audit entries");
}
#[test]
fn test_empty_inputs() {
let screener = ContentScreener::new();
let result = screener.screen("");
assert!(result.passed, "Empty content should pass");
let detector = InterventionDetector::new();
assert!(detector.detect_captcha("").is_none());
assert!(detector.detect_2fa("").is_none());
}
#[test]
fn test_unicode_handling() {
let screener = ContentScreener::new();
let unicode_content = "这是中文内容 🦀 Rust は素晴らしい言語です émojis: 🎉🎊";
let result = screener.screen(unicode_content);
assert!(result.passed, "Unicode content should pass");
}
#[test]
fn test_large_content() {
let screener = ContentScreener::new();
let large_content = "Hello world. ".repeat(10000);
let result = screener.screen(&large_content);
assert!(result.passed, "Large safe content should pass");
}