1use depyler_hir::hir::{HirFunction, Type};
10use serde::{Deserialize, Serialize};
11use std::collections::HashMap;
12use std::path::PathBuf;
13
14#[derive(Debug, Clone, Serialize, Deserialize)]
16pub struct SourceMap {
17 pub source_file: PathBuf,
19 pub target_file: PathBuf,
21 pub mappings: Vec<SourceMapping>,
23 pub function_map: HashMap<String, FunctionMapping>,
25}
26
27#[derive(Debug, Clone, Serialize, Deserialize)]
28pub struct SourceMapping {
29 pub python_line: usize,
31 pub python_column: usize,
32 pub rust_line: usize,
34 pub rust_column: usize,
35 pub symbol: Option<String>,
37}
38
39#[derive(Debug, Clone, Serialize, Deserialize)]
40pub struct FunctionMapping {
41 pub python_name: String,
42 pub rust_name: String,
43 pub python_start_line: usize,
44 pub python_end_line: usize,
45 pub rust_start_line: usize,
46 pub rust_end_line: usize,
47}
48
49pub struct DebugInfoGenerator {
51 source_map: SourceMap,
52 current_rust_line: usize,
53 debug_level: DebugLevel,
54}
55
56#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
57pub enum DebugLevel {
58 None,
60 Basic,
62 Full,
64}
65
66impl DebugInfoGenerator {
67 pub fn new(source_file: PathBuf, target_file: PathBuf, debug_level: DebugLevel) -> Self {
68 Self {
69 source_map: SourceMap {
70 source_file,
71 target_file,
72 mappings: Vec::new(),
73 function_map: HashMap::new(),
74 },
75 current_rust_line: 1,
76 debug_level,
77 }
78 }
79
80 pub fn add_mapping(
82 &mut self,
83 python_line: usize,
84 python_column: usize,
85 symbol: Option<String>,
86 ) {
87 if self.debug_level == DebugLevel::None {
88 return;
89 }
90
91 self.source_map.mappings.push(SourceMapping {
92 python_line,
93 python_column,
94 rust_line: self.current_rust_line,
95 rust_column: 0, symbol,
97 });
98 }
99
100 pub fn add_function_mapping(&mut self, func: &HirFunction, rust_start: usize) {
102 if self.debug_level == DebugLevel::None {
103 return;
104 }
105
106 let rust_end = self.current_rust_line;
107 self.source_map.function_map.insert(
108 func.name.clone(),
109 FunctionMapping {
110 python_name: func.name.clone(),
111 rust_name: func.name.clone(), python_start_line: 0, python_end_line: 0,
114 rust_start_line: rust_start,
115 rust_end_line: rust_end,
116 },
117 );
118 }
119
120 pub fn new_line(&mut self) {
122 self.current_rust_line += 1;
123 }
124
125 pub fn source_map(&self) -> &SourceMap {
127 &self.source_map
128 }
129
130 pub fn generate_function_debug(&self, func: &HirFunction) -> String {
132 match self.debug_level {
133 DebugLevel::None => String::new(),
134 DebugLevel::Basic => format!("// Function: {}\n", func.name),
135 DebugLevel::Full => {
136 format!(
137 "// Function: {} (Python source)\n// Parameters: {:?}\n// Returns: {:?}\n",
138 func.name,
139 func.params.iter().map(|p| &p.name).collect::<Vec<_>>(),
140 func.ret_type
141 )
142 }
143 }
144 }
145
146 pub fn generate_debug_print(&self, var_name: &str, var_type: &Type) -> String {
148 match self.debug_level {
149 DebugLevel::None => String::new(),
150 DebugLevel::Basic | DebugLevel::Full => match var_type {
151 Type::Int | Type::Float | Type::Bool => {
152 format!("eprintln!(\"DEBUG: {} = {{}}\", {});", var_name, var_name)
153 }
154 Type::String => {
155 format!("eprintln!(\"DEBUG: {} = {{}}\", {});", var_name, var_name)
156 }
157 _ => {
158 format!("eprintln!(\"DEBUG: {} = {{:?}}\", {});", var_name, var_name)
159 }
160 },
161 }
162 }
163}
164
165pub struct DebugRuntime;
167
168impl DebugRuntime {
169 pub fn breakpoint() -> &'static str {
171 "depyler_breakpoint!()"
172 }
173
174 pub fn debug_assert(condition: &str, message: &str) -> String {
176 format!("debug_assert!({}, \"{}\");", condition, message)
177 }
178
179 pub fn trace_point(location: &str) -> String {
181 format!("depyler_trace!(\"{}\");", location)
182 }
183}
184
185pub struct DebuggerIntegration {
187 debugger_type: DebuggerType,
188}
189
190#[derive(Debug, Clone, Copy)]
191pub enum DebuggerType {
192 Gdb,
193 Lldb,
194 RustGdb,
195}
196
197impl DebuggerIntegration {
198 pub fn new(debugger_type: DebuggerType) -> Self {
199 Self { debugger_type }
200 }
201
202 pub fn generate_init_script(&self, source_map: &SourceMap) -> String {
204 match self.debugger_type {
205 DebuggerType::Gdb | DebuggerType::RustGdb => self.generate_gdb_script(source_map),
206 DebuggerType::Lldb => self.generate_lldb_script(source_map),
207 }
208 }
209
210 fn generate_gdb_script(&self, source_map: &SourceMap) -> String {
211 let mut script = String::new();
212 script.push_str("# GDB initialization script for Depyler debugging\n");
213 script.push_str("# Source: ");
214 script.push_str(&source_map.source_file.display().to_string());
215 script.push_str("\n\n");
216
217 script.push_str("directory .\n");
219
220 for mapping in source_map.function_map.values() {
222 script.push_str(&format!("break {}\n", mapping.rust_name));
223 }
224
225 if matches!(self.debugger_type, DebuggerType::RustGdb) {
227 script.push_str("\n# Load Rust pretty printers\n");
228 script.push_str("python\nimport gdb\n");
229 script.push_str("gdb.execute('set print pretty on')\n");
230 script.push_str("end\n");
231 }
232
233 script
234 }
235
236 fn generate_lldb_script(&self, source_map: &SourceMap) -> String {
237 let mut script = String::new();
238 script.push_str("# LLDB initialization script for Depyler debugging\n");
239 script.push_str("# Source: ");
240 script.push_str(&source_map.source_file.display().to_string());
241 script.push_str("\n\n");
242
243 script.push_str("settings set target.source-map . .\n");
245
246 for mapping in source_map.function_map.values() {
248 script.push_str(&format!("breakpoint set --name {}\n", mapping.rust_name));
249 }
250
251 script
252 }
253}
254
255#[derive(Debug, Clone, Serialize, Deserialize)]
257pub struct DebugConfig {
258 pub debug_level: DebugLevel,
259 pub generate_source_map: bool,
260 pub preserve_symbols: bool,
261 pub debug_prints: bool,
262 pub breakpoints: bool,
263}
264
265impl Default for DebugConfig {
266 fn default() -> Self {
267 Self {
268 debug_level: DebugLevel::Basic,
269 generate_source_map: true,
270 preserve_symbols: true,
271 debug_prints: false,
272 breakpoints: false,
273 }
274 }
275}
276
277pub fn generate_debug_macros() -> String {
279 r#"
280// Depyler debugging macros
281#[macro_export]
282macro_rules! depyler_breakpoint {
283 () => {
284 #[cfg(debug_assertions)]
285 {
286 eprintln!("BREAKPOINT at {}:{}", file!(), line!());
287 // Uncomment to actually break in debugger
288 // std::intrinsics::breakpoint();
289 }
290 };
291}
292
293#[macro_export]
294macro_rules! depyler_trace {
295 ($msg:expr) => {
296 #[cfg(debug_assertions)]
297 eprintln!("[TRACE] {} at {}:{}", $msg, file!(), line!());
298 };
299}
300"#
301 .to_string()
302}
303
304#[cfg(test)]
305mod tests {
306 use super::*;
307 use depyler_hir::hir::{FunctionProperties, HirParam};
308 use smallvec::smallvec;
309
310 #[test]
313 fn test_source_map_new() {
314 let sm = SourceMap {
315 source_file: PathBuf::from("input.py"),
316 target_file: PathBuf::from("output.rs"),
317 mappings: vec![],
318 function_map: HashMap::new(),
319 };
320 assert_eq!(sm.source_file, PathBuf::from("input.py"));
321 assert_eq!(sm.target_file, PathBuf::from("output.rs"));
322 assert!(sm.mappings.is_empty());
323 }
324
325 #[test]
326 fn test_source_map_clone() {
327 let sm = SourceMap {
328 source_file: PathBuf::from("a.py"),
329 target_file: PathBuf::from("a.rs"),
330 mappings: vec![SourceMapping {
331 python_line: 1,
332 python_column: 0,
333 rust_line: 1,
334 rust_column: 0,
335 symbol: None,
336 }],
337 function_map: HashMap::new(),
338 };
339 let cloned = sm.clone();
340 assert_eq!(cloned.mappings.len(), 1);
341 }
342
343 #[test]
344 fn test_source_map_serialize() {
345 let sm = SourceMap {
346 source_file: PathBuf::from("test.py"),
347 target_file: PathBuf::from("test.rs"),
348 mappings: vec![],
349 function_map: HashMap::new(),
350 };
351 let json = serde_json::to_string(&sm).unwrap();
352 assert!(json.contains("test.py"));
353 let deserialized: SourceMap = serde_json::from_str(&json).unwrap();
354 assert_eq!(deserialized.source_file, sm.source_file);
355 }
356
357 #[test]
360 fn test_source_mapping_new() {
361 let mapping = SourceMapping {
362 python_line: 42,
363 python_column: 8,
364 rust_line: 100,
365 rust_column: 4,
366 symbol: Some("my_func".to_string()),
367 };
368 assert_eq!(mapping.python_line, 42);
369 assert_eq!(mapping.rust_line, 100);
370 assert_eq!(mapping.symbol, Some("my_func".to_string()));
371 }
372
373 #[test]
374 fn test_source_mapping_clone() {
375 let mapping = SourceMapping {
376 python_line: 1,
377 python_column: 0,
378 rust_line: 5,
379 rust_column: 0,
380 symbol: None,
381 };
382 let cloned = mapping.clone();
383 assert_eq!(cloned.python_line, mapping.python_line);
384 }
385
386 #[test]
387 fn test_source_mapping_serialize() {
388 let mapping = SourceMapping {
389 python_line: 10,
390 python_column: 2,
391 rust_line: 20,
392 rust_column: 4,
393 symbol: Some("var".to_string()),
394 };
395 let json = serde_json::to_string(&mapping).unwrap();
396 assert!(json.contains("10"));
397 assert!(json.contains("var"));
398 }
399
400 #[test]
403 fn test_function_mapping_new() {
404 let fm = FunctionMapping {
405 python_name: "py_func".to_string(),
406 rust_name: "rust_func".to_string(),
407 python_start_line: 5,
408 python_end_line: 15,
409 rust_start_line: 10,
410 rust_end_line: 30,
411 };
412 assert_eq!(fm.python_name, "py_func");
413 assert_eq!(fm.rust_name, "rust_func");
414 }
415
416 #[test]
417 fn test_function_mapping_clone() {
418 let fm = FunctionMapping {
419 python_name: "f".to_string(),
420 rust_name: "f".to_string(),
421 python_start_line: 1,
422 python_end_line: 2,
423 rust_start_line: 3,
424 rust_end_line: 4,
425 };
426 let cloned = fm.clone();
427 assert_eq!(cloned.python_name, fm.python_name);
428 }
429
430 #[test]
433 fn test_debug_level_none() {
434 assert_eq!(DebugLevel::None, DebugLevel::None);
435 assert_ne!(DebugLevel::None, DebugLevel::Basic);
436 }
437
438 #[test]
439 fn test_debug_level_basic() {
440 assert_eq!(DebugLevel::Basic, DebugLevel::Basic);
441 }
442
443 #[test]
444 fn test_debug_level_full() {
445 let level = DebugLevel::Full;
446 let cloned = level;
447 assert_eq!(cloned, DebugLevel::Full);
448 }
449
450 #[test]
451 fn test_debug_level_serialize() {
452 let level = DebugLevel::Full;
453 let json = serde_json::to_string(&level).unwrap();
454 let deserialized: DebugLevel = serde_json::from_str(&json).unwrap();
455 assert_eq!(deserialized, level);
456 }
457
458 #[test]
461 fn test_debug_info_generator_new() {
462 let gen = DebugInfoGenerator::new(
463 PathBuf::from("src.py"),
464 PathBuf::from("src.rs"),
465 DebugLevel::Basic,
466 );
467 assert_eq!(gen.current_rust_line, 1);
468 assert_eq!(gen.debug_level, DebugLevel::Basic);
469 }
470
471 #[test]
472 fn test_debug_info_generator_add_mapping_none_level() {
473 let mut gen = DebugInfoGenerator::new(
474 PathBuf::from("a.py"),
475 PathBuf::from("a.rs"),
476 DebugLevel::None,
477 );
478 gen.add_mapping(10, 0, Some("test".to_string()));
479 assert!(gen.source_map().mappings.is_empty());
481 }
482
483 #[test]
484 fn test_debug_info_generator_new_line() {
485 let mut gen = DebugInfoGenerator::new(
486 PathBuf::from("a.py"),
487 PathBuf::from("a.rs"),
488 DebugLevel::Basic,
489 );
490 assert_eq!(gen.current_rust_line, 1);
491 gen.new_line();
492 assert_eq!(gen.current_rust_line, 2);
493 gen.new_line();
494 gen.new_line();
495 assert_eq!(gen.current_rust_line, 4);
496 }
497
498 #[test]
499 fn test_debug_info_generator_source_map_getter() {
500 let gen = DebugInfoGenerator::new(
501 PathBuf::from("test.py"),
502 PathBuf::from("test.rs"),
503 DebugLevel::Full,
504 );
505 let sm = gen.source_map();
506 assert_eq!(sm.source_file, PathBuf::from("test.py"));
507 }
508
509 #[test]
510 fn test_generate_function_debug_none_level() {
511 let gen = DebugInfoGenerator::new(
512 PathBuf::from("a.py"),
513 PathBuf::from("a.rs"),
514 DebugLevel::None,
515 );
516 let func = HirFunction {
517 name: "test".to_string(),
518 params: smallvec![],
519 ret_type: Type::None,
520 body: vec![],
521 properties: FunctionProperties::default(),
522 annotations: depyler_annotations::TranspilationAnnotations::default(),
523 docstring: None,
524 };
525 let debug = gen.generate_function_debug(&func);
526 assert!(debug.is_empty());
527 }
528
529 #[test]
530 fn test_generate_function_debug_basic_level() {
531 let gen = DebugInfoGenerator::new(
532 PathBuf::from("a.py"),
533 PathBuf::from("a.rs"),
534 DebugLevel::Basic,
535 );
536 let func = HirFunction {
537 name: "my_func".to_string(),
538 params: smallvec![],
539 ret_type: Type::Int,
540 body: vec![],
541 properties: FunctionProperties::default(),
542 annotations: depyler_annotations::TranspilationAnnotations::default(),
543 docstring: None,
544 };
545 let debug = gen.generate_function_debug(&func);
546 assert!(debug.contains("// Function: my_func"));
547 assert!(!debug.contains("Parameters")); }
549
550 #[test]
551 fn test_generate_function_debug_full_level() {
552 let gen = DebugInfoGenerator::new(
553 PathBuf::from("a.py"),
554 PathBuf::from("a.rs"),
555 DebugLevel::Full,
556 );
557 let func = HirFunction {
558 name: "calc".to_string(),
559 params: smallvec![HirParam::new("x".to_string(), Type::Int)],
560 ret_type: Type::Int,
561 body: vec![],
562 properties: FunctionProperties::default(),
563 annotations: depyler_annotations::TranspilationAnnotations::default(),
564 docstring: None,
565 };
566 let debug = gen.generate_function_debug(&func);
567 assert!(debug.contains("// Function: calc"));
568 assert!(debug.contains("Parameters"));
569 assert!(debug.contains("Returns"));
570 }
571
572 #[test]
573 fn test_generate_debug_print_none_level() {
574 let gen = DebugInfoGenerator::new(
575 PathBuf::from("a.py"),
576 PathBuf::from("a.rs"),
577 DebugLevel::None,
578 );
579 let debug = gen.generate_debug_print("x", &Type::Int);
580 assert!(debug.is_empty());
581 }
582
583 #[test]
584 fn test_generate_debug_print_float() {
585 let gen = DebugInfoGenerator::new(
586 PathBuf::from("a.py"),
587 PathBuf::from("a.rs"),
588 DebugLevel::Basic,
589 );
590 let debug = gen.generate_debug_print("value", &Type::Float);
591 assert!(debug.contains("eprintln!"));
592 assert!(debug.contains("value = {}"));
593 }
594
595 #[test]
596 fn test_generate_debug_print_bool() {
597 let gen = DebugInfoGenerator::new(
598 PathBuf::from("a.py"),
599 PathBuf::from("a.rs"),
600 DebugLevel::Full,
601 );
602 let debug = gen.generate_debug_print("flag", &Type::Bool);
603 assert!(debug.contains("flag = {}"));
604 }
605
606 #[test]
607 fn test_generate_debug_print_string() {
608 let gen = DebugInfoGenerator::new(
609 PathBuf::from("a.py"),
610 PathBuf::from("a.rs"),
611 DebugLevel::Basic,
612 );
613 let debug = gen.generate_debug_print("name", &Type::String);
614 assert!(debug.contains("name = {}"));
615 }
616
617 #[test]
618 fn test_add_function_mapping_none_level() {
619 let mut gen = DebugInfoGenerator::new(
620 PathBuf::from("a.py"),
621 PathBuf::from("a.rs"),
622 DebugLevel::None,
623 );
624 let func = HirFunction {
625 name: "test".to_string(),
626 params: smallvec![],
627 ret_type: Type::None,
628 body: vec![],
629 properties: FunctionProperties::default(),
630 annotations: depyler_annotations::TranspilationAnnotations::default(),
631 docstring: None,
632 };
633 gen.add_function_mapping(&func, 1);
634 assert!(gen.source_map().function_map.is_empty());
635 }
636
637 #[test]
638 fn test_add_function_mapping_full_level() {
639 let mut gen = DebugInfoGenerator::new(
640 PathBuf::from("a.py"),
641 PathBuf::from("a.rs"),
642 DebugLevel::Full,
643 );
644 gen.new_line(); gen.new_line(); let func = HirFunction {
647 name: "my_func".to_string(),
648 params: smallvec![],
649 ret_type: Type::Int,
650 body: vec![],
651 properties: FunctionProperties::default(),
652 annotations: depyler_annotations::TranspilationAnnotations::default(),
653 docstring: None,
654 };
655 gen.add_function_mapping(&func, 1);
656 assert!(gen.source_map().function_map.contains_key("my_func"));
657 let fm = gen.source_map().function_map.get("my_func").unwrap();
658 assert_eq!(fm.rust_start_line, 1);
659 assert_eq!(fm.rust_end_line, 3);
660 }
661
662 #[test]
665 fn test_debug_runtime_breakpoint() {
666 let bp = DebugRuntime::breakpoint();
667 assert_eq!(bp, "depyler_breakpoint!()");
668 }
669
670 #[test]
671 fn test_debug_runtime_debug_assert() {
672 let assertion = DebugRuntime::debug_assert("x > 0", "x must be positive");
673 assert!(assertion.contains("debug_assert!"));
674 assert!(assertion.contains("x > 0"));
675 assert!(assertion.contains("x must be positive"));
676 }
677
678 #[test]
679 fn test_debug_runtime_trace_point() {
680 let trace = DebugRuntime::trace_point("entering loop");
681 assert!(trace.contains("depyler_trace!"));
682 assert!(trace.contains("entering loop"));
683 }
684
685 #[test]
688 fn test_debugger_type_gdb() {
689 let dt = DebuggerType::Gdb;
690 let debug = format!("{:?}", dt);
691 assert!(debug.contains("Gdb"));
692 }
693
694 #[test]
695 fn test_debugger_type_lldb() {
696 let dt = DebuggerType::Lldb;
697 let cloned = dt;
698 assert!(matches!(cloned, DebuggerType::Lldb));
699 }
700
701 #[test]
702 fn test_debugger_type_rust_gdb() {
703 let dt = DebuggerType::RustGdb;
704 let debug = format!("{:?}", dt);
705 assert!(debug.contains("RustGdb"));
706 }
707
708 #[test]
711 fn test_debugger_integration_new() {
712 let di = DebuggerIntegration::new(DebuggerType::Gdb);
713 assert!(matches!(di.debugger_type, DebuggerType::Gdb));
714 }
715
716 #[test]
717 fn test_generate_rust_gdb_script() {
718 let source_map = SourceMap {
719 source_file: PathBuf::from("test.py"),
720 target_file: PathBuf::from("test.rs"),
721 mappings: vec![],
722 function_map: HashMap::new(),
723 };
724 let di = DebuggerIntegration::new(DebuggerType::RustGdb);
725 let script = di.generate_init_script(&source_map);
726 assert!(script.contains("GDB initialization"));
727 assert!(script.contains("Rust pretty printers"));
728 assert!(script.contains("python"));
729 }
730
731 #[test]
734 fn test_debug_config_default() {
735 let config = DebugConfig::default();
736 assert_eq!(config.debug_level, DebugLevel::Basic);
737 assert!(config.generate_source_map);
738 assert!(config.preserve_symbols);
739 assert!(!config.debug_prints);
740 assert!(!config.breakpoints);
741 }
742
743 #[test]
744 fn test_debug_config_clone() {
745 let config = DebugConfig {
746 debug_level: DebugLevel::Full,
747 generate_source_map: false,
748 preserve_symbols: false,
749 debug_prints: true,
750 breakpoints: true,
751 };
752 let cloned = config.clone();
753 assert_eq!(cloned.debug_level, DebugLevel::Full);
754 assert!(cloned.debug_prints);
755 }
756
757 #[test]
758 fn test_debug_config_serialize() {
759 let config = DebugConfig::default();
760 let json = serde_json::to_string(&config).unwrap();
761 assert!(json.contains("Basic"));
762 let deserialized: DebugConfig = serde_json::from_str(&json).unwrap();
763 assert_eq!(deserialized.debug_level, config.debug_level);
764 }
765
766 #[test]
769 fn test_generate_debug_macros() {
770 let macros = generate_debug_macros();
771 assert!(macros.contains("depyler_breakpoint"));
772 assert!(macros.contains("depyler_trace"));
773 assert!(macros.contains("#[macro_export]"));
774 assert!(macros.contains("debug_assertions"));
775 }
776
777 #[test]
780 fn test_source_mapping() {
781 let mut generator = DebugInfoGenerator::new(
782 PathBuf::from("test.py"),
783 PathBuf::from("test.rs"),
784 DebugLevel::Full,
785 );
786
787 generator.add_mapping(10, 0, Some("test_func".to_string()));
788 generator.new_line();
789 generator.add_mapping(11, 4, None);
790
791 assert_eq!(generator.source_map().mappings.len(), 2);
792 assert_eq!(generator.source_map().mappings[0].python_line, 10);
793 assert_eq!(generator.source_map().mappings[0].rust_line, 1);
794 assert_eq!(generator.source_map().mappings[1].rust_line, 2);
795 }
796
797 #[test]
798 fn test_debug_print_generation() {
799 let generator = DebugInfoGenerator::new(
800 PathBuf::from("test.py"),
801 PathBuf::from("test.rs"),
802 DebugLevel::Full,
803 );
804
805 let int_debug = generator.generate_debug_print("x", &Type::Int);
806 assert!(int_debug.contains("eprintln!"));
807 assert!(int_debug.contains("x = {}"));
808
809 let vec_debug = generator.generate_debug_print("items", &Type::List(Box::new(Type::Int)));
810 assert!(vec_debug.contains("{:?}"));
811 }
812
813 #[test]
814 fn test_debugger_scripts() {
815 let source_map = SourceMap {
816 source_file: PathBuf::from("test.py"),
817 target_file: PathBuf::from("test.rs"),
818 mappings: vec![],
819 function_map: vec![(
820 "test_func".to_string(),
821 FunctionMapping {
822 python_name: "test_func".to_string(),
823 rust_name: "test_func".to_string(),
824 python_start_line: 1,
825 python_end_line: 5,
826 rust_start_line: 10,
827 rust_end_line: 20,
828 },
829 )]
830 .into_iter()
831 .collect(),
832 };
833
834 let gdb_integration = DebuggerIntegration::new(DebuggerType::Gdb);
835 let gdb_script = gdb_integration.generate_init_script(&source_map);
836 assert!(gdb_script.contains("break test_func"));
837
838 let lldb_integration = DebuggerIntegration::new(DebuggerType::Lldb);
839 let lldb_script = lldb_integration.generate_init_script(&source_map);
840 assert!(lldb_script.contains("breakpoint set --name test_func"));
841 }
842}