use cdp_server::*;
use serde_json::json;
#[test]
fn test_target_info_serde_roundtrip() {
let info = TargetInfo {
id: "t-1".into(),
target_type: "page".into(),
title: "Test".into(),
url: "https://example.com".into(),
web_socket_debugger_url: "ws://127.0.0.1:9222/devtools/page/t-1".into(),
};
let json_str = serde_json::to_string(&info).unwrap();
let parsed: TargetInfo = serde_json::from_str(&json_str).unwrap();
assert_eq!(parsed.id, info.id);
assert_eq!(parsed.target_type, info.target_type);
assert_eq!(parsed.title, info.title);
assert_eq!(parsed.url, info.url);
assert_eq!(parsed.web_socket_debugger_url, info.web_socket_debugger_url);
}
#[test]
fn test_target_info_json_fields() {
let info = TargetInfo {
id: "abc".into(),
target_type: "page".into(),
title: "Title".into(),
url: "https://test.com".into(),
web_socket_debugger_url: "ws://localhost:9222/devtools/page/abc".into(),
};
let json_val: serde_json::Value = serde_json::to_value(&info).unwrap();
assert_eq!(json_val["id"], "abc");
assert_eq!(json_val["type"], "page");
assert_eq!(json_val["title"], "Title");
assert_eq!(json_val["url"], "https://test.com");
assert_eq!(
json_val["web_socket_debugger_url"],
"ws://localhost:9222/devtools/page/abc"
);
}
#[test]
fn test_target_info_deserialize_with_type_field() {
let json = r#"{"id":"x","type":"iframe","title":"Sub","url":"about:blank","web_socket_debugger_url":"ws://127.0.0.1:9222/devtools/page/x"}"#;
let info: TargetInfo = serde_json::from_str(json).unwrap();
assert_eq!(info.target_type, "iframe");
}
#[test]
fn test_target_info_empty_fields() {
let info = TargetInfo {
id: String::new(),
target_type: String::new(),
title: String::new(),
url: String::new(),
web_socket_debugger_url: String::new(),
};
let json = serde_json::to_string(&info).unwrap();
let parsed: TargetInfo = serde_json::from_str(&json).unwrap();
assert!(parsed.id.is_empty());
}
#[test]
fn test_target_info_clone() {
let info = TargetInfo {
id: "t-1".into(),
target_type: "page".into(),
title: "Test".into(),
url: "about:blank".into(),
web_socket_debugger_url: String::new(),
};
let mut cloned = info.clone();
cloned.id = "t-2".into();
assert_eq!(info.id, "t-1");
assert_eq!(cloned.id, "t-2");
}
#[test]
fn test_target_info_debug() {
let info = TargetInfo {
id: "t-1".into(),
target_type: "page".into(),
title: "Test".into(),
url: "about:blank".into(),
web_socket_debugger_url: String::new(),
};
let debug = format!("{:?}", info);
assert!(debug.contains("t-1"));
assert!(debug.contains("page"));
}
#[test]
fn test_server_config_default_port() {
let config = ServerConfig::default();
assert_eq!(config.port, 9222);
}
#[test]
fn test_server_config_default_host() {
let config = ServerConfig::default();
assert_eq!(config.host, "127.0.0.1");
}
#[test]
fn test_server_config_default_max_sessions() {
let config = ServerConfig::default();
assert_eq!(config.max_sessions, 100);
}
#[test]
fn test_server_config_builder_full() {
let config = ServerConfig::builder()
.host("0.0.0.0")
.port(3000)
.max_sessions(200)
.browser_name("TestBrowser")
.user_agent("Agent/1.0")
.v8_version("SM")
.webkit_version("Servo")
.http_timeout_seconds(30)
.build();
assert_eq!(config.host, "0.0.0.0");
assert_eq!(config.port, 3000);
assert_eq!(config.max_sessions, 200);
assert_eq!(config.browser_name, "TestBrowser");
assert_eq!(config.user_agent.as_deref(), Some("Agent/1.0"));
assert_eq!(config.http_timeout_seconds, 30);
}
#[test]
fn test_server_config_builder_partial() {
let config = ServerConfig::builder().port(8888).build();
assert_eq!(config.port, 8888);
assert_eq!(config.host, "127.0.0.1"); }
#[test]
fn test_cdp_server_new_default() {
let server = CdpServer::new(ServerConfig::default());
assert_eq!(server.port(), 9222);
}
#[test]
fn test_cdp_server_custom_port() {
let server = CdpServer::new(ServerConfig::builder().port(5555).build());
assert_eq!(server.port(), 5555);
}
#[test]
fn test_cdp_server_ws_url_format() {
let server = CdpServer::new(ServerConfig::default());
let url = server.ws_url_for_target("test-id");
assert!(url.starts_with("ws://"));
assert!(url.contains("9222"));
assert!(url.contains("test-id"));
}
#[test]
fn test_cdp_server_ws_url_custom_port() {
let server = CdpServer::new(ServerConfig::builder().port(8080).build());
let url = server.ws_url_for_target("abc");
assert!(url.contains("8080"));
}
#[test]
fn test_cdp_server_registry_empty() {
let server = CdpServer::new(ServerConfig::default());
assert!(!server.registry().has_domain("Page"));
assert!(!server.registry().has_domain("Runtime"));
}
#[test]
fn test_cdp_server_broadcaster_exists() {
let server = CdpServer::new(ServerConfig::default());
let bc = server.broadcaster();
assert!(Arc::strong_count(&bc) >= 1);
}
struct NopSender;
impl EventSender for NopSender {
fn send_event(&self, _method: &str, _params: serde_json::Value) {}
}
struct EchoHandler {
name: &'static str,
}
impl DomainHandler for EchoHandler {
fn domain_name(&self) -> &'static str {
self.name
}
fn handle_command(
&self,
cmd: &str,
params: serde_json::Value,
_: &dyn EventSender,
) -> Result<serde_json::Value, CdpError> {
Ok(json!({"echo": cmd, "params": params}))
}
fn on_session_created(&self, _session_id: &str) {}
fn on_session_destroyed(&self, _session_id: &str) {}
}
#[test]
fn test_registry_register_and_dispatch() {
let reg = DomainRegistry::<EchoHandler>::new();
reg.register(EchoHandler { name: "Test" }).unwrap();
assert!(reg.has_domain("Test"));
let result = reg
.dispatch_command("Test.run", json!({"x": 1}), &NopSender)
.unwrap()
.unwrap();
assert_eq!(result["echo"], "Test.run");
assert_eq!(result["params"]["x"], 1);
}
#[test]
fn test_registry_unknown_domain_returns_none() {
let reg = DomainRegistry::<EchoHandler>::new();
assert!(reg
.dispatch_command("Unknown.method", json!({}), &NopSender)
.is_none());
}
#[test]
fn test_registry_no_dot_returns_none() {
let reg = DomainRegistry::<EchoHandler>::new();
assert!(reg
.dispatch_command("NoDotMethod", json!({}), &NopSender)
.is_none());
}
#[test]
fn test_registry_empty_method_returns_none() {
let reg = DomainRegistry::<EchoHandler>::new();
assert!(reg.dispatch_command("", json!({}), &NopSender).is_none());
}
#[test]
fn test_registry_dispatch_with_empty_params() {
let reg = DomainRegistry::<EchoHandler>::new();
reg.register(EchoHandler { name: "Page" }).unwrap();
let result = reg
.dispatch_command("Page.enable", json!({}), &NopSender)
.unwrap()
.unwrap();
assert_eq!(result["echo"], "Page.enable");
}
#[test]
fn test_broadcaster_no_sessions_no_panic() {
let sessions = Arc::new(std::sync::Mutex::new(std::collections::HashMap::new()));
let bc = EventBroadcaster::new(sessions);
bc.send_event("Page.loadEventFired", json!({}));
bc.send_event("Runtime.consoleAPICalled", json!({}));
}
#[test]
fn test_broadcaster_sender_sends() {
let sessions = Arc::new(std::sync::Mutex::new(std::collections::HashMap::new()));
let bc = EventBroadcaster::new(sessions);
let sender = bc.sender();
sender.send_event("Test.event", json!({"key": "val"}));
}
#[test]
fn test_broadcaster_clone_shares_state() {
let sessions = Arc::new(std::sync::Mutex::new(std::collections::HashMap::new()));
let bc1 = EventBroadcaster::new(sessions);
let bc2 = bc1.clone();
bc1.send_event("Test.a", json!({}));
bc2.send_event("Test.b", json!({}));
}
#[test]
fn test_session_state_ordering() {
assert!((SessionState::Created as u8) < (SessionState::Active as u8));
assert!((SessionState::Active as u8) < (SessionState::Closing as u8));
assert!((SessionState::Closing as u8) < (SessionState::Closed as u8));
}
#[test]
fn test_session_state_debug() {
assert_eq!(format!("{:?}", SessionState::Created), "Created");
assert_eq!(format!("{:?}", SessionState::Active), "Active");
assert_eq!(format!("{:?}", SessionState::Closing), "Closing");
assert_eq!(format!("{:?}", SessionState::Closed), "Closed");
}
#[test]
fn test_session_state_copy() {
let s1 = SessionState::Active;
let s2 = s1;
assert_eq!(s1, s2);
}
#[test]
fn test_session_state_equality() {
assert_eq!(SessionState::Created, SessionState::Created);
assert_ne!(SessionState::Active, SessionState::Closed);
}
#[test]
fn test_cdp_error_fields() {
let err = CdpError {
code: -32600,
message: "invalid".into(),
};
assert_eq!(err.code, -32600);
assert_eq!(err.message, "invalid");
}
#[test]
fn test_cdp_error_debug() {
let err = CdpError {
code: -32700,
message: "parse".into(),
};
assert!(format!("{:?}", err).contains("-32700"));
}
#[test]
fn test_cdp_response_success_serializes() {
let resp = CdpResponse {
id: Some(1),
result: Some(json!({"ok": true})),
error: None,
};
let raw = serde_json::to_string(&resp).unwrap();
let parsed: serde_json::Value = serde_json::from_str(&raw).unwrap();
assert_eq!(parsed["id"], 1);
assert_eq!(parsed["result"]["ok"], true);
}
#[test]
fn test_cdp_response_error_serializes() {
let resp = CdpResponse {
id: Some(42),
result: None,
error: Some(CdpError {
code: -32601,
message: "not found".into(),
}),
};
let raw = serde_json::to_string(&resp).unwrap();
let parsed: serde_json::Value = serde_json::from_str(&raw).unwrap();
assert!(parsed.get("result").is_none());
assert_eq!(parsed["error"]["code"], -32601);
}
#[test]
fn test_cdp_event_with_params() {
let ev = CdpEvent {
method: "Page.load".into(),
params: Some(json!({"ts": 1})),
};
let raw = serde_json::to_string(&ev).unwrap();
let parsed: serde_json::Value = serde_json::from_str(&raw).unwrap();
assert_eq!(parsed["method"], "Page.load");
assert_eq!(parsed["params"]["ts"], 1);
}
#[test]
fn test_cdp_event_without_params() {
let ev = CdpEvent {
method: "DOM.updated".into(),
params: None,
};
let raw = serde_json::to_string(&ev).unwrap();
let parsed: serde_json::Value = serde_json::from_str(&raw).unwrap();
assert!(parsed.get("params").is_none());
}
use std::sync::Arc;