1use serde::{Deserialize, Serialize};
7
8#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
10pub struct StackAllocationInfo {
11 pub frame_id: usize,
13 pub var_name: String,
15 pub stack_offset: isize,
17 pub size: usize,
19 pub function_name: String,
21 pub stack_depth: usize,
23 pub scope_info: StackScopeInfo,
25}
26
27#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
29pub struct StackScopeInfo {
30 pub scope_type: ScopeType,
32 pub start_line: Option<u32>,
34 pub end_line: Option<u32>,
36 pub parent_scope: Option<usize>,
38 pub nesting_level: usize,
40}
41
42#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
44pub enum ScopeType {
45 Function,
47 Block,
49 Loop,
51 Conditional,
53 Match,
55 Async,
57 Unsafe,
59}
60
61impl From<crate::core::types::StackAllocationInfo> for StackAllocationInfo {
63 fn from(old: crate::core::types::StackAllocationInfo) -> Self {
64 Self {
65 frame_id: old.frame_id,
66 var_name: old.var_name,
67 stack_offset: old.stack_offset,
68 size: old.size,
69 function_name: old.function_name,
70 stack_depth: old.stack_depth,
71 scope_info: StackScopeInfo {
72 scope_type: match old.scope_info.scope_type {
73 crate::core::types::ScopeType::Function => ScopeType::Function,
74 crate::core::types::ScopeType::Block => ScopeType::Block,
75 crate::core::types::ScopeType::Loop => ScopeType::Loop,
76 crate::core::types::ScopeType::Conditional => ScopeType::Conditional,
77 crate::core::types::ScopeType::Match => ScopeType::Match,
78 crate::core::types::ScopeType::Async => ScopeType::Async,
79 crate::core::types::ScopeType::Unsafe => ScopeType::Unsafe,
80 },
81 start_line: old.scope_info.start_line,
82 end_line: old.scope_info.end_line,
83 parent_scope: old.scope_info.parent_scope,
84 nesting_level: old.scope_info.nesting_level,
85 },
86 }
87 }
88}
89
90#[cfg(test)]
91mod tests {
92 use super::*;
93
94 #[test]
95 fn test_stack_allocation_info() {
96 let info = StackAllocationInfo {
97 frame_id: 1,
98 var_name: "local_var".to_string(),
99 stack_offset: -16,
100 size: 8,
101 function_name: "main".to_string(),
102 stack_depth: 2,
103 scope_info: StackScopeInfo {
104 scope_type: ScopeType::Function,
105 start_line: Some(10),
106 end_line: Some(20),
107 parent_scope: None,
108 nesting_level: 0,
109 },
110 };
111
112 assert_eq!(info.frame_id, 1);
113 assert_eq!(info.var_name, "local_var");
114 assert_eq!(info.stack_offset, -16);
115 }
116
117 #[test]
118 fn test_scope_type_variants() {
119 let types = vec![
120 ScopeType::Function,
121 ScopeType::Block,
122 ScopeType::Loop,
123 ScopeType::Conditional,
124 ScopeType::Match,
125 ScopeType::Async,
126 ScopeType::Unsafe,
127 ];
128
129 for scope_type in types {
130 assert!(!format!("{scope_type:?}").is_empty());
131 }
132 }
133
134 #[test]
135 fn test_stack_scope_info_creation() {
136 let scope = StackScopeInfo {
137 scope_type: ScopeType::Loop,
138 start_line: Some(5),
139 end_line: Some(15),
140 parent_scope: Some(1),
141 nesting_level: 2,
142 };
143
144 assert_eq!(scope.scope_type, ScopeType::Loop);
145 assert_eq!(scope.start_line, Some(5));
146 assert_eq!(scope.parent_scope, Some(1));
147 assert_eq!(scope.nesting_level, 2);
148 }
149
150 #[test]
151 fn test_stack_allocation_info_with_block_scope() {
152 let info = StackAllocationInfo {
153 frame_id: 2,
154 var_name: "block_var".to_string(),
155 stack_offset: -32,
156 size: 16,
157 function_name: "process".to_string(),
158 stack_depth: 3,
159 scope_info: StackScopeInfo {
160 scope_type: ScopeType::Block,
161 start_line: Some(25),
162 end_line: Some(35),
163 parent_scope: Some(0),
164 nesting_level: 1,
165 },
166 };
167
168 assert_eq!(info.scope_info.scope_type, ScopeType::Block);
169 assert_eq!(info.size, 16);
170 }
171
172 #[test]
173 fn test_stack_allocation_info_with_match_scope() {
174 let info = StackAllocationInfo {
175 frame_id: 3,
176 var_name: "match_var".to_string(),
177 stack_offset: -8,
178 size: 4,
179 function_name: "handle".to_string(),
180 stack_depth: 1,
181 scope_info: StackScopeInfo {
182 scope_type: ScopeType::Match,
183 start_line: Some(100),
184 end_line: Some(120),
185 parent_scope: None,
186 nesting_level: 0,
187 },
188 };
189
190 assert_eq!(info.scope_info.scope_type, ScopeType::Match);
191 assert_eq!(info.stack_depth, 1);
192 }
193
194 #[test]
195 fn test_stack_allocation_info_with_async_scope() {
196 let info = StackAllocationInfo {
197 frame_id: 4,
198 var_name: "async_var".to_string(),
199 stack_offset: -64,
200 size: 32,
201 function_name: "async_fn".to_string(),
202 stack_depth: 5,
203 scope_info: StackScopeInfo {
204 scope_type: ScopeType::Async,
205 start_line: Some(1),
206 end_line: Some(50),
207 parent_scope: None,
208 nesting_level: 0,
209 },
210 };
211
212 assert_eq!(info.scope_info.scope_type, ScopeType::Async);
213 assert_eq!(info.function_name, "async_fn");
214 }
215
216 #[test]
217 fn test_stack_allocation_info_with_unsafe_scope() {
218 let info = StackAllocationInfo {
219 frame_id: 5,
220 var_name: "unsafe_var".to_string(),
221 stack_offset: -128,
222 size: 64,
223 function_name: "unsafe_fn".to_string(),
224 stack_depth: 2,
225 scope_info: StackScopeInfo {
226 scope_type: ScopeType::Unsafe,
227 start_line: Some(10),
228 end_line: Some(20),
229 parent_scope: Some(1),
230 nesting_level: 1,
231 },
232 };
233
234 assert_eq!(info.scope_info.scope_type, ScopeType::Unsafe);
235 }
236
237 #[test]
238 fn test_stack_allocation_info_with_conditional_scope() {
239 let info = StackAllocationInfo {
240 frame_id: 6,
241 var_name: "cond_var".to_string(),
242 stack_offset: -24,
243 size: 8,
244 function_name: "check".to_string(),
245 stack_depth: 2,
246 scope_info: StackScopeInfo {
247 scope_type: ScopeType::Conditional,
248 start_line: Some(30),
249 end_line: Some(40),
250 parent_scope: None,
251 nesting_level: 0,
252 },
253 };
254
255 assert_eq!(info.scope_info.scope_type, ScopeType::Conditional);
256 }
257
258 #[test]
259 fn test_stack_scope_info_no_lines() {
260 let scope = StackScopeInfo {
261 scope_type: ScopeType::Function,
262 start_line: None,
263 end_line: None,
264 parent_scope: None,
265 nesting_level: 0,
266 };
267
268 assert!(scope.start_line.is_none());
269 assert!(scope.end_line.is_none());
270 }
271
272 #[test]
273 fn test_stack_allocation_info_serialization() {
274 let info = StackAllocationInfo {
275 frame_id: 10,
276 var_name: "serialized_var".to_string(),
277 stack_offset: -48,
278 size: 24,
279 function_name: "test_serialization".to_string(),
280 stack_depth: 4,
281 scope_info: StackScopeInfo {
282 scope_type: ScopeType::Function,
283 start_line: Some(1),
284 end_line: Some(10),
285 parent_scope: None,
286 nesting_level: 0,
287 },
288 };
289
290 let json = serde_json::to_string(&info).unwrap();
291 let deserialized: StackAllocationInfo = serde_json::from_str(&json).unwrap();
292 assert_eq!(deserialized.frame_id, info.frame_id);
293 assert_eq!(deserialized.var_name, info.var_name);
294 }
295
296 #[test]
297 fn test_stack_scope_info_serialization() {
298 let scope = StackScopeInfo {
299 scope_type: ScopeType::Loop,
300 start_line: Some(5),
301 end_line: Some(15),
302 parent_scope: Some(1),
303 nesting_level: 2,
304 };
305
306 let json = serde_json::to_string(&scope).unwrap();
307 let deserialized: StackScopeInfo = serde_json::from_str(&json).unwrap();
308 assert_eq!(deserialized.scope_type, scope.scope_type);
309 assert_eq!(deserialized.nesting_level, scope.nesting_level);
310 }
311
312 #[test]
313 fn test_scope_type_serialization() {
314 let types = vec![
315 ScopeType::Function,
316 ScopeType::Block,
317 ScopeType::Loop,
318 ScopeType::Conditional,
319 ScopeType::Match,
320 ScopeType::Async,
321 ScopeType::Unsafe,
322 ];
323
324 for scope_type in types {
325 let json = serde_json::to_string(&scope_type).unwrap();
326 let deserialized: ScopeType = serde_json::from_str(&json).unwrap();
327 assert_eq!(deserialized, scope_type);
328 }
329 }
330
331 #[test]
332 fn test_stack_allocation_info_clone() {
333 let info = StackAllocationInfo {
334 frame_id: 1,
335 var_name: "clone_test".to_string(),
336 stack_offset: -16,
337 size: 8,
338 function_name: "test".to_string(),
339 stack_depth: 1,
340 scope_info: StackScopeInfo {
341 scope_type: ScopeType::Function,
342 start_line: None,
343 end_line: None,
344 parent_scope: None,
345 nesting_level: 0,
346 },
347 };
348
349 let cloned = info.clone();
350 assert_eq!(cloned.frame_id, info.frame_id);
351 assert_eq!(cloned.var_name, info.var_name);
352 }
353
354 #[test]
355 fn test_stack_scope_info_clone() {
356 let scope = StackScopeInfo {
357 scope_type: ScopeType::Block,
358 start_line: Some(10),
359 end_line: Some(20),
360 parent_scope: Some(5),
361 nesting_level: 3,
362 };
363
364 let cloned = scope.clone();
365 assert_eq!(cloned.scope_type, scope.scope_type);
366 assert_eq!(cloned.nesting_level, scope.nesting_level);
367 }
368
369 #[test]
370 fn test_stack_allocation_info_debug() {
371 let info = StackAllocationInfo {
372 frame_id: 1,
373 var_name: "debug_test".to_string(),
374 stack_offset: -16,
375 size: 8,
376 function_name: "test".to_string(),
377 stack_depth: 1,
378 scope_info: StackScopeInfo {
379 scope_type: ScopeType::Function,
380 start_line: None,
381 end_line: None,
382 parent_scope: None,
383 nesting_level: 0,
384 },
385 };
386
387 let debug_str = format!("{:?}", info);
388 assert!(debug_str.contains("StackAllocationInfo"));
389 assert!(debug_str.contains("frame_id"));
390 }
391
392 #[test]
393 fn test_stack_scope_info_debug() {
394 let scope = StackScopeInfo {
395 scope_type: ScopeType::Loop,
396 start_line: Some(1),
397 end_line: Some(10),
398 parent_scope: None,
399 nesting_level: 0,
400 };
401
402 let debug_str = format!("{:?}", scope);
403 assert!(debug_str.contains("StackScopeInfo"));
404 assert!(debug_str.contains("scope_type"));
405 }
406
407 #[test]
408 fn test_stack_allocation_info_equality() {
409 let info1 = StackAllocationInfo {
410 frame_id: 1,
411 var_name: "test".to_string(),
412 stack_offset: -16,
413 size: 8,
414 function_name: "fn".to_string(),
415 stack_depth: 1,
416 scope_info: StackScopeInfo {
417 scope_type: ScopeType::Function,
418 start_line: None,
419 end_line: None,
420 parent_scope: None,
421 nesting_level: 0,
422 },
423 };
424
425 let info2 = StackAllocationInfo {
426 frame_id: 1,
427 var_name: "test".to_string(),
428 stack_offset: -16,
429 size: 8,
430 function_name: "fn".to_string(),
431 stack_depth: 1,
432 scope_info: StackScopeInfo {
433 scope_type: ScopeType::Function,
434 start_line: None,
435 end_line: None,
436 parent_scope: None,
437 nesting_level: 0,
438 },
439 };
440
441 assert_eq!(info1, info2);
442 }
443
444 #[test]
445 fn test_stack_scope_info_equality() {
446 let scope1 = StackScopeInfo {
447 scope_type: ScopeType::Function,
448 start_line: Some(1),
449 end_line: Some(10),
450 parent_scope: None,
451 nesting_level: 0,
452 };
453
454 let scope2 = StackScopeInfo {
455 scope_type: ScopeType::Function,
456 start_line: Some(1),
457 end_line: Some(10),
458 parent_scope: None,
459 nesting_level: 0,
460 };
461
462 assert_eq!(scope1, scope2);
463 }
464
465 #[test]
466 fn test_boundary_values_stack_allocation() {
467 let info = StackAllocationInfo {
468 frame_id: usize::MAX,
469 var_name: String::new(),
470 stack_offset: isize::MIN,
471 size: usize::MAX,
472 function_name: String::new(),
473 stack_depth: usize::MAX,
474 scope_info: StackScopeInfo {
475 scope_type: ScopeType::Function,
476 start_line: Some(u32::MAX),
477 end_line: Some(u32::MAX),
478 parent_scope: Some(usize::MAX),
479 nesting_level: usize::MAX,
480 },
481 };
482
483 assert_eq!(info.frame_id, usize::MAX);
484 assert_eq!(info.stack_offset, isize::MIN);
485 assert_eq!(info.size, usize::MAX);
486 }
487
488 #[test]
489 fn test_negative_stack_offset() {
490 let info = StackAllocationInfo {
491 frame_id: 1,
492 var_name: "negative_offset".to_string(),
493 stack_offset: -1024,
494 size: 64,
495 function_name: "test".to_string(),
496 stack_depth: 1,
497 scope_info: StackScopeInfo {
498 scope_type: ScopeType::Function,
499 start_line: None,
500 end_line: None,
501 parent_scope: None,
502 nesting_level: 0,
503 },
504 };
505
506 assert_eq!(info.stack_offset, -1024);
507 }
508
509 #[test]
510 fn test_positive_stack_offset() {
511 let info = StackAllocationInfo {
512 frame_id: 1,
513 var_name: "positive_offset".to_string(),
514 stack_offset: 256,
515 size: 32,
516 function_name: "test".to_string(),
517 stack_depth: 1,
518 scope_info: StackScopeInfo {
519 scope_type: ScopeType::Function,
520 start_line: None,
521 end_line: None,
522 parent_scope: None,
523 nesting_level: 0,
524 },
525 };
526
527 assert_eq!(info.stack_offset, 256);
528 }
529
530 #[test]
531 fn test_deep_nesting_level() {
532 let scope = StackScopeInfo {
533 scope_type: ScopeType::Block,
534 start_line: Some(1),
535 end_line: Some(10),
536 parent_scope: Some(99),
537 nesting_level: 100,
538 };
539
540 assert_eq!(scope.nesting_level, 100);
541 }
542}