()
| 2101 | Some(&image), |
| 2102 | session, |
| 2103 | 60_000_000, |
| 2104 | ); |
| 2105 | |
| 2106 | assert!(!uart.contains("PANIC!"), "kernel panicked; uart={uart:?}"); |
| 2107 | assert!( |
| 2108 | uart.contains("[1] pid 2"), |
| 2109 | "background job not announced; uart={uart:?}" |
| 2110 | ); |
| 2111 | assert!( |
| 2112 | uart.contains("] done pid 2"), |
| 2113 | "killed job was not reaped from the table; uart={uart:?}" |
| 2114 | ); |
| 2115 | assert!( |
| 2116 | uart.contains("no background jobs"), |
| 2117 | "job still listed after kill %1; uart={uart:?}" |
| 2118 | ); |
| 2119 | assert!( |
| 2120 | matches!(outcome, StepOutcome::Halted(0)), |
| 2121 | "shell did not exit cleanly after kill; outcome={outcome:?} uart={uart:?}" |
| 2122 | ); |
| 2123 | } |
| 2124 | |
| 2125 | // `prog > file` binds the child's fd 1 to an FS file. Ordering is the proof: a |
| 2126 | // failed redirect would print the marker to the UART before `cat` reads it back. |
| 2127 | #[test] |
| 2128 | fn kernel_redirect_stdout_to_file() { |
| 2129 | let shell = compile_hosted_program("shell"); |
| 2130 | let printer = compile_hosted( |
| 2131 | r#" |
| 2132 | external console_writeln: (str: u8*) |
| 2133 | external sys_exit: (code: i64) |
| 2134 | main: () -> i32 { |
| 2135 | console_writeln("REDIRECT_OK".ptr) |
| 2136 | sys_exit(0) |
| 2137 | return 0 |
| 2138 | } |
| 2139 | "#, |
| 2140 | ); |
| 2141 | let printer_exec = assembled_to_elf_file(&printer); |
| 2142 | let image = build_fs_image(&[FsEntry::File { |
| 2143 | path: "/printer.elf", |
| 2144 | data: &printer_exec, |
| 2145 | }]); |
| 2146 | |
| 2147 | let session = "run /printer.elf > /out.txt\ncat /out.txt\nexit\n"; |
| 2148 | let (_, outcome, uart) = boot_kernel( |
| 2149 | cached_kernel(), |
| 2150 | Some(&shell), |
| 2151 | Some(&image), |
nothing calls this directly
no test coverage detected