aether/debugger/
breakpoint.rs1#[derive(Debug, Clone, PartialEq)]
6pub enum BreakpointType {
7 Line { file: String, line: usize },
9 Function { name: String },
11 Conditional {
13 file: String,
14 line: usize,
15 condition: String,
16 },
17}
18
19#[derive(Debug, Clone, PartialEq)]
21pub struct Breakpoint {
22 pub id: usize,
23 pub bp_type: BreakpointType,
24 pub enabled: bool,
25 pub hit_count: usize,
26 pub ignore_count: usize, }
28
29impl Breakpoint {
30 pub fn new(id: usize, bp_type: BreakpointType) -> Self {
32 Breakpoint {
33 id,
34 bp_type,
35 enabled: true,
36 hit_count: 0,
37 ignore_count: 0,
38 }
39 }
40
41 pub fn should_trigger(&mut self, file: &str, line: usize) -> bool {
43 if !self.enabled {
44 return false;
45 }
46
47 let matches = match &self.bp_type {
48 BreakpointType::Line { file: f, line: l } => f == file && *l == line,
49 BreakpointType::Conditional {
50 file: f, line: l, ..
51 } => f == file && *l == line,
52 BreakpointType::Function { .. } => false, };
54
55 if matches && self.hit_count >= self.ignore_count {
56 self.hit_count += 1;
57 true
58 } else if matches {
59 self.hit_count += 1;
60 false
61 } else {
62 false
63 }
64 }
65
66 pub fn is_function_breakpoint(&self, func_name: &str) -> bool {
68 match &self.bp_type {
69 BreakpointType::Function { name } => name == func_name,
70 _ => false,
71 }
72 }
73
74 pub fn get_condition(&self) -> Option<&str> {
76 match &self.bp_type {
77 BreakpointType::Conditional { condition, .. } => Some(condition.as_str()),
78 _ => None,
79 }
80 }
81
82 pub fn location_string(&self) -> String {
84 match &self.bp_type {
85 BreakpointType::Line { file, line } => {
86 format!("{}:{}", file, line)
87 }
88 BreakpointType::Function { name } => {
89 format!("function '{}'", name)
90 }
91 BreakpointType::Conditional {
92 file,
93 line,
94 condition,
95 } => {
96 format!("{}:{} if {}", file, line, condition)
97 }
98 }
99 }
100}
101
102#[cfg(test)]
103mod tests {
104 use super::*;
105
106 #[test]
107 fn test_breakpoint_creation() {
108 let bp = Breakpoint::new(
109 1,
110 BreakpointType::Line {
111 file: "test.aether".to_string(),
112 line: 10,
113 },
114 );
115
116 assert_eq!(bp.id, 1);
117 assert!(bp.enabled);
118 assert_eq!(bp.hit_count, 0);
119 }
120
121 #[test]
122 fn test_breakpoint_trigger() {
123 let mut bp = Breakpoint::new(
124 1,
125 BreakpointType::Line {
126 file: "test.aether".to_string(),
127 line: 10,
128 },
129 );
130
131 assert!(bp.should_trigger("test.aether", 10));
132 assert!(!bp.should_trigger("test.aether", 11));
133 assert!(!bp.should_trigger("other.aether", 10));
134 }
135
136 #[test]
137 fn test_disabled_breakpoint() {
138 let mut bp = Breakpoint::new(
139 1,
140 BreakpointType::Line {
141 file: "test.aether".to_string(),
142 line: 10,
143 },
144 );
145 bp.enabled = false;
146
147 assert!(!bp.should_trigger("test.aether", 10));
148 }
149
150 #[test]
151 fn test_ignore_count() {
152 let mut bp = Breakpoint::new(
153 1,
154 BreakpointType::Line {
155 file: "test.aether".to_string(),
156 line: 10,
157 },
158 );
159 bp.ignore_count = 2;
160
161 assert!(!bp.should_trigger("test.aether", 10)); assert!(!bp.should_trigger("test.aether", 10)); assert!(bp.should_trigger("test.aether", 10)); }
165
166 #[test]
167 fn test_function_breakpoint() {
168 let bp = Breakpoint::new(
169 1,
170 BreakpointType::Function {
171 name: "myFunc".to_string(),
172 },
173 );
174
175 assert!(bp.is_function_breakpoint("myFunc"));
176 assert!(!bp.is_function_breakpoint("otherFunc"));
177 }
178}