#![cfg(feature = "dap")]
use pmat::cli::language_analyzer::Language;
use serde_json::json;
#[test]
fn test_dap_detects_rust_language() {
let server = pmat::services::dap::DapServer::new();
let init_request = json!({
"seq": 1,
"type": "request",
"command": "initialize",
"arguments": {
"clientID": "test",
"adapterID": "pmat"
}
});
server.handle_request(init_request);
let launch_request = json!({
"seq": 2,
"type": "request",
"command": "launch",
"arguments": {
"program": "tests/fixtures/sample.rs"
}
});
server.handle_request(launch_request);
assert_eq!(
server.current_language(),
Some(Language::Rust),
"Should detect Rust from .rs file"
);
}
#[test]
fn test_dap_detects_python_language() {
let server = pmat::services::dap::DapServer::new();
let init_request = json!({
"seq": 1,
"type": "request",
"command": "initialize",
"arguments": {"clientID": "test", "adapterID": "pmat"}
});
server.handle_request(init_request);
let launch_request = json!({
"seq": 2,
"type": "request",
"command": "launch",
"arguments": {
"program": "tests/fixtures/sample.py"
}
});
server.handle_request(launch_request);
assert_eq!(
server.current_language(),
Some(Language::Python),
"Should detect Python from .py file"
);
}
#[test]
fn test_dap_no_language_before_launch() {
let server = pmat::services::dap::DapServer::new();
assert_eq!(
server.current_language(),
None,
"Should have no language before program is launched"
);
}
#[test]
fn test_dap_caches_ast_after_launch() {
let server = pmat::services::dap::DapServer::new();
let init_request = json!({
"seq": 1,
"type": "request",
"command": "initialize",
"arguments": {"clientID": "test", "adapterID": "pmat"}
});
server.handle_request(init_request);
let launch_request = json!({
"seq": 2,
"type": "request",
"command": "launch",
"arguments": {
"program": "tests/fixtures/sample.rs"
}
});
server.handle_request(launch_request);
assert!(
server.has_ast_for("tests/fixtures/sample.rs"),
"Should cache AST for launched program"
);
}
#[test]
fn test_dap_no_ast_before_launch() {
let server = pmat::services::dap::DapServer::new();
assert!(
!server.has_ast_for("tests/fixtures/sample.rs"),
"Should not have AST before launch"
);
}
#[test]
fn test_dap_caches_ast_for_multiple_files() {
let server = pmat::services::dap::DapServer::new();
let init_request = json!({
"seq": 1,
"type": "request",
"command": "initialize",
"arguments": {"clientID": "test", "adapterID": "pmat"}
});
server.handle_request(init_request);
let launch_request1 = json!({
"seq": 2,
"type": "request",
"command": "launch",
"arguments": {
"program": "tests/fixtures/sample.rs"
}
});
server.handle_request(launch_request1);
let bp_request = json!({
"seq": 3,
"type": "request",
"command": "setBreakpoints",
"arguments": {
"source": {"path": "tests/fixtures/complex.rs"},
"breakpoints": [{"line": 10}]
}
});
server.handle_request(bp_request);
assert!(
server.has_ast_for("tests/fixtures/sample.rs"),
"Should cache AST for launched program"
);
assert!(
server.has_ast_for("tests/fixtures/complex.rs"),
"Should cache AST when breakpoints are set"
);
}
#[test]
fn test_dap_extracts_variables_at_breakpoint() {
let server = pmat::services::dap::DapServer::new();
let init_request = json!({
"seq": 1,
"type": "request",
"command": "initialize",
"arguments": {"clientID": "test", "adapterID": "pmat"}
});
server.handle_request(init_request);
let launch_request = json!({
"seq": 2,
"type": "request",
"command": "launch",
"arguments": {
"program": "tests/fixtures/complex.rs"
}
});
server.handle_request(launch_request);
let bp_request = json!({
"seq": 3,
"type": "request",
"command": "setBreakpoints",
"arguments": {
"source": {"path": "tests/fixtures/complex.rs"},
"breakpoints": [{"line": 11}]
}
});
server.handle_request(bp_request);
let variables = server.get_variables_at_line("tests/fixtures/complex.rs", 11);
assert!(
variables.is_ok(),
"Should successfully extract variables: {:?}",
variables
);
let vars = variables.unwrap();
assert!(
!vars.is_empty(),
"Should find variables at line 11 (deeply_nested scope)"
);
let var_names: Vec<String> = vars.iter().map(|v| v.name.clone()).collect();
assert!(
var_names.contains(&"deeply_nested".to_string()),
"Should find deeply_nested variable. Found: {:?}",
var_names
);
}
#[test]
fn test_dap_returns_empty_variables_when_none_exist() {
let server = pmat::services::dap::DapServer::new();
let init_request = json!({
"seq": 1,
"type": "request",
"command": "initialize",
"arguments": {"clientID": "test", "adapterID": "pmat"}
});
server.handle_request(init_request);
let launch_request = json!({
"seq": 2,
"type": "request",
"command": "launch",
"arguments": {
"program": "tests/fixtures/sample.rs"
}
});
server.handle_request(launch_request);
let variables = server.get_variables_at_line("tests/fixtures/sample.rs", 1);
assert!(variables.is_ok(), "Should succeed even with no variables");
assert_eq!(
variables.unwrap().len(),
0,
"Should return empty vector for comment line"
);
}
#[test]
fn test_dap_handles_variable_shadowing() {
let server = pmat::services::dap::DapServer::new();
let init_request = json!({
"seq": 1,
"type": "request",
"command": "initialize",
"arguments": {"clientID": "test", "adapterID": "pmat"}
});
server.handle_request(init_request);
let launch_request = json!({
"seq": 2,
"type": "request",
"command": "launch",
"arguments": {
"program": "tests/fixtures/complex.rs"
}
});
server.handle_request(launch_request);
let variables = server.get_variables_at_line("tests/fixtures/complex.rs", 25);
assert!(variables.is_ok(), "Should handle shadowed variables");
let vars = variables.unwrap();
let x_var = vars.iter().find(|v| v.name == "x");
assert!(x_var.is_some(), "Should find shadowed variable 'x'");
assert_eq!(
x_var.unwrap().type_info,
"&str",
"Should return &str type for shadowed x (not i32)"
);
}
#[test]
#[ignore = "DAP Python variable extraction not yet implemented"]
fn test_dap_extracts_python_variables() {
let server = pmat::services::dap::DapServer::new();
let init_request = json!({
"seq": 1,
"type": "request",
"command": "initialize",
"arguments": {"clientID": "test", "adapterID": "pmat"}
});
server.handle_request(init_request);
let launch_request = json!({
"seq": 2,
"type": "request",
"command": "launch",
"arguments": {
"program": "tests/fixtures/sample.py"
}
});
server.handle_request(launch_request);
let variables = server.get_variables_at_line("tests/fixtures/sample.py", 5);
assert!(variables.is_ok(), "Should extract Python variables");
let vars = variables.unwrap();
assert!(
vars.len() >= 3,
"Should find at least 3 variables (x, y, result, doubled)"
);
let var_names: Vec<String> = vars.iter().map(|v| v.name.clone()).collect();
assert!(
var_names.contains(&"result".to_string()),
"Should find 'result' variable"
);
}
#[test]
fn test_dap_scopes_request_integrates_with_variable_inspector() {
let mut server = pmat::services::dap::DapServer::new();
let init_request = json!({
"seq": 1,
"type": "request",
"command": "initialize",
"arguments": {"clientID": "test", "adapterID": "pmat"}
});
server.handle_request(init_request);
let launch_request = json!({
"seq": 2,
"type": "request",
"command": "launch",
"arguments": {
"program": "tests/fixtures/complex.rs"
}
});
server.handle_request(launch_request);
server.simulate_stop_at_line("tests/fixtures/complex.rs", 11);
let scopes_request = json!({
"seq": 3,
"type": "request",
"command": "scopes",
"arguments": {
"frameId": 0
}
});
let response = server.handle_request(scopes_request);
let scopes = response["body"]["scopes"].as_array();
assert!(scopes.is_some(), "Should return scopes array");
assert!(
!scopes.unwrap().is_empty(),
"Should have at least one scope (locals)"
);
let local_scope = &scopes.unwrap()[0];
assert_eq!(
local_scope["name"].as_str().unwrap(),
"Locals",
"First scope should be 'Locals'"
);
assert!(
local_scope["variablesReference"].as_i64().unwrap() > 0,
"Should have non-zero variable reference"
);
}
#[test]
fn test_dap_variables_request_returns_inspected_variables() {
let mut server = pmat::services::dap::DapServer::new();
let init_request = json!({
"seq": 1,
"type": "request",
"command": "initialize",
"arguments": {"clientID": "test", "adapterID": "pmat"}
});
server.handle_request(init_request);
let launch_request = json!({
"seq": 2,
"type": "request",
"command": "launch",
"arguments": {
"program": "tests/fixtures/complex.rs"
}
});
server.handle_request(launch_request);
server.simulate_stop_at_line("tests/fixtures/complex.rs", 11);
let scopes_request = json!({
"seq": 3,
"type": "request",
"command": "scopes",
"arguments": {"frameId": 0}
});
let scopes_response = server.handle_request(scopes_request);
let var_ref = scopes_response["body"]["scopes"][0]["variablesReference"]
.as_i64()
.unwrap();
let vars_request = json!({
"seq": 4,
"type": "request",
"command": "variables",
"arguments": {
"variablesReference": var_ref
}
});
let response = server.handle_request(vars_request);
let variables = response["body"]["variables"].as_array();
assert!(variables.is_some(), "Should return variables array");
assert!(
!variables.unwrap().is_empty(),
"Should have variables at line 11"
);
let vars_array = variables.unwrap();
let has_deeply_nested = vars_array
.iter()
.any(|v| v["name"].as_str() == Some("deeply_nested"));
assert!(
has_deeply_nested,
"Should include 'deeply_nested' variable. Got: {:?}",
vars_array
);
}