#![cfg(feature = "dap")]
use serde_json::json;
#[test]
fn test_set_breakpoint_in_rust_file() {
let mut mgr = pmat::services::dap::BreakpointManager::new();
let bp = pmat::services::dap::Breakpoint {
source: "src/main.rs".to_string(),
line: 10,
column: None,
condition: None,
};
let result = mgr.set_breakpoint(bp.clone());
assert!(result.is_ok(), "Setting valid breakpoint should succeed");
assert_eq!(mgr.count(), 1, "Should have 1 breakpoint");
assert!(
mgr.has_breakpoint(&bp.source, bp.line),
"Should find breakpoint at line 10"
);
}
#[test]
fn test_remove_breakpoint() {
let mut mgr = pmat::services::dap::BreakpointManager::new();
let bp = pmat::services::dap::Breakpoint {
source: "src/main.rs".to_string(),
line: 10,
column: None,
condition: None,
};
mgr.set_breakpoint(bp.clone()).unwrap();
assert_eq!(mgr.count(), 1);
let result = mgr.remove_breakpoint(&bp.source, bp.line);
assert!(
result.is_ok(),
"Removing existing breakpoint should succeed"
);
assert_eq!(mgr.count(), 0, "Should have 0 breakpoints after removal");
assert!(
!mgr.has_breakpoint(&bp.source, bp.line),
"Should not find breakpoint after removal"
);
}
#[test]
fn test_multiple_breakpoints_same_file() {
let mut mgr = pmat::services::dap::BreakpointManager::new();
let bp1 = pmat::services::dap::Breakpoint {
source: "src/main.rs".to_string(),
line: 10,
column: None,
condition: None,
};
let bp2 = pmat::services::dap::Breakpoint {
source: "src/main.rs".to_string(),
line: 20,
column: None,
condition: None,
};
mgr.set_breakpoint(bp1.clone()).unwrap();
mgr.set_breakpoint(bp2.clone()).unwrap();
assert_eq!(mgr.count(), 2, "Should have 2 breakpoints");
assert!(mgr.has_breakpoint(&bp1.source, bp1.line));
assert!(mgr.has_breakpoint(&bp2.source, bp2.line));
}
#[test]
fn test_breakpoints_multiple_files() {
let mut mgr = pmat::services::dap::BreakpointManager::new();
let bp1 = pmat::services::dap::Breakpoint {
source: "src/main.rs".to_string(),
line: 10,
column: None,
condition: None,
};
let bp2 = pmat::services::dap::Breakpoint {
source: "src/lib.rs".to_string(),
line: 15,
column: None,
condition: None,
};
mgr.set_breakpoint(bp1.clone()).unwrap();
mgr.set_breakpoint(bp2.clone()).unwrap();
assert_eq!(mgr.count(), 2);
assert_eq!(mgr.breakpoints_in_file(&bp1.source).len(), 1);
assert_eq!(mgr.breakpoints_in_file(&bp2.source).len(), 1);
}
#[test]
fn test_clear_all_breakpoints() {
let mut mgr = pmat::services::dap::BreakpointManager::new();
mgr.set_breakpoint(pmat::services::dap::Breakpoint {
source: "src/main.rs".to_string(),
line: 10,
column: None,
condition: None,
})
.unwrap();
mgr.set_breakpoint(pmat::services::dap::Breakpoint {
source: "src/lib.rs".to_string(),
line: 15,
column: None,
condition: None,
})
.unwrap();
assert_eq!(mgr.count(), 2);
mgr.clear_all();
assert_eq!(mgr.count(), 0, "Should have 0 breakpoints after clear");
}
#[test]
fn test_clear_file_breakpoints() {
let mut mgr = pmat::services::dap::BreakpointManager::new();
mgr.set_breakpoint(pmat::services::dap::Breakpoint {
source: "src/main.rs".to_string(),
line: 10,
column: None,
condition: None,
})
.unwrap();
mgr.set_breakpoint(pmat::services::dap::Breakpoint {
source: "src/lib.rs".to_string(),
line: 15,
column: None,
condition: None,
})
.unwrap();
mgr.clear_file("src/main.rs");
assert_eq!(
mgr.count(),
1,
"Should have 1 breakpoint after clearing main.rs"
);
assert_eq!(mgr.breakpoints_in_file("src/lib.rs").len(), 1);
assert_eq!(mgr.breakpoints_in_file("src/main.rs").len(), 0);
}
#[test]
fn test_conditional_breakpoint_simple() {
let mut mgr = pmat::services::dap::BreakpointManager::new();
let bp = pmat::services::dap::Breakpoint {
source: "src/main.rs".to_string(),
line: 10,
column: None,
condition: Some("x > 5".to_string()),
};
mgr.set_breakpoint(bp.clone()).unwrap();
let retrieved = mgr.get_breakpoint(&bp.source, bp.line);
assert!(retrieved.is_some(), "Should find breakpoint");
assert_eq!(retrieved.unwrap().condition, Some("x > 5".to_string()));
}
#[test]
fn test_conditional_breakpoint_evaluation() {
let mut mgr = pmat::services::dap::BreakpointManager::new();
let bp = pmat::services::dap::Breakpoint {
source: "src/main.rs".to_string(),
line: 10,
column: None,
condition: Some("count == 3".to_string()),
};
mgr.set_breakpoint(bp.clone()).unwrap();
let variables = json!({
"count": 3
});
let should_break = mgr.should_break(&bp.source, bp.line, Some(&variables));
assert!(should_break, "Should break when condition is true");
let variables2 = json!({
"count": 5
});
let should_not_break = mgr.should_break(&bp.source, bp.line, Some(&variables2));
assert!(
!should_not_break,
"Should not break when condition is false"
);
}
#[test]
fn test_unconditional_breakpoint_always_breaks() {
let mut mgr = pmat::services::dap::BreakpointManager::new();
let bp = pmat::services::dap::Breakpoint {
source: "src/main.rs".to_string(),
line: 10,
column: None,
condition: None,
};
mgr.set_breakpoint(bp.clone()).unwrap();
let should_break1 = mgr.should_break(&bp.source, bp.line, None);
assert!(
should_break1,
"Unconditional breakpoint should always break (no vars)"
);
let variables = json!({"x": 10});
let should_break2 = mgr.should_break(&bp.source, bp.line, Some(&variables));
assert!(
should_break2,
"Unconditional breakpoint should always break (with vars)"
);
}
#[test]
fn test_hit_count_tracking() {
let mut mgr = pmat::services::dap::BreakpointManager::new();
let bp = pmat::services::dap::Breakpoint {
source: "src/main.rs".to_string(),
line: 10,
column: None,
condition: None,
};
mgr.set_breakpoint(bp.clone()).unwrap();
assert_eq!(mgr.get_hit_count(&bp.source, bp.line), 0);
mgr.record_hit(&bp.source, bp.line);
assert_eq!(mgr.get_hit_count(&bp.source, bp.line), 1);
mgr.record_hit(&bp.source, bp.line);
assert_eq!(mgr.get_hit_count(&bp.source, bp.line), 2);
mgr.record_hit(&bp.source, bp.line);
assert_eq!(mgr.get_hit_count(&bp.source, bp.line), 3);
}
#[test]
fn test_hit_count_reset_on_removal() {
let mut mgr = pmat::services::dap::BreakpointManager::new();
let bp = pmat::services::dap::Breakpoint {
source: "src/main.rs".to_string(),
line: 10,
column: None,
condition: None,
};
mgr.set_breakpoint(bp.clone()).unwrap();
mgr.record_hit(&bp.source, bp.line);
mgr.record_hit(&bp.source, bp.line);
assert_eq!(mgr.get_hit_count(&bp.source, bp.line), 2);
mgr.remove_breakpoint(&bp.source, bp.line).unwrap();
mgr.set_breakpoint(bp.clone()).unwrap();
assert_eq!(mgr.get_hit_count(&bp.source, bp.line), 0);
}
#[test]
fn test_concurrent_breakpoint_access() {
use std::sync::{Arc, Mutex};
use std::thread;
let mgr = Arc::new(Mutex::new(pmat::services::dap::BreakpointManager::new()));
let mut handles = vec![];
for i in 0..10 {
let mgr_clone = Arc::clone(&mgr);
let handle = thread::spawn(move || {
let mut mgr = mgr_clone.lock().unwrap();
let bp = pmat::services::dap::Breakpoint {
source: "src/main.rs".to_string(),
line: 10 + i as i64,
column: None,
condition: None,
};
mgr.set_breakpoint(bp).unwrap();
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
let mgr = mgr.lock().unwrap();
assert_eq!(
mgr.count(),
10,
"Should have 10 breakpoints from concurrent access"
);
}
#[test]
fn test_get_all_breakpoints() {
let mut mgr = pmat::services::dap::BreakpointManager::new();
mgr.set_breakpoint(pmat::services::dap::Breakpoint {
source: "src/main.rs".to_string(),
line: 10,
column: None,
condition: None,
})
.unwrap();
mgr.set_breakpoint(pmat::services::dap::Breakpoint {
source: "src/lib.rs".to_string(),
line: 15,
column: None,
condition: Some("x > 0".to_string()),
})
.unwrap();
let all_bps = mgr.all_breakpoints();
assert_eq!(all_bps.len(), 2, "Should return all breakpoints");
}
#[test]
fn test_duplicate_breakpoint_handling() {
let mut mgr = pmat::services::dap::BreakpointManager::new();
let bp = pmat::services::dap::Breakpoint {
source: "src/main.rs".to_string(),
line: 10,
column: None,
condition: None,
};
mgr.set_breakpoint(bp.clone()).unwrap();
assert_eq!(mgr.count(), 1);
let bp_updated = pmat::services::dap::Breakpoint {
source: "src/main.rs".to_string(),
line: 10,
column: None,
condition: Some("x > 5".to_string()),
};
mgr.set_breakpoint(bp_updated.clone()).unwrap();
assert_eq!(
mgr.count(),
1,
"Should still have 1 breakpoint (updated, not duplicated)"
);
let retrieved = mgr.get_breakpoint(&bp.source, bp.line);
assert_eq!(retrieved.unwrap().condition, Some("x > 5".to_string()));
}
#[test]
fn test_performance_many_breakpoints() {
use std::time::Instant;
let mut mgr = pmat::services::dap::BreakpointManager::new();
let start = Instant::now();
for i in 0..1000 {
let bp = pmat::services::dap::Breakpoint {
source: format!("src/file_{}.rs", i / 100),
line: i,
column: None,
condition: None,
};
mgr.set_breakpoint(bp).unwrap();
}
let duration = start.elapsed();
assert!(
duration.as_millis() < 100,
"Setting 1000 breakpoints should take less than 100ms, took {:?}",
duration
);
assert_eq!(mgr.count(), 1000);
}