boxmux 0.240.3373

YAML-driven terminal UI framework for rich, interactive CLI applications and dashboards with PTY support
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
//! Edge case tests for BoxMux
//!
//! These tests cover error conditions, boundary cases, and unusual scenarios
//! that might not be covered by regular unit tests.

#[cfg(test)]
mod tests {
    use crate::model::app::App;
    use crate::model::common::{InputBounds, SocketFunction};
    use crate::model::layout::Layout;
    use crate::model::muxbox::MuxBox;
    use crate::tests::test_utils::*;
    use crate::thread_manager::Message;
    use crate::utils::*;
    use std::collections::HashMap;

    /// Test empty and null configurations
    #[test]
    fn test_empty_configurations() {
        // Test app with no layouts
        let mut empty_app = App::new();
        empty_app.layouts = vec![];
        empty_app.libs = None;
        empty_app.on_keypress = None;

        // This should handle empty layouts gracefully
        let _graph = empty_app.generate_graph();
        // Just verify it doesn't panic

        // Test layout with no muxboxes
        let empty_layout = Layout {
            id: "empty".to_string(),
            title: None,
            children: None, // No muxboxes
            root: Some(true),
            ..Default::default()
        };

        // Should handle empty muxbox list
        assert!(
            empty_layout.children.is_none() || empty_layout.children.as_ref().unwrap().is_empty()
        );
    }

    /// Test extremely large inputs
    #[test]
    fn test_large_inputs() {
        // Test very long muxbox content
        let huge_content = "x".repeat(1_000_000); // 1MB of content
        let mut muxbox = TestDataFactory::create_test_muxbox("huge_muxbox");
        muxbox.content = Some(huge_content.clone());

        assert_eq!(muxbox.content.as_ref().unwrap().len(), 1_000_000);

        // Test very long script arrays
        let huge_script: Vec<String> = (0..10000)
            .map(|i| format!("echo 'command number {}'", i))
            .collect();

        muxbox.script = Some(huge_script.clone());
        assert_eq!(muxbox.script.as_ref().unwrap().len(), 10000);
    }

    /// Test invalid bounds configurations
    #[test]
    fn test_invalid_bounds() {
        let parent_bounds = TestDataFactory::create_bounds(0, 0, 100, 50);

        // Test bounds with invalid percentages
        let invalid_bounds = InputBounds {
            x1: "150%".to_string(), // Over 100%
            y1: "-10%".to_string(), // Negative
            x2: "abc%".to_string(), // Non-numeric
            y2: "50%".to_string(),
        };

        // Should handle invalid bounds gracefully
        let result = input_bounds_to_bounds(&invalid_bounds, &parent_bounds);
        // The actual behavior depends on implementation, but shouldn't crash
        assert!(result.x1 <= parent_bounds.x2);
        assert!(result.y1 <= parent_bounds.y2);

        // Test bounds where x1 > x2, y1 > y2
        let backwards_bounds = InputBounds {
            x1: "90".to_string(),
            y1: "40".to_string(),
            x2: "10".to_string(), // Less than x1
            y2: "5".to_string(),  // Less than y1
        };

        let _result = input_bounds_to_bounds(&backwards_bounds, &parent_bounds);
        // Should handle gracefully without crashing
    }

    /// Test malformed input strings
    #[test]
    fn test_malformed_inputs() {
        // Test ANSI stripping with malformed escape sequences
        let malformed_ansi = vec![
            "\x1b[",                            // Incomplete escape
            "\x1b[999m",                        // Invalid code
            "\x1b[31",                          // Missing 'm'
            "\x1b[31;",                         // Incomplete parameter
            "normal\x1b[31mred\x1b[incomplete", // Mixed valid/invalid
        ];

        for input in malformed_ansi {
            let result = strip_ansi_codes(input);
            // Should not crash and should return a string (possibly empty)
            // The main goal is that it doesn't panic on malformed input
            assert!(result.len() <= input.len()); // Result should not be longer than input
        }

        // Test key mapping with unusual key strings
        let key_mappings = MockUtils::create_test_key_mappings();
        let unusual_keys = vec![
            "",           // Empty string
            "   ",        // Whitespace only
            "CTRL++",     // Double symbols
            "ctrl+",      // Incomplete
            "Ctrl + + C", // Extra spaces and symbols
            "ĀĂĄ",        // Unicode
            "😀",         // Emoji
        ];

        for key in unusual_keys {
            let result = handle_keypress(key, &key_mappings);
            // Should handle gracefully, typically returning None
            // The exact behavior depends on implementation
        }
    }

