⚠️ VeridianOS Kernel Documentation - This is low-level kernel code. All functions are unsafe unless explicitly marked otherwise. no_std

veridian_kernel/
userland.rs

1//! Userland Module
2//!
3//! Re-exports userland test programs and infrastructure for kernel integration.
4
5#![allow(clippy::type_complexity)]
6
7#[cfg(feature = "alloc")]
8extern crate alloc;
9
10// Re-export userland functionality for kernel integration
11pub use crate::userspace::*;
12
13// Import userland test infrastructure from root
14pub mod test_programs {
15    //! Test programs for user-space validation
16
17    #[cfg(feature = "alloc")]
18    extern crate alloc;
19
20    /// Hello world test program
21    pub mod hello_world {
22        use alloc::string::String;
23
24        pub fn run() -> Result<(), String> {
25            crate::println!("Hello, World from VeridianOS!");
26            Ok(())
27        }
28    }
29
30    /// Process management test - verifies process server has processes
31    pub mod process_test {
32        use alloc::string::String;
33
34        pub fn run() -> Result<(), String> {
35            crate::println!("Process test: checking process server...");
36            let ps = crate::services::process_server::get_process_server();
37            let processes = ps.list_processes();
38            if processes.is_empty() {
39                return Err(String::from("Process server has no processes"));
40            }
41            crate::println!("  Found {} processes", processes.len());
42            Ok(())
43        }
44    }
45
46    /// Thread management test - verifies thread manager responds
47    pub mod thread_test {
48        use alloc::string::String;
49
50        pub fn run() -> Result<(), String> {
51            crate::println!("Thread test: checking thread manager...");
52            let tm = crate::thread_api::get_thread_manager();
53            if tm.get_current_thread_id().is_some() {
54                crate::println!("  Thread manager responding");
55                Ok(())
56            } else {
57                Err(String::from("Thread manager not responding"))
58            }
59        }
60    }
61
62    /// Filesystem test - exercises VFS write/read/mkdir/readdir
63    pub mod filesystem_test {
64        use alloc::string::String;
65
66        pub fn run() -> Result<(), String> {
67            crate::println!("Filesystem test: exercising VFS...");
68
69            // Write a file
70            crate::fs::write_file("/tmp/fs_test.txt", b"VFS works")
71                .map_err(|e| alloc::format!("{}", e))?;
72
73            // Read it back
74            let data =
75                crate::fs::read_file("/tmp/fs_test.txt").map_err(|e| alloc::format!("{}", e))?;
76            if data != b"VFS works" {
77                return Err(String::from("Read data mismatch"));
78            }
79            crate::println!("  Write/read verified");
80
81            // List /tmp
82            let vfs = crate::fs::get_vfs().read();
83            let node = vfs
84                .resolve_path("/tmp")
85                .map_err(|e| alloc::format!("{}", e))?;
86            let entries = node.readdir().map_err(|e| alloc::format!("{}", e))?;
87            let found = entries.iter().any(|e| e.name == "fs_test.txt");
88            if !found {
89                return Err(String::from("File not found in directory listing"));
90            }
91            crate::println!("  Directory listing verified");
92
93            Ok(())
94        }
95    }
96
97    /// Network test - checks if network subsystem is reachable
98    pub mod network_test {
99        use alloc::string::String;
100
101        pub fn run() -> Result<(), String> {
102            crate::println!("Network test: checking network subsystem...");
103            let _initialized = crate::drivers::network::is_network_initialized();
104            crate::println!("  Network subsystem checked (non-critical)");
105            Ok(())
106        }
107    }
108
109    /// Driver test - verifies driver framework has registered drivers
110    pub mod driver_test {
111        use alloc::string::String;
112
113        pub fn run() -> Result<(), String> {
114            crate::println!("Driver test: checking driver framework...");
115            let df = crate::services::driver_framework::get_driver_framework();
116            let stats = df.get_statistics();
117            crate::println!(
118                "  Drivers: {}, Buses: {}",
119                stats.total_drivers,
120                stats.total_buses
121            );
122            if stats.total_drivers == 0 && stats.total_buses == 0 {
123                return Err(String::from("No drivers or buses registered"));
124            }
125            Ok(())
126        }
127    }
128
129    /// Shell test - runs built-in commands programmatically
130    pub mod shell_test {
131        use alloc::string::String;
132
133        pub fn run() -> Result<(), String> {
134            crate::println!("Shell test: executing built-in commands...");
135            let shell = crate::services::shell::get_shell();
136
137            // Test pwd
138            if !matches!(
139                shell.execute_command("pwd"),
140                crate::services::shell::CommandResult::Success(_)
141            ) {
142                return Err(String::from("pwd command failed"));
143            }
144            crate::println!("  pwd: ok");
145
146            // Test env
147            if !matches!(
148                shell.execute_command("env"),
149                crate::services::shell::CommandResult::Success(_)
150            ) {
151                return Err(String::from("env command failed"));
152            }
153            crate::println!("  env: ok");
154
155            // Test nonexistent command returns NotFound
156            if !matches!(
157                shell.execute_command("nonexistent_cmd_xyz"),
158                crate::services::shell::CommandResult::NotFound
159            ) {
160                return Err(String::from("Expected NotFound for unknown command"));
161            }
162            crate::println!("  not-found detection: ok");
163
164            Ok(())
165        }
166    }
167
168    /// Standard library test
169    pub mod stdlib_test {
170        use alloc::string::String;
171
172        pub fn run() -> Result<(), String> {
173            crate::println!("Standard library test: basic validation...");
174            // Verify alloc works (String, Vec)
175            let s = String::from("hello");
176            let v: alloc::vec::Vec<u32> = alloc::vec![1, 2, 3];
177            if s.len() != 5 || v.len() != 3 {
178                return Err(String::from("Basic alloc types broken"));
179            }
180            crate::println!("  alloc types: ok");
181            Ok(())
182        }
183    }
184}
185
186pub mod test_runner {
187    //! Test runner for user-space programs
188
189    #[cfg(feature = "alloc")]
190    extern crate alloc;
191
192    use alloc::{format, string::String, vec::Vec};
193
194    /// Test suite summary
195    #[derive(Debug, Clone)]
196    pub struct TestSuiteSummary {
197        pub total_tests: usize,
198        pub passed: usize,
199        pub failed: usize,
200        pub errors: Vec<String>,
201    }
202
203    impl Default for TestSuiteSummary {
204        fn default() -> Self {
205            Self::new()
206        }
207    }
208
209    impl TestSuiteSummary {
210        pub fn new() -> Self {
211            Self {
212                total_tests: 0,
213                passed: 0,
214                failed: 0,
215                errors: Vec::new(),
216            }
217        }
218
219        pub fn success_rate(&self) -> f32 {
220            if self.total_tests == 0 {
221                100.0
222            } else {
223                (self.passed as f32 / self.total_tests as f32) * 100.0
224            }
225        }
226    }
227
228    /// Run Phase 2 validation
229    pub fn run_phase2_validation() -> TestSuiteSummary {
230        let mut summary = TestSuiteSummary::new();
231
232        crate::println!("🚀 Running Phase 2 Validation Tests...");
233
234        // Run all test programs
235        let tests: [(&str, fn() -> Result<(), String>); 8] = [
236            ("Hello World", super::test_programs::hello_world::run),
237            ("Process Test", super::test_programs::process_test::run),
238            ("Thread Test", super::test_programs::thread_test::run),
239            (
240                "Filesystem Test",
241                super::test_programs::filesystem_test::run,
242            ),
243            ("Network Test", super::test_programs::network_test::run),
244            ("Driver Test", super::test_programs::driver_test::run),
245            ("Shell Test", super::test_programs::shell_test::run),
246            ("Stdlib Test", super::test_programs::stdlib_test::run),
247        ];
248
249        for (name, test_fn) in &tests {
250            summary.total_tests += 1;
251            match test_fn() {
252                Ok(()) => {
253                    crate::println!("✅ {} - PASSED", name);
254                    summary.passed += 1;
255                }
256                Err(e) => {
257                    crate::println!("❌ {} - FAILED: {}", name, e);
258                    summary.failed += 1;
259                    summary.errors.push(format!("{}: {}", name, e));
260                }
261            }
262        }
263
264        crate::println!("");
265        crate::println!(
266            "📊 Test Results: {}/{} passed ({:.1}%)",
267            summary.passed,
268            summary.total_tests,
269            summary.success_rate()
270        );
271
272        summary
273    }
274
275    /// Run critical tests
276    pub fn run_critical_tests() -> TestSuiteSummary {
277        let mut summary = TestSuiteSummary::new();
278
279        crate::println!("🔥 Running Critical Tests...");
280
281        // Critical tests
282        let tests: [(&str, fn() -> Result<(), String>); 3] = [
283            ("Process Test", super::test_programs::process_test::run),
284            (
285                "Filesystem Test",
286                super::test_programs::filesystem_test::run,
287            ),
288            ("Driver Test", super::test_programs::driver_test::run),
289        ];
290
291        for (name, test_fn) in &tests {
292            summary.total_tests += 1;
293            match test_fn() {
294                Ok(()) => {
295                    crate::println!("✅ {} - PASSED", name);
296                    summary.passed += 1;
297                }
298                Err(e) => {
299                    crate::println!("❌ {} - FAILED: {}", name, e);
300                    summary.failed += 1;
301                    summary.errors.push(format!("{}: {}", name, e));
302                }
303            }
304        }
305
306        summary
307    }
308
309    /// Run specific tests
310    pub fn run_specific_tests(test_names: &[&str]) -> TestSuiteSummary {
311        let mut summary = TestSuiteSummary::new();
312
313        crate::println!("🎯 Running Specific Tests...");
314
315        for name in test_names {
316            summary.total_tests += 1;
317            let result = match *name {
318                "hello_world" => super::test_programs::hello_world::run(),
319                "process" => super::test_programs::process_test::run(),
320                "thread" => super::test_programs::thread_test::run(),
321                "filesystem" => super::test_programs::filesystem_test::run(),
322                "network" => super::test_programs::network_test::run(),
323                "driver" => super::test_programs::driver_test::run(),
324                "shell" => super::test_programs::shell_test::run(),
325                "stdlib" => super::test_programs::stdlib_test::run(),
326                _ => Err(format!("Unknown test: {}", name)),
327            };
328
329            match result {
330                Ok(()) => {
331                    crate::println!("✅ {} - PASSED", name);
332                    summary.passed += 1;
333                }
334                Err(e) => {
335                    crate::println!("❌ {} - FAILED: {}", name, e);
336                    summary.failed += 1;
337                    summary.errors.push(format!("{}: {}", name, e));
338                }
339            }
340        }
341
342        summary
343    }
344
345    /// Interactive test menu (placeholder for kernel context)
346    pub fn interactive_test_menu() -> TestSuiteSummary {
347        crate::println!("📋 Interactive test menu not available in kernel context");
348        crate::println!("Running full Phase 2 validation instead...");
349        run_phase2_validation()
350    }
351
352    #[cfg(test)]
353    mod tests {
354        use super::*;
355
356        #[test]
357        fn test_suite_summary_new() {
358            let s = TestSuiteSummary::new();
359            assert_eq!(s.total_tests, 0);
360            assert_eq!(s.passed, 0);
361            assert_eq!(s.failed, 0);
362            assert!(s.errors.is_empty());
363        }
364
365        #[test]
366        fn test_suite_summary_default() {
367            let s = TestSuiteSummary::default();
368            assert_eq!(s.total_tests, 0);
369            assert_eq!(s.passed, 0);
370            assert_eq!(s.failed, 0);
371            assert!(s.errors.is_empty());
372        }
373
374        #[test]
375        fn test_suite_summary_new_equals_default() {
376            let a = TestSuiteSummary::new();
377            let b = TestSuiteSummary::default();
378            assert_eq!(a.total_tests, b.total_tests);
379            assert_eq!(a.passed, b.passed);
380            assert_eq!(a.failed, b.failed);
381            assert_eq!(a.errors.len(), b.errors.len());
382        }
383
384        #[test]
385        fn test_success_rate_empty() {
386            let s = TestSuiteSummary::new();
387            // Zero tests should report 100% success
388            assert_eq!(s.success_rate(), 100.0);
389        }
390
391        #[test]
392        fn test_success_rate_all_passed() {
393            let mut s = TestSuiteSummary::new();
394            s.total_tests = 10;
395            s.passed = 10;
396            s.failed = 0;
397            assert_eq!(s.success_rate(), 100.0);
398        }
399
400        #[test]
401        fn test_success_rate_none_passed() {
402            let mut s = TestSuiteSummary::new();
403            s.total_tests = 5;
404            s.passed = 0;
405            s.failed = 5;
406            assert_eq!(s.success_rate(), 0.0);
407        }
408
409        #[test]
410        fn test_success_rate_half_passed() {
411            let mut s = TestSuiteSummary::new();
412            s.total_tests = 4;
413            s.passed = 2;
414            s.failed = 2;
415            assert_eq!(s.success_rate(), 50.0);
416        }
417
418        #[test]
419        fn test_suite_summary_clone() {
420            let mut s = TestSuiteSummary::new();
421            s.total_tests = 3;
422            s.passed = 2;
423            s.failed = 1;
424            s.errors.push(String::from("test failure"));
425            let cloned = s.clone();
426            assert_eq!(cloned.total_tests, 3);
427            assert_eq!(cloned.passed, 2);
428            assert_eq!(cloned.failed, 1);
429            assert_eq!(cloned.errors.len(), 1);
430            assert_eq!(cloned.errors[0], "test failure");
431        }
432
433        #[test]
434        fn test_suite_summary_errors_accumulate() {
435            let mut s = TestSuiteSummary::new();
436            assert!(s.errors.is_empty());
437            s.errors.push(String::from("error 1"));
438            s.errors.push(String::from("error 2"));
439            assert_eq!(s.errors.len(), 2);
440        }
441
442        #[test]
443        fn test_suite_summary_debug_impl() {
444            let s = TestSuiteSummary::new();
445            let debug_str = alloc::format!("{:?}", s);
446            assert!(debug_str.contains("TestSuiteSummary"));
447            assert!(debug_str.contains("total_tests"));
448        }
449
450        #[test]
451        fn test_success_rate_single_test_passed() {
452            let mut s = TestSuiteSummary::new();
453            s.total_tests = 1;
454            s.passed = 1;
455            assert_eq!(s.success_rate(), 100.0);
456        }
457
458        #[test]
459        fn test_success_rate_single_test_failed() {
460            let mut s = TestSuiteSummary::new();
461            s.total_tests = 1;
462            s.passed = 0;
463            s.failed = 1;
464            assert_eq!(s.success_rate(), 0.0);
465        }
466    }
467}