use super::*; use domain::scheduler::SchedulerDecision; use types::id::{CoreId, IrqId, ThreadId}; use types::time::TimeSlice; #[test] fn tick_continues_when_time_remaining() { let (mut k, _) = kernel_with_process(); let decision = k.handle_tick(CoreId::from_raw(0)); assert!(matches!(decision, SchedulerDecision::Continue)); } #[test] fn tick_preempts_when_time_expired_and_other_thread_ready() { let mut k = test_kernel(); let mock = MockPlatform::new(1); let pool = PagePool::new(PhysicalAddress::from_raw(0x8000_0000), 1024); let mut k = Kernel::new(mock, pool); // Boot with quantum=2 so it expires after 2 ticks let (pid, tid1) = k.boot(Priority::new(16).unwrap(), TimeSlice::new(2)).unwrap(); // Spawn a second thread so scheduler has someone to switch to let tid2 = k.spawn_thread_for_test(pid, Priority::new(16).unwrap(), TimeSlice::new(100)); // First tick: time remaining let d1 = k.handle_tick(CoreId::from_raw(0)); assert!(matches!(d1, SchedulerDecision::Continue)); // Second tick: time expired, should preempt let d2 = k.handle_tick(CoreId::from_raw(0)); assert!(matches!(d2, SchedulerDecision::Preempt(_))); } #[test] fn interrupt_unknown_irq_returns_none() { let (mut k, _) = kernel_with_process(); assert!(k.handle_interrupt(IrqId::from_raw(99)).is_none()); } #[test] fn interrupt_unblocks_registered_thread() { let (mut k, _) = kernel_with_process(); let tid = ThreadId::from_raw(0); let irq = IrqId::from_raw(5); // Register and block the thread on this IRQ k.register_irq_for_test(irq, tid); k.block_thread_for_test(tid, domain::thread::BlockReason::WaitingForInterrupt( types::bounded::CapSlot::new(0).unwrap() )); let result = k.handle_interrupt(irq); assert_eq!(result, Some(tid)); }