()
| 600 | ); |
| 601 | |
| 602 | // A large opaque-black region proves the FILL clear path ran. |
| 603 | let px = vm.peek_framebuffer(); |
| 604 | let opaque_black = px |
| 605 | .chunks_exact(4) |
| 606 | .filter(|p| p[0] == 0 && p[1] == 0 && p[2] == 0 && p[3] == 255) |
| 607 | .count(); |
| 608 | assert!( |
| 609 | opaque_black > 10_000, |
| 610 | "expected the clear to fill the framebuffer, got {opaque_black} black pixels" |
| 611 | ); |
| 612 | // The device-side FILL must actually have run at least once in this budget. |
| 613 | assert!( |
| 614 | vm.framebuffer_fill_count() >= 1, |
| 615 | "cube did not clear the framebuffer via the FILL register" |
| 616 | ); |
| 617 | } |
| 618 | |
| 619 | // Bounded like the cube run, so assert on the device FILL clear plus at least |
| 620 | // one live cell rather than on exact cell positions. |
| 621 | #[test] |
| 622 | fn life_demo_drives_framebuffer() { |
| 623 | let user = compile_hosted(user::LIFE); |
| 624 | let (vm, outcome, uart) = boot_kernel(cached_kernel(), Some(&user), None, "", 20_000_000); |
| 625 | |
| 626 | assert!(!uart.contains("PANIC!"), "kernel panicked; uart={uart:?}"); |
| 627 | assert!( |
| 628 | !uart.contains("unhandled exception"), |
| 629 | "unhandled CPU exception; uart={uart:?}" |
| 630 | ); |
| 631 | assert!( |
| 632 | uart.contains("[ PROC ] pid 1 ready"), |
| 633 | "life process was not spawned; uart={uart:?}" |
| 634 | ); |
| 635 | assert!( |
| 636 | uart.contains("life: running"), |
| 637 | "life did not reach its render loop; uart={uart:?}" |
| 638 | ); |
| 639 | assert!( |
| 640 | matches!(outcome, StepOutcome::Continue), |
| 641 | "life should run continuously, got {outcome:?}" |
| 642 | ); |
| 643 |
nothing calls this directly
no test coverage detected