    /// Test script execution edge cases
    #[test]
    fn test_script_edge_cases() {
        // Test empty script
        let result = run_script(None, &vec![]);
        // Behavior depends on implementation, but shouldn't crash

        // Test script with empty commands
        let empty_commands = vec!["".to_string(), "   ".to_string()];
        let result = run_script(None, &empty_commands);
        // Should handle gracefully

        // Test script with very long command
        let long_command = "echo ".to_string() + &"x".repeat(100000);
        let result = run_script(None, &vec![long_command]);
        // Should either succeed or fail gracefully

        // Test script with special characters
        let special_commands = vec![
            "echo '$(dangerous command)'".to_string(),
            "echo '&& rm -rf /'".to_string(),
            "echo '|'".to_string(),
            "echo ';'".to_string(),
        ];

        for cmd in special_commands {
            let result = run_script(None, &vec![cmd.clone()]);
            // Should execute safely or fail gracefully
            match result {
                Ok(_) => {}  // Fine if it executes
                Err(_) => {} // Fine if it fails safely
            }
        }
    }

    /// Test concurrent access patterns
    #[test]
    fn test_concurrent_patterns() {
        use std::sync::{Arc, Mutex};
        use std::thread;

        let app = Arc::new(Mutex::new(TestDataFactory::create_test_app()));
        let mut handles = vec![];

        // Simulate multiple threads accessing app simultaneously
        for i in 0..10 {
            let app_clone: Arc<std::sync::Mutex<App>> = Arc::clone(&app);
            let handle = thread::spawn(move || {
                let _app_guard = app_clone.lock().unwrap();
                // Simulate some work with the app
                let _muxbox = TestDataFactory::create_test_muxbox(&format!("thread_muxbox_{}", i));
                thread::sleep(std::time::Duration::from_millis(1));
            });
            handles.push(handle);
        }

        // Wait for all threads to complete
        for handle in handles {
            handle.join().unwrap();
        }

        // App should still be in valid state
        let final_app = app.lock().unwrap();
        assert!(!final_app.layouts.is_empty());
    }

    /// Test memory pressure scenarios
    #[test]
    fn test_memory_pressure() {
        // Create many objects quickly to test memory handling
        let mut objects = Vec::new();

        for i in 0..1000 {
            let app = TestDataFactory::create_multi_layout_app();
            let large_layout = PerformanceTestUtils::create_large_layout(100);

            objects.push((app, large_layout));

            // Periodically clear some objects to test cleanup
            if i % 100 == 0 {
                objects.clear();
            }
        }

        // Final cleanup
        objects.clear();

        // Should complete without memory issues
    }

    /// Test validation edge cases
    #[test]
    fn test_validation_edge_cases() {
        // Test muxbox with extremely long ID
        let mut muxbox = TestDataFactory::create_test_muxbox("normal_id");
        muxbox.id = "x".repeat(10000);

        // Should handle long IDs (behavior depends on implementation)
        assert_eq!(muxbox.id.len(), 10000);

        // Test layout with circular references (if possible)
        let mut layout = TestDataFactory::create_test_layout("circular", None);
        // This would create circular reference if the structure allowed it
        // layout.parent = Some(&layout); // Not possible with current structure

        // Test app with many duplicate layout IDs
        let mut problematic_app = App::new();
        problematic_app.layouts = vec![
            TestDataFactory::create_test_layout("same_id", None),
            TestDataFactory::create_test_layout("same_id", None),
            TestDataFactory::create_test_layout("same_id", None),
        ];
        problematic_app.libs = None;
        problematic_app.on_keypress = None;

        // Should handle duplicate IDs appropriately
        let graph = problematic_app.generate_graph();
        // Behavior depends on implementation
    }

    /// Test socket function edge cases
    #[test]
    fn test_socket_function_edge_cases() {
        // Test with empty muxbox ID
        let empty_id_function = SocketFunction::ReplaceBoxContent {
            box_id: "".to_string(),
            success: true,
            content: "content".to_string(),
        };

        let result = IntegrationTestUtils::simulate_socket_to_app_workflow(empty_id_function);
        assert!(result.is_ok()); // Should handle gracefully

        // Test with extremely long content
        let huge_content = "x".repeat(1_000_000);
        let huge_content_function = SocketFunction::ReplaceBoxContent {
            box_id: "test".to_string(),
            success: true,
            content: huge_content,
        };

        let result = IntegrationTestUtils::simulate_socket_to_app_workflow(huge_content_function);
        assert!(result.is_ok());

        // Test with special characters in content
        let special_content = "Special chars: ñáéíóú 中文 🚀 \n\r\t\\\"'";
        let special_function = SocketFunction::ReplaceBoxContent {
            box_id: "special".to_string(),
            success: true,
            content: special_content.to_string(),
        };

        let result = IntegrationTestUtils::simulate_socket_to_app_workflow(special_function);
        assert!(result.is_ok());

        if let Ok(Message::StreamUpdateMessage(stream_update)) = result {
            let content = stream_update.content_update;
            assert_eq!(content, special_content);
        }
    }

    /// Test boundary value scenarios
    #[test]
    fn test_boundary_values() {
        // Test with zero-sized bounds
        let zero_bounds = TestDataFactory::create_bounds(10, 10, 10, 10);
        let input_bounds = TestDataFactory::create_input_bounds("0", "0", "0", "0");
        let result = input_bounds_to_bounds(&input_bounds, &zero_bounds);

        // Should handle zero-sized areas gracefully
        assert!(result.x1 <= result.x2);
        assert!(result.y1 <= result.y2);

        // Test with maximum usize values
        let max_bounds = TestDataFactory::create_bounds(0, 0, usize::MAX, usize::MAX);
        let max_input = TestDataFactory::create_input_bounds("100%", "100%", "100%", "100%");
        let result = input_bounds_to_bounds(&max_input, &max_bounds);

        // Should handle large values without overflow
        assert!(result.x2 >= result.x1);
        assert!(result.y2 >= result.y1);
    }

    /// Test error propagation
    #[test]
    fn test_error_propagation() {
        // Test what happens when script execution fails
        let failing_script = vec!["false".to_string()]; // Command that returns error code
        let result = run_script(None, &failing_script);

        // Should either succeed (if implementation ignores exit codes) or fail gracefully
        match result {
            Ok(_) => {} // Implementation might ignore exit codes
            Err(e) => {
                // Should be a reasonable error message
                let error_msg = format!("{}", e);
                assert!(!error_msg.is_empty());
            }
        }

        // Test with non-existent command
        let nonexistent_script = vec!["this_command_definitely_does_not_exist_12345".to_string()];
        let result = run_script(None, &nonexistent_script);

        // Should fail gracefully
        assert!(result.is_err());
    }

    /// Test unicode and internationalization
    #[test]
    fn test_unicode_handling() {
        // Test unicode in muxbox content
        let unicode_content = "Hello: 你好 مرحبا こんにちは 🌍 🚀 ñáéíóú";
        let mut muxbox = TestDataFactory::create_test_muxbox("unicode_muxbox");
        muxbox.content = Some(unicode_content.to_string());

        assert_eq!(muxbox.content.as_ref().unwrap(), unicode_content);

        // Test unicode in ANSI stripping
        let unicode_ansi = format!("\x1b[31m{}\x1b[0m", unicode_content);
        let stripped = strip_ansi_codes(&unicode_ansi);
        assert_eq!(stripped, unicode_content);

        // Test unicode in key mappings
        let mut unicode_mappings = HashMap::new();
        unicode_mappings.insert("Ctrl + ñ".to_string(), vec!["special_action".to_string()]);

        let result = handle_keypress("ctrl+ñ", &unicode_mappings);
        // Behavior depends on key normalization implementation
    }

    /// Test resource exhaustion scenarios
    #[test]
    fn test_resource_exhaustion() {
        // Test creating maximum reasonable number of muxboxes
        let large_muxbox_count = 10000;
        let start_time = std::time::Instant::now();

        let large_muxboxes = PerformanceTestUtils::create_large_muxbox_list(large_muxbox_count);

        let creation_time = start_time.elapsed();
        println!(
            "Created {} muxboxes in {:?}",
            large_muxbox_count, creation_time
        );

        assert_eq!(large_muxboxes.len(), large_muxbox_count);

        // Should complete in reasonable time (less than 5 seconds)
        assert!(
            creation_time.as_secs() < 5,
            "Creating {} muxboxes took too long: {:?}",
            large_muxbox_count,
            creation_time
        );

        // Test memory usage stays reasonable
        let muxbox_size = std::mem::size_of::<MuxBox>();
        let expected_memory = large_muxbox_count * muxbox_size;
        println!(
            "Estimated memory usage: {} bytes ({} MB)",
            expected_memory,
            expected_memory / 1_000_000
        );

        // Memory usage should be reasonable (less than 100MB for 10k muxboxes)
        assert!(
            expected_memory < 100_000_000,
            "Memory usage too high: {} bytes",
            expected_memory
        );
    }
}