Nothing to see here, move along
at main 266 lines 9.5 kB view raw
1use lancer_core::header::{KernelObjectHeader, NONE_SENTINEL}; 2use lancer_core::object_layout::*; 3use lancer_core::object_tag::ObjectTag; 4use lancer_core::untyped::UntypedState; 5 6#[test] 7fn header_size_is_32() { 8 assert_eq!(core::mem::size_of::<KernelObjectHeader>(), 32); 9} 10 11#[test] 12fn all_fixed_objects_are_64_bytes() { 13 assert_eq!(core::mem::size_of::<EndpointObject>(), 64); 14 assert_eq!(core::mem::size_of::<NotificationObject>(), 64); 15 assert_eq!(core::mem::size_of::<SchedContextObject>(), 64); 16 assert_eq!(core::mem::size_of::<UntypedObject>(), 64); 17 assert_eq!(core::mem::size_of::<IrqHandlerObject>(), 64); 18 assert_eq!(core::mem::size_of::<FramebufferObject>(), 64); 19 assert_eq!(core::mem::size_of::<PciDeviceObject>(), 64); 20 assert_eq!(core::mem::size_of::<ProcessObject>(), 64); 21 assert_eq!(core::mem::size_of::<FrameObject>(), 64); 22 assert_eq!(core::mem::size_of::<CNodeObject>(), 64); 23} 24 25#[test] 26fn header_field_offsets() { 27 assert_eq!(core::mem::offset_of!(KernelObjectHeader, tag), 0); 28 assert_eq!(core::mem::offset_of!(KernelObjectHeader, generation), 4); 29 assert_eq!(core::mem::offset_of!(KernelObjectHeader, ref_count), 8); 30 assert_eq!(core::mem::offset_of!(KernelObjectHeader, parent_untyped), 12); 31 assert_eq!(core::mem::offset_of!(KernelObjectHeader, next_child), 14); 32 assert_eq!(core::mem::offset_of!(KernelObjectHeader, object_size), 16); 33} 34 35#[test] 36fn data_fields_start_at_32() { 37 assert_eq!(core::mem::offset_of!(EndpointObject, sender_head), 32); 38 assert_eq!(core::mem::offset_of!(NotificationObject, word), 32); 39 assert_eq!(core::mem::offset_of!(SchedContextObject, budget_us), 32); 40 assert_eq!(core::mem::offset_of!(UntypedObject, phys_base), 32); 41 assert_eq!(core::mem::offset_of!(IrqHandlerObject, vector), 32); 42 assert_eq!(core::mem::offset_of!(FramebufferObject, phys_addr), 32); 43 assert_eq!(core::mem::offset_of!(PciDeviceObject, device_table_idx), 32); 44 assert_eq!(core::mem::offset_of!(ProcessObject, pid), 32); 45 assert_eq!(core::mem::offset_of!(FrameObject, phys_addr), 32); 46 assert_eq!(core::mem::offset_of!(CNodeObject, slots_phys), 32); 47} 48 49#[test] 50fn init_default_sets_tag_and_refcount() { 51 let header = KernelObjectHeader::new(ObjectTag::Endpoint, 42, 64); 52 let obj = EndpointObject::init_default(header); 53 assert_eq!(obj.header.tag_byte(), ObjectTag::Endpoint as u8); 54 assert_eq!(obj.header.ref_count(), 1); 55 assert_eq!(obj.header.generation(), 42); 56 assert_eq!(obj.header.object_size(), 64); 57 assert_eq!(obj.sender_head, NONE_SENTINEL); 58 assert_eq!(obj.sender_tail, NONE_SENTINEL); 59 assert_eq!(obj.sender_len, 0); 60 assert_eq!(obj.receiver_head, NONE_SENTINEL); 61 assert_eq!(obj.receiver_tail, NONE_SENTINEL); 62 assert_eq!(obj.receiver_len, 0); 63 assert_eq!(obj.holder, NONE_SENTINEL); 64} 65 66#[test] 67fn init_default_notification() { 68 let header = KernelObjectHeader::new(ObjectTag::Notification, 7, 64); 69 let obj = NotificationObject::init_default(header); 70 assert_eq!(obj.header.tag_byte(), ObjectTag::Notification as u8); 71 assert_eq!(obj.word, 0); 72 assert_eq!(obj.waiter_count, 0); 73 obj.waiters.iter().for_each(|w| assert_eq!(*w, 0xFFFF)); 74} 75 76#[test] 77fn init_default_sched_context() { 78 let header = KernelObjectHeader::new(ObjectTag::SchedContext, 0, 64); 79 let obj = SchedContextObject::init_default(header); 80 assert_eq!(obj.budget_us, 0); 81 assert_eq!(obj.period_us, 0); 82 assert_eq!(obj.remaining_us, 0); 83 assert_eq!(obj.replenish_remaining_us, 0); 84 assert_eq!(obj.attached_pid, 0xFFFF); 85 assert_eq!(obj.priority, 0); 86 assert_eq!(obj.flags, 0); 87} 88 89#[test] 90fn header_parent_and_child_default_to_none() { 91 let header = KernelObjectHeader::new(ObjectTag::Endpoint, 0, 64); 92 assert_eq!(header.parent_untyped(), NONE_SENTINEL); 93 assert_eq!(header.next_child(), NONE_SENTINEL); 94} 95 96#[test] 97fn inc_dec_ref_roundtrip() { 98 let mut header = KernelObjectHeader::new(ObjectTag::Endpoint, 0, 64); 99 assert_eq!(header.ref_count(), 1); 100 assert_eq!(header.inc_ref(), Some(2)); 101 assert_eq!(header.ref_count(), 2); 102 assert_eq!(header.inc_ref(), Some(3)); 103 assert_eq!(header.ref_count(), 3); 104 let remaining = header.dec_ref(); 105 assert_eq!(remaining, 2); 106 let remaining = header.dec_ref(); 107 assert_eq!(remaining, 1); 108 let remaining = header.dec_ref(); 109 assert_eq!(remaining, 0); 110} 111 112#[test] 113fn ref_count_saturates() { 114 let mut header = KernelObjectHeader::new(ObjectTag::Endpoint, 0, 64); 115 let remaining = header.dec_ref(); 116 assert_eq!(remaining, 0); 117 let remaining = header.dec_ref(); 118 assert_eq!(remaining, 0); 119} 120 121#[test] 122fn inc_ref_returns_none_at_max() { 123 let mut header = KernelObjectHeader::new(ObjectTag::Endpoint, 0, 64); 124 header.ref_count = u32::MAX; 125 assert_eq!(header.inc_ref(), None); 126 assert_eq!(header.ref_count(), u32::MAX); 127} 128 129#[test] 130fn inc_ref_sequential() { 131 let mut header = KernelObjectHeader::new(ObjectTag::Endpoint, 0, 64); 132 (0..10u32).for_each(|_| { assert!(header.inc_ref().is_some()); }); 133 assert_eq!(header.ref_count(), 11); 134} 135 136#[test] 137fn is_stale_correctness() { 138 let header = KernelObjectHeader::new(ObjectTag::Frame, 100, 64); 139 assert!(!header.is_stale(100)); 140 assert!(header.is_stale(99)); 141 assert!(header.is_stale(101)); 142} 143 144#[test] 145fn set_parent_and_next_child() { 146 let mut header = KernelObjectHeader::new(ObjectTag::Endpoint, 0, 64); 147 header.set_parent_untyped(42); 148 header.set_next_child(99); 149 assert_eq!(header.parent_untyped(), 42); 150 assert_eq!(header.next_child(), 99); 151} 152 153#[test] 154fn untyped_state_roundtrip() { 155 let state = UntypedState::from_parts(1024, 20, true, 5); 156 let header = KernelObjectHeader::new(ObjectTag::Untyped, 0, 64); 157 let mut obj = UntypedObject::init_default(header); 158 obj.apply_state(&state); 159 160 let recovered = obj.to_state(); 161 assert_eq!(recovered.watermark(), 1024); 162 assert_eq!(recovered.size_bits(), 20); 163 assert!(recovered.is_device()); 164 assert_eq!(recovered.child_count(), 5); 165} 166 167#[test] 168fn untyped_state_roundtrip_non_device() { 169 let state = UntypedState::new(15, false); 170 let header = KernelObjectHeader::new(ObjectTag::Untyped, 0, 64); 171 let mut obj = UntypedObject::init_default(header); 172 obj.apply_state(&state); 173 174 let recovered = obj.to_state(); 175 assert_eq!(recovered.watermark(), 0); 176 assert_eq!(recovered.size_bits(), 15); 177 assert!(!recovered.is_device()); 178 assert_eq!(recovered.child_count(), 0); 179} 180 181#[test] 182fn kernel_object_trait_constants() { 183 assert_eq!(EndpointObject::METADATA_SIZE, 64); 184 assert_eq!(EndpointObject::METADATA_ALIGN, 64); 185 assert_eq!(EndpointObject::TAG, ObjectTag::Endpoint); 186 187 assert_eq!(CNodeObject::TAG, ObjectTag::CNode); 188 assert_eq!(FrameObject::TAG, ObjectTag::Frame); 189 assert_eq!(UntypedObject::TAG, ObjectTag::Untyped); 190 assert_eq!(SchedContextObject::TAG, ObjectTag::SchedContext); 191} 192 193#[test] 194fn frame_object_default_size_bits() { 195 let header = KernelObjectHeader::new(ObjectTag::Frame, 0, 64); 196 let obj = FrameObject::init_default(header); 197 assert_eq!(obj.size_bits, 12); 198 assert_eq!(obj.phys_addr, 0); 199} 200 201#[test] 202fn cnode_object_default() { 203 let header = KernelObjectHeader::new(ObjectTag::CNode, 0, 64); 204 let obj = CNodeObject::init_default(header); 205 assert_eq!(obj.slots_phys, 0); 206 assert_eq!(obj.size_bits, 0); 207 assert_eq!(obj.frame_count, 0); 208} 209 210#[test] 211fn init_default_tag_matches_trait_tag_all_types() { 212 fn check<T: KernelObject>() { 213 let header = KernelObjectHeader::new(T::TAG, 0, T::METADATA_SIZE as u16); 214 let obj = T::init_default(header); 215 let header_ref: &KernelObjectHeader = 216 unsafe { &*((&obj as *const T).cast::<KernelObjectHeader>()) }; 217 assert_eq!(header_ref.tag_byte(), T::TAG as u8); 218 assert_eq!(header_ref.object_size(), T::METADATA_SIZE as u16); 219 } 220 check::<EndpointObject>(); 221 check::<NotificationObject>(); 222 check::<SchedContextObject>(); 223 check::<UntypedObject>(); 224 check::<IrqHandlerObject>(); 225 check::<FramebufferObject>(); 226 check::<PciDeviceObject>(); 227 check::<ProcessObject>(); 228 check::<FrameObject>(); 229 check::<CNodeObject>(); 230} 231 232use proptest::prelude::*; 233 234proptest! { 235 #[test] 236 fn arbitrary_generation_header(generation in proptest::num::u32::ANY) { 237 let header = KernelObjectHeader::new(ObjectTag::Notification, generation, 64); 238 prop_assert_eq!(header.generation(), generation); 239 prop_assert!(!header.is_stale(generation)); 240 prop_assert!(header.is_stale(generation.wrapping_add(1))); 241 } 242 243 #[test] 244 fn ref_count_sequence(ops in proptest::collection::vec(proptest::bool::ANY, 0..50)) { 245 let mut header = KernelObjectHeader::new(ObjectTag::Endpoint, 0, 64); 246 let mut expected: u32 = 1; 247 ops.iter().for_each(|inc| { 248 match *inc { 249 true => match expected.checked_add(1) { 250 Some(next) => { 251 assert_eq!(header.inc_ref(), Some(next)); 252 expected = next; 253 } 254 None => { 255 assert_eq!(header.inc_ref(), None); 256 } 257 }, 258 false => { 259 header.dec_ref(); 260 expected = expected.saturating_sub(1); 261 } 262 } 263 assert_eq!(header.ref_count(), expected); 264 }); 265 } 266}