use bao_stealth::{
AudioProfile, BehaviorSimulator, CanvasNoise, Http2Fingerprint, NavigatorProfile,
ScreenProfile, WebGLProfile,
};
#[test]
fn test_navigator_firefox_user_agent() {
let nav = NavigatorProfile::firefox();
assert!(nav.user_agent.contains("Firefox"));
assert!(nav.user_agent.contains("rv:128.0"));
}
#[test]
fn test_navigator_firefox_platform() {
let nav = NavigatorProfile::firefox();
assert_eq!(nav.platform, "Linux x86_64");
}
#[test]
fn test_navigator_firefox_language() {
let nav = NavigatorProfile::firefox();
assert_eq!(nav.language, "en-US");
}
#[test]
fn test_navigator_firefox_hardware_concurrency() {
let nav = NavigatorProfile::firefox();
assert_eq!(nav.hardware_concurrency, 8);
}
#[test]
fn test_navigator_firefox_max_touch_points() {
let nav = NavigatorProfile::firefox();
assert_eq!(nav.max_touch_points, 0);
}
#[test]
fn test_navigator_firefox_vendor_empty() {
let nav = NavigatorProfile::firefox();
assert!(nav.vendor.is_empty());
}
#[test]
fn test_navigator_firefox_oscpu_some() {
let nav = NavigatorProfile::firefox();
assert!(nav.oscpu.is_some());
assert!(nav.oscpu.as_ref().unwrap().contains("Linux"));
}
#[test]
fn test_navigator_firefox_build_id_some() {
let nav = NavigatorProfile::firefox();
assert!(nav.build_id.is_some());
}
#[test]
fn test_navigator_firefox_product_sub() {
let nav = NavigatorProfile::firefox();
assert_eq!(nav.product_sub, "20100101");
}
#[test]
fn test_navigator_chrome_user_agent() {
let nav = NavigatorProfile::chrome();
assert!(nav.user_agent.contains("Chrome/128"));
}
#[test]
fn test_navigator_chrome_vendor_google() {
let nav = NavigatorProfile::chrome();
assert_eq!(nav.vendor, "Google Inc.");
}
#[test]
fn test_navigator_chrome_oscpu_none() {
let nav = NavigatorProfile::chrome();
assert!(nav.oscpu.is_none());
}
#[test]
fn test_navigator_chrome_build_id_none() {
let nav = NavigatorProfile::chrome();
assert!(nav.build_id.is_none());
}
#[test]
fn test_navigator_chrome_product_sub() {
let nav = NavigatorProfile::chrome();
assert_eq!(nav.product_sub, "20030107");
}
#[test]
fn test_navigator_firefox_chrome_differ() {
let ff = NavigatorProfile::firefox();
let ch = NavigatorProfile::chrome();
assert_ne!(ff.user_agent, ch.user_agent);
assert_ne!(ff.vendor, ch.vendor);
assert_ne!(ff.product_sub, ch.product_sub);
}
#[test]
fn test_navigator_clone() {
let nav = NavigatorProfile::firefox();
let cloned = nav.clone();
assert_eq!(nav.user_agent, cloned.user_agent);
assert_eq!(nav.platform, cloned.platform);
assert_eq!(nav.oscpu, cloned.oscpu);
}
#[test]
fn test_navigator_debug() {
let nav = NavigatorProfile::firefox();
let debug = format!("{:?}", nav);
assert!(debug.contains("Firefox") || debug.contains("NavigatorProfile"));
}
#[test]
fn test_screen_default_dimensions() {
let scr = ScreenProfile::default();
assert_eq!(scr.width, 1920);
assert_eq!(scr.height, 1080);
}
#[test]
fn test_screen_default_avail() {
let scr = ScreenProfile::default();
assert_eq!(scr.avail_width, 1920);
assert_eq!(scr.avail_height, 1040);
}
#[test]
fn test_screen_default_depth() {
let scr = ScreenProfile::default();
assert_eq!(scr.color_depth, 24);
assert_eq!(scr.pixel_depth, 24);
}
#[test]
fn test_screen_default_dpr() {
let scr = ScreenProfile::default();
assert!((scr.device_pixel_ratio - 1.0).abs() < f64::EPSILON);
}
#[test]
fn test_screen_custom() {
let scr = ScreenProfile::new(2560, 1440, 2.0);
assert_eq!(scr.width, 2560);
assert_eq!(scr.height, 1440);
assert_eq!(scr.avail_width, 2560);
assert_eq!(scr.avail_height, 1400); assert!((scr.device_pixel_ratio - 2.0).abs() < f64::EPSILON);
}
#[test]
fn test_screen_small_dims() {
let scr = ScreenProfile::new(800, 600, 1.0);
assert_eq!(scr.avail_height, 560);
}
#[test]
fn test_screen_clone() {
let scr = ScreenProfile::default();
let cloned = scr.clone();
assert_eq!(cloned.width, scr.width);
assert_eq!(cloned.device_pixel_ratio, scr.device_pixel_ratio);
}
#[test]
fn test_screen_debug() {
let scr = ScreenProfile::default();
let debug = format!("{:?}", scr);
assert!(debug.contains("1920") || debug.contains("ScreenProfile"));
}
#[test]
fn test_canvas_seed() {
let cn = CanvasNoise::new(42);
assert_eq!(cn.seed(), 42);
}
#[test]
fn test_canvas_noise_amplitude() {
let cn = CanvasNoise::new(42);
assert!((cn.noise_amplitude() - 0.001).abs() < f64::EPSILON);
}
#[test]
fn test_canvas_apply_to_pixel_deterministic() {
let cn = CanvasNoise::new(42);
let p1 = cn.apply_to_pixel(128, 128, 128, 255, 100, 200);
let p2 = cn.apply_to_pixel(128, 128, 128, 255, 100, 200);
assert_eq!(p1, p2);
}
#[test]
fn test_canvas_apply_different_coords() {
let cn = CanvasNoise::new(42);
let p1 = cn.apply_to_pixel(128, 128, 128, 255, 0, 0);
let p2 = cn.apply_to_pixel(128, 128, 128, 255, 999, 999);
let _ = (p1, p2);
}
#[test]
fn test_canvas_apply_preserves_alpha() {
let cn = CanvasNoise::new(42);
let p = cn.apply_to_pixel(128, 128, 128, 200, 10, 20);
assert_eq!(p.3, 200);
}
#[test]
fn test_canvas_apply_clamps_zero() {
let cn = CanvasNoise::new(42);
let p = cn.apply_to_pixel(0, 0, 0, 255, 0, 0);
assert_eq!(p.3, 255);
}
#[test]
fn test_canvas_apply_clamps_max() {
let cn = CanvasNoise::new(42);
let p = cn.apply_to_pixel(255, 255, 255, 255, 0, 0);
let _ = p;
}
#[test]
fn test_canvas_different_seeds() {
let cn1 = CanvasNoise::new(42);
let cn2 = CanvasNoise::new(137);
assert_ne!(cn1.seed(), cn2.seed());
assert!((cn1.noise_amplitude() - cn2.noise_amplitude()).abs() < f64::EPSILON);
}
#[test]
fn test_canvas_clone() {
let cn = CanvasNoise::new(42);
let cloned = cn.clone();
assert_eq!(cn.seed(), cloned.seed());
}
#[test]
fn test_canvas_debug() {
let cn = CanvasNoise::new(42);
let debug = format!("{:?}", cn);
assert!(debug.contains("CanvasNoise") || debug.contains("seed"));
}
#[test]
#[should_panic(expected = "canvas_seed must be > 0")]
fn test_canvas_zero_seed_panics() {
let _ = CanvasNoise::new(0);
}
#[test]
fn test_webgl_firefox_vendor() {
let gl = WebGLProfile::firefox();
assert_eq!(gl.vendor, "Mozilla");
}
#[test]
fn test_webgl_firefox_renderer() {
let gl = WebGLProfile::firefox();
assert!(gl.renderer.contains("WebGL"));
}
#[test]
fn test_webgl_firefox_extensions_nonempty() {
let gl = WebGLProfile::firefox();
assert!(!gl.extensions.is_empty());
}
#[test]
fn test_webgl_firefox_max_texture_size() {
let gl = WebGLProfile::firefox();
assert_eq!(gl.max_texture_size, 16384);
}
#[test]
fn test_webgl_firefox_max_viewport_dims() {
let gl = WebGLProfile::firefox();
assert_eq!(gl.max_viewport_dims, [16384, 16384]);
}
#[test]
fn test_webgl_chrome_vendor() {
let gl = WebGLProfile::chrome();
assert!(gl.vendor.contains("Google"));
}
#[test]
fn test_webgl_chrome_renderer() {
let gl = WebGLProfile::chrome();
assert!(gl.renderer.contains("ANGLE"));
}
#[test]
fn test_webgl_firefox_more_extensions_than_chrome() {
let ff = WebGLProfile::firefox();
let ch = WebGLProfile::chrome();
assert!(ff.extensions.len() > ch.extensions.len());
}
#[test]
fn test_webgl_firefox_chrome_differ() {
let ff = WebGLProfile::firefox();
let ch = WebGLProfile::chrome();
assert_ne!(ff.vendor, ch.vendor);
assert_ne!(ff.renderer, ch.renderer);
}
#[test]
fn test_webgl_same_max_sizes() {
let ff = WebGLProfile::firefox();
let ch = WebGLProfile::chrome();
assert_eq!(ff.max_texture_size, ch.max_texture_size);
assert_eq!(ff.max_renderbuffer_size, ch.max_renderbuffer_size);
}
#[test]
fn test_webgl_clone() {
let gl = WebGLProfile::firefox();
let cloned = gl.clone();
assert_eq!(gl.vendor, cloned.vendor);
assert_eq!(gl.extensions.len(), cloned.extensions.len());
}
#[test]
fn test_webgl_debug() {
let gl = WebGLProfile::firefox();
let debug = format!("{:?}", gl);
assert!(debug.contains("Mozilla") || debug.contains("WebGLProfile"));
}
#[test]
fn test_audio_seed() {
let audio = AudioProfile::new(42);
assert_eq!(audio.seed(), 42);
}
#[test]
fn test_audio_noise_amplitude() {
let audio = AudioProfile::new(42);
assert!(audio.noise_amplitude() > 0.0);
assert!(audio.noise_amplitude() < 1e-5);
}
#[test]
fn test_audio_sample_rate() {
let audio = AudioProfile::new(42);
assert_eq!(audio.sample_rate(), 44100);
}
#[test]
fn test_audio_apply_noise_deterministic() {
let audio = AudioProfile::new(42);
let s1 = audio.apply_noise(1.0, 100);
let s2 = audio.apply_noise(1.0, 100);
assert!((s1 - s2).abs() < f64::EPSILON);
}
#[test]
fn test_audio_apply_noise_different_indices() {
let audio = AudioProfile::new(42);
let s1 = audio.apply_noise(1.0, 0);
let s2 = audio.apply_noise(1.0, 1);
assert_ne!(s1, s2);
}
#[test]
fn test_audio_apply_noise_small() {
let audio = AudioProfile::new(42);
let original = 0.5;
let noisy = audio.apply_noise(original, 50);
assert!((noisy - original).abs() < 1e-3);
}
#[test]
fn test_audio_different_seeds() {
let a1 = AudioProfile::new(42);
let a2 = AudioProfile::new(137);
let s1 = a1.apply_noise(1.0, 10);
let s2 = a2.apply_noise(1.0, 10);
assert_ne!(s1, s2);
}
#[test]
fn test_audio_clone() {
let audio = AudioProfile::new(42);
let cloned = audio.clone();
assert_eq!(audio.seed(), cloned.seed());
assert_eq!(audio.sample_rate(), cloned.sample_rate());
}
#[test]
fn test_behavior_seed() {
let b = BehaviorSimulator::new(42);
assert_eq!(b.seed(), 42);
}
#[test]
fn test_behavior_mouse_path_count() {
let b = BehaviorSimulator::new(42);
let path = b.generate_mouse_path(0.0, 0.0, 100.0, 100.0, 20);
assert_eq!(path.len(), 21);
}
#[test]
fn test_behavior_mouse_path_start_end() {
let b = BehaviorSimulator::new(42);
let path = b.generate_mouse_path(10.0, 20.0, 110.0, 120.0, 10);
let first = path.first().unwrap();
let last = path.last().unwrap();
assert!((first.0 - 10.0).abs() < 1.0);
assert!((first.1 - 20.0).abs() < 1.0);
assert!((last.0 - 110.0).abs() < 1.0);
assert!((last.1 - 120.0).abs() < 1.0);
}
#[test]
fn test_behavior_mouse_path_deterministic() {
let b = BehaviorSimulator::new(42);
let p1 = b.generate_mouse_path(0.0, 0.0, 100.0, 100.0, 10);
let p2 = b.generate_mouse_path(0.0, 0.0, 100.0, 100.0, 10);
assert_eq!(p1, p2);
}
#[test]
fn test_behavior_mouse_path_different_seeds() {
let b1 = BehaviorSimulator::new(42);
let b2 = BehaviorSimulator::new(137);
let p1 = b1.generate_mouse_path(0.0, 0.0, 100.0, 100.0, 10);
let p2 = b2.generate_mouse_path(0.0, 0.0, 100.0, 100.0, 10);
assert_ne!(p1, p2);
}
#[test]
fn test_behavior_mouse_path_single_step() {
let b = BehaviorSimulator::new(42);
let path = b.generate_mouse_path(0.0, 0.0, 100.0, 100.0, 1);
assert_eq!(path.len(), 2);
}
#[test]
fn test_behavior_typing_delays_count() {
let b = BehaviorSimulator::new(42);
let delays = b.generate_typing_delays(10);
assert!(
delays.len() >= 10,
"Expected >= 10 delays, got {}",
delays.len()
);
}
#[test]
fn test_behavior_typing_delays_range() {
let b = BehaviorSimulator::new(42);
let delays = b.generate_typing_delays(100);
for d in &delays {
assert!(*d > 0, "delay should be positive");
assert!(*d < 5000, "delay too large: {}", d);
}
}
#[test]
fn test_behavior_typing_delays_deterministic() {
let b = BehaviorSimulator::new(42);
let d1 = b.generate_typing_delays(5);
let d2 = b.generate_typing_delays(5);
assert_eq!(d1, d2);
}
#[test]
fn test_behavior_scroll_deltas_count() {
let b = BehaviorSimulator::new(42);
let deltas = b.generate_scroll_deltas(500.0, 20);
assert!(!deltas.is_empty());
}
#[test]
fn test_behavior_scroll_deltas_deterministic() {
let b = BehaviorSimulator::new(42);
let d1 = b.generate_scroll_deltas(500.0, 10);
let d2 = b.generate_scroll_deltas(500.0, 10);
assert_eq!(d1, d2);
}
#[test]
fn test_behavior_scroll_deltas_non_negative() {
let b = BehaviorSimulator::new(42);
let deltas = b.generate_scroll_deltas(500.0, 20);
for d in &deltas {
assert!(d.is_finite());
}
}
#[test]
fn test_behavior_clone() {
let b = BehaviorSimulator::new(42);
let cloned = b.clone();
assert_eq!(b.seed(), cloned.seed());
}
#[test]
fn test_http2_firefox_akamai_format() {
let h2 = Http2Fingerprint::firefox();
let fp = h2.akamai_fingerprint();
let parts: Vec<&str> = fp.split(':').collect();
assert_eq!(parts.len(), 6);
assert_eq!(parts[0], "65536"); }
#[test]
fn test_http2_chrome_akamai_format() {
let h2 = Http2Fingerprint::chrome();
let fp = h2.akamai_fingerprint();
assert!(fp.starts_with("65536:"));
}
#[test]
fn test_http2_firefox_initial_window_size() {
let h2 = Http2Fingerprint::firefox();
assert_eq!(h2.initial_window_size, 131072);
}
#[test]
fn test_http2_chrome_initial_window_size() {
let h2 = Http2Fingerprint::chrome();
assert_eq!(h2.initial_window_size, 6291456);
}
#[test]
fn test_http2_firefox_pseudo_header_order() {
let h2 = Http2Fingerprint::firefox();
assert_eq!(
h2.pseudo_header_order,
vec![":method", ":path", ":authority", ":scheme"]
);
}
#[test]
fn test_http2_chrome_pseudo_header_order() {
let h2 = Http2Fingerprint::chrome();
assert_eq!(
h2.pseudo_header_order,
vec![":method", ":authority", ":scheme", ":path"]
);
}
#[test]
fn test_http2_settings_frame_payload_count() {
let h2 = Http2Fingerprint::firefox();
let payload = h2.settings_frame_payload();
assert_eq!(payload.len(), 6);
}
#[test]
fn test_http2_settings_frame_payload_ids() {
let h2 = Http2Fingerprint::firefox();
let payload = h2.settings_frame_payload();
let ids: Vec<u16> = payload.iter().map(|(id, _)| *id).collect();
assert_eq!(ids, vec![0x01, 0x02, 0x03, 0x04, 0x05, 0x06]);
}
#[test]
fn test_http2_ordered_headers() {
let h2 = Http2Fingerprint::firefox();
let headers = vec![
(":scheme", "https"),
(":method", "GET"),
(":path", "/"),
(":authority", "example.com"),
("content-length", "0"),
];
let ordered = h2.ordered_headers(&headers);
assert_eq!(ordered[0].0, ":method");
assert_eq!(ordered[1].0, ":path");
assert_eq!(ordered[2].0, ":authority");
assert_eq!(ordered[3].0, ":scheme");
assert_eq!(ordered[4].0, "content-length");
}
#[test]
fn test_http2_ordered_headers_chrome() {
let h2 = Http2Fingerprint::chrome();
let headers = vec![
(":path", "/"),
(":method", "GET"),
("accept", "*/*"),
(":authority", "x.com"),
(":scheme", "https"),
];
let ordered = h2.ordered_headers(&headers);
assert_eq!(ordered[0].0, ":method");
assert_eq!(ordered[1].0, ":authority");
assert_eq!(ordered[2].0, ":scheme");
assert_eq!(ordered[3].0, ":path");
assert_eq!(ordered[4].0, "accept");
}
#[test]
fn test_http2_ordered_headers_no_pseudo() {
let h2 = Http2Fingerprint::firefox();
let headers = vec![("content-type", "text/html"), ("accept", "*/*")];
let ordered = h2.ordered_headers(&headers);
assert_eq!(ordered.len(), 2);
}
#[test]
fn test_http2_firefox_chrome_differ() {
let ff = Http2Fingerprint::firefox();
let ch = Http2Fingerprint::chrome();
assert_ne!(ff.initial_window_size, ch.initial_window_size);
assert_ne!(ff.max_concurrent_streams, ch.max_concurrent_streams);
assert_ne!(ff.window_update_size, ch.window_update_size);
assert_ne!(ff.pseudo_header_order, ch.pseudo_header_order);
}
#[test]
fn test_http2_both_disable_push() {
let ff = Http2Fingerprint::firefox();
let ch = Http2Fingerprint::chrome();
assert!(!ff.enable_push);
assert!(!ch.enable_push);
}
#[test]
fn test_http2_clone() {
let h2 = Http2Fingerprint::firefox();
let cloned = h2.clone();
assert_eq!(h2.initial_window_size, cloned.initial_window_size);
assert_eq!(
h2.pseudo_header_order.len(),
cloned.pseudo_header_order.len()
);
}
#[test]
fn test_http2_debug() {
let h2 = Http2Fingerprint::firefox();
let debug = format!("{:?}", h2);
assert!(debug.contains("Http2Fingerprint") || debug.contains("131072"));
}