From 8fe60c832ab5006e77c72be52481619f4dff84e8 Mon Sep 17 00:00:00 2001 From: Flamki <9833ayush@gmail.com> Date: Fri, 27 Mar 2026 11:52:09 +0530 Subject: [PATCH] tests(mark_sweep): cover merged parity helper APIs --- oscars/src/collectors/mark_sweep/tests.rs | 70 +++++++++++++++++++ .../src/collectors/mark_sweep_arena2/tests.rs | 70 +++++++++++++++++++ 2 files changed, 140 insertions(+) diff --git a/oscars/src/collectors/mark_sweep/tests.rs b/oscars/src/collectors/mark_sweep/tests.rs index dc3e5bf..454e5e6 100644 --- a/oscars/src/collectors/mark_sweep/tests.rs +++ b/oscars/src/collectors/mark_sweep/tests.rs @@ -149,6 +149,76 @@ fn ptr_eq_distinguishes_equal_values() { ); } +#[test] +fn gc_raw_roundtrip_preserves_identity() { + let collector = &mut MarkSweepGarbageCollector::default() + .with_page_size(256) + .with_heap_threshold(512); + + let original = Gc::new_in(7u32, collector); + let raw = Gc::into_raw(original.clone()); + // SAFETY: `raw` came directly from `Gc::into_raw` above and is still live. + let revived = unsafe { Gc::from_raw(raw) }; + + assert!( + Gc::ptr_eq(&original, &revived), + "into_raw/from_raw should preserve pointer identity" + ); + assert_eq!(*revived, 7u32, "round-tripped pointer value changed"); +} + +#[test] +fn gc_downcast_and_cast_unchecked_parity() { + let collector = &mut MarkSweepGarbageCollector::default() + .with_page_size(256) + .with_heap_threshold(512); + + let typed = Gc::new_in(13u32, collector); + + let erased_as_u64: Gc = unsafe { Gc::cast_unchecked(typed.clone()) }; + assert!( + Gc::downcast::(erased_as_u64).is_none(), + "downcast should fail when runtime type does not match target" + ); + + let erased_as_u64: Gc = unsafe { Gc::cast_unchecked(typed.clone()) }; + let recovered = + Gc::downcast::(erased_as_u64).expect("downcast should succeed for real runtime type"); + + assert_eq!(*recovered, 13u32, "downcast recovered wrong value"); + assert!( + Gc::ptr_eq(&typed, &recovered), + "downcast should recover the same allocation" + ); +} + +#[test] +fn weak_upgrade_tracks_liveness() { + let collector = &mut MarkSweepGarbageCollector::default() + .with_page_size(256) + .with_heap_threshold(512); + + let strong = Gc::new_in(99u32, collector); + let weak = WeakGc::new_in(&strong, collector); + + let upgraded = weak + .upgrade() + .expect("weak should upgrade while strong is alive"); + assert!( + Gc::ptr_eq(&strong, &upgraded), + "upgrade should return a pointer to the same allocation" + ); + + drop(upgraded); + drop(strong); + collector.collect(); + + assert!( + weak.upgrade().is_none(), + "upgrade should fail after referent is collected" + ); +} + #[test] fn multi_gc() { let collector = &mut MarkSweepGarbageCollector::default() diff --git a/oscars/src/collectors/mark_sweep_arena2/tests.rs b/oscars/src/collectors/mark_sweep_arena2/tests.rs index 4cada03..e556a56 100644 --- a/oscars/src/collectors/mark_sweep_arena2/tests.rs +++ b/oscars/src/collectors/mark_sweep_arena2/tests.rs @@ -160,6 +160,76 @@ fn ptr_eq_distinguishes_equal_values() { ); } +#[test] +fn gc_raw_roundtrip_preserves_identity() { + let collector = &mut MarkSweepGarbageCollector::default() + .with_arena_size(256) + .with_heap_threshold(512); + + let original = Gc::new_in(7u32, collector); + let raw = Gc::into_raw(original.clone()); + // SAFETY: `raw` came directly from `Gc::into_raw` above and is still live. + let revived = unsafe { Gc::from_raw(raw) }; + + assert!( + Gc::ptr_eq(&original, &revived), + "into_raw/from_raw should preserve pointer identity" + ); + assert_eq!(*revived, 7u32, "round-tripped pointer value changed"); +} + +#[test] +fn gc_downcast_and_cast_unchecked_parity() { + let collector = &mut MarkSweepGarbageCollector::default() + .with_arena_size(256) + .with_heap_threshold(512); + + let typed = Gc::new_in(13u32, collector); + + let erased_as_u64: Gc = unsafe { Gc::cast_unchecked(typed.clone()) }; + assert!( + Gc::downcast::(erased_as_u64).is_none(), + "downcast should fail when runtime type does not match target" + ); + + let erased_as_u64: Gc = unsafe { Gc::cast_unchecked(typed.clone()) }; + let recovered = + Gc::downcast::(erased_as_u64).expect("downcast should succeed for real runtime type"); + + assert_eq!(*recovered, 13u32, "downcast recovered wrong value"); + assert!( + Gc::ptr_eq(&typed, &recovered), + "downcast should recover the same allocation" + ); +} + +#[test] +fn weak_upgrade_tracks_liveness() { + let collector = &mut MarkSweepGarbageCollector::default() + .with_arena_size(256) + .with_heap_threshold(512); + + let strong = Gc::new_in(99u32, collector); + let weak = WeakGc::new_in(&strong, collector); + + let upgraded = weak + .upgrade() + .expect("weak should upgrade while strong is alive"); + assert!( + Gc::ptr_eq(&strong, &upgraded), + "upgrade should return a pointer to the same allocation" + ); + + drop(upgraded); + drop(strong); + collector.collect(); + + assert!( + weak.upgrade().is_none(), + "upgrade should fail after referent is collected" + ); +} + #[test] fn multi_gc() { let collector = &mut MarkSweepGarbageCollector::default()