From 6f7c54fc6b7370070a5bda034f0c93003380716b Mon Sep 17 00:00:00 2001 From: pjh456 <147148383@qq.com> Date: Wed, 16 Sep 2026 00:43:32 +0000 Subject: [PATCH] =?UTF-8?q?test:=20kernel.rs=20=E5=86=85=E8=81=94=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=E7=A7=BB=E5=85=A5=E9=9B=86=E6=88=90=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crates/oxide_kernel/src/kernel.rs | 200 --------------------- crates/oxide_kernel/tests/kernel_tests.rs | 202 ++++++++++++++++++++++ 2 files changed, 202 insertions(+), 200 deletions(-) create mode 100644 crates/oxide_kernel/tests/kernel_tests.rs diff --git a/crates/oxide_kernel/src/kernel.rs b/crates/oxide_kernel/src/kernel.rs index ed956a28..1577cd3a 100644 --- a/crates/oxide_kernel/src/kernel.rs +++ b/crates/oxide_kernel/src/kernel.rs @@ -865,203 +865,3 @@ impl Drop for KernelSession { self.teardown_builtins(); } } - -#[cfg(test)] -mod tests { - use super::*; - use crate::shape_forge::EMPTY_SHAPE_ID; - - #[test] - fn test_kernel_new() { - let core = KernelCore::new(KernelConfig::minimal()); - let (i1, _) = core.perm_interner().intern("test"); - let (i2, _) = core.perm_interner().intern("test"); - assert_eq!(i1, i2); - } - - #[test] - fn test_kernel_builtins_accessible() { - let core = KernelCore::new(KernelConfig::minimal()); - let session = KernelSession::new(&core); - assert!(!session.builtin_world().object_proto.is_function()); - assert!(session.builtin_world().object_constructor.is_function()); - } - - #[test] - fn test_kernel_shape_forge() { - let core = KernelCore::new(KernelConfig::minimal()); - assert!(core.shape_forge().get_shape(EMPTY_SHAPE_ID).is_some()); - } - - #[test] - fn test_kernel_string_forge() { - let core = KernelCore::new(KernelConfig::minimal()); - let (i1, _) = core.perm_interner().intern("hello"); - let (i2, _) = core.perm_interner().intern("hello"); - assert_eq!(i1, i2); - } - - #[test] - fn test_kernel_config_presets() { - assert_eq!(KernelConfig::minimal().max_pool_size, Some(8)); - assert_eq!(KernelConfig::standard().max_pool_size, Some(32)); - assert_eq!(KernelConfig::minimal().max_steps, None); - assert_eq!(KernelConfig::standard().max_steps, None); - assert_eq!(KernelConfig::full().max_steps, None); - assert_eq!(KernelConfig::minimal().log_levels, [Level::Off; SUBSYSTEM_COUNT]); - assert!(!KernelConfig::minimal().warmup_builtin_ic); - assert!(KernelConfig::full().warmup_builtin_ic); - assert_eq!(KernelConfig::full().max_pool_size, None); - } - - #[test] - fn should_rebuild_perm_default_off() { - // 预设默认 None = 无阈值:任意键数下永不触发,钉死零漂移默认面。 - let core = KernelCore::new(KernelConfig::minimal()); - for i in 0..10 { - core.perm_interner().intern(&format!("key{i}")); - } - assert_eq!(core.should_rebuild_perm(), None); - } - - #[test] - fn should_rebuild_perm_exceeds_threshold() { - let mut config = KernelConfig::minimal(); - config.perm_interner_max_entries = Some(2); - let core = KernelCore::new(config); - core.perm_interner().intern("a"); - core.perm_interner().intern("b"); - // 恰在阈值不触发(超阈值,非达到)。 - assert_eq!(core.should_rebuild_perm(), None); - core.perm_interner().intern("c"); - // 建议上限 = 阈值取 2 的幂后加倍:2 -> 4。 - assert_eq!(core.should_rebuild_perm(), Some(4)); - } - - #[test] - fn should_rebuild_perm_below_threshold() { - let mut config = KernelConfig::minimal(); - config.perm_interner_max_entries = Some(100); - let core = KernelCore::new(config); - core.perm_interner().intern("a"); - core.perm_interner().intern("b"); - assert_eq!(core.should_rebuild_perm(), None); - } - - #[test] - fn test_session_rebuild_shares_forges() { - let core = KernelCore::new(KernelConfig::minimal()); - let (i1, _) = core.perm_interner().intern("hello"); - let _s2 = KernelSession::new(&core); - let (i2, _) = core.perm_interner().intern("hello"); - assert_eq!(i1, i2); - } - - #[test] - fn snapshot_fresh_session_is_clean() { - let core = KernelCore::new(KernelConfig::minimal()); - let session = KernelSession::new(&core); - let dirty = session.dirty_since_snapshot(); - - assert!(!dirty.any()); - assert!(!dirty.any_builtin_dirty()); - assert!(!session.is_dirty_since_snapshot()); - } - - #[test] - fn snapshot_detects_array_dirty() { - let core = KernelCore::new(KernelConfig::minimal()); - let session = KernelSession::new(&core); - - unsafe { &mut *(session.builtin_world.array_proto.as_ptr() as *mut JsObject) }.bump_generation(); - let dirty = session.dirty_since_snapshot(); - - assert!(dirty.array); - assert!(dirty.any_builtin_dirty()); - assert!(session.is_dirty_since_snapshot()); - assert!(!dirty.global); - assert!(!dirty.object); - } - - #[test] - fn snapshot_detects_global_dirty() { - let core = KernelCore::new(KernelConfig::minimal()); - let session = KernelSession::new(&core); - - unsafe { &mut *(session.global_object.as_ptr() as *mut JsObject) }.bump_generation(); - let dirty = session.dirty_since_snapshot(); - - assert!(dirty.global); - assert!(dirty.any()); - assert!(!dirty.any_builtin_dirty()); - } - - #[test] - fn snapshot_detects_stub_dirty() { - let core = KernelCore::new(KernelConfig::minimal()); - let mut session = KernelSession::new(&core); - Arc::get_mut(&mut session.builtin_world) - .expect("fresh session owns its builtin world") - .stub_objects - .push(P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null()))); - session.record_snapshot(); - - Arc::get_mut(&mut session.builtin_world) - .expect("fresh session owns its builtin world") - .stub_objects - .push(P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null()))); - - let dirty = session.dirty_since_snapshot(); - assert!(dirty.stubs); - assert!(dirty.any_builtin_dirty()); - assert!(!dirty.global); - } - - #[test] - fn selective_reset_clean_keeps_builtin_world() { - let core = KernelCore::new(KernelConfig::minimal()); - let mut session = KernelSession::new(&core); - let world_ptr = Arc::as_ptr(&session.builtin_world); - - let dirty = session.selective_reset(&core); - - assert!(!dirty.any()); - assert!(std::ptr::eq(world_ptr, Arc::as_ptr(&session.builtin_world))); - } - - #[test] - fn selective_reset_rebuilds_global_only_when_global_dirty() { - let core = KernelCore::new(KernelConfig::minimal()); - let mut session = KernelSession::new(&core); - let world_ptr = Arc::as_ptr(&session.builtin_world); - let global_ptr = session.global_object.as_ptr(); - - unsafe { &mut *(session.global_object.as_ptr() as *mut JsObject) }.bump_generation(); - let dirty = session.selective_reset(&core); - - assert!(dirty.global); - assert!(!dirty.any_builtin_dirty()); - assert!(std::ptr::eq(world_ptr, Arc::as_ptr(&session.builtin_world))); - assert!(!std::ptr::eq(global_ptr, session.global_object.as_ptr())); - } - - #[test] - fn selective_reset_rebuilds_dirty_builtin_group() { - let core = KernelCore::new(KernelConfig::minimal()); - let mut session = KernelSession::new(&core); - let object_proto = session.builtin_world.object_proto.as_ptr(); - let array_proto = session.builtin_world.array_proto.as_ptr(); - let world_ptr = Arc::as_ptr(&session.builtin_world); - - unsafe { &mut *(session.builtin_world.array_proto.as_ptr() as *mut JsObject) }.bump_generation(); - let dirty = session.selective_reset(&core); - - assert!(dirty.array); - assert!(!std::ptr::eq(world_ptr, Arc::as_ptr(&session.builtin_world))); - assert!(std::ptr::eq(object_proto, session.builtin_world.object_proto.as_ptr())); - assert!(!std::ptr::eq(array_proto, session.builtin_world.array_proto.as_ptr())); - - let ctor_proto = session.builtin_world.array_constructor.get_prop_at(0).as_js_object_ptr(); - assert!(std::ptr::eq(ctor_proto, session.builtin_world.array_proto.as_ptr() as *mut JsObject)); - } -} diff --git a/crates/oxide_kernel/tests/kernel_tests.rs b/crates/oxide_kernel/tests/kernel_tests.rs new file mode 100644 index 00000000..35d992aa --- /dev/null +++ b/crates/oxide_kernel/tests/kernel_tests.rs @@ -0,0 +1,202 @@ +use std::sync::Arc; + +use oxide_kernel::kernel::{KernelConfig, KernelCore, KernelSession}; +use oxide_kernel::shape_forge::EMPTY_SHAPE_ID; +use oxide_log::{Level, SUBSYSTEM_COUNT}; +use oxide_types::mem::P; +use oxide_types::object::JsObject; +use oxide_types::value::JsValue; + +#[test] +fn test_kernel_new() { + let core = KernelCore::new(KernelConfig::minimal()); + let (i1, _) = core.perm_interner().intern("test"); + let (i2, _) = core.perm_interner().intern("test"); + assert_eq!(i1, i2); +} + +#[test] +fn test_kernel_builtins_accessible() { + let core = KernelCore::new(KernelConfig::minimal()); + let session = KernelSession::new(&core); + assert!(!session.builtin_world().object_proto.is_function()); + assert!(session.builtin_world().object_constructor.is_function()); +} + +#[test] +fn test_kernel_shape_forge() { + let core = KernelCore::new(KernelConfig::minimal()); + assert!(core.shape_forge().get_shape(EMPTY_SHAPE_ID).is_some()); +} + +#[test] +fn test_kernel_string_forge() { + let core = KernelCore::new(KernelConfig::minimal()); + let (i1, _) = core.perm_interner().intern("hello"); + let (i2, _) = core.perm_interner().intern("hello"); + assert_eq!(i1, i2); +} + +#[test] +fn test_kernel_config_presets() { + assert_eq!(KernelConfig::minimal().max_pool_size, Some(8)); + assert_eq!(KernelConfig::standard().max_pool_size, Some(32)); + assert_eq!(KernelConfig::minimal().max_steps, None); + assert_eq!(KernelConfig::standard().max_steps, None); + assert_eq!(KernelConfig::full().max_steps, None); + assert_eq!(KernelConfig::minimal().log_levels, [Level::Off; SUBSYSTEM_COUNT]); + assert!(!KernelConfig::minimal().warmup_builtin_ic); + assert!(KernelConfig::full().warmup_builtin_ic); + assert_eq!(KernelConfig::full().max_pool_size, None); +} + +#[test] +fn should_rebuild_perm_default_off() { + // 预设默认 None = 无阈值:任意键数下永不触发,钉死零漂移默认面。 + let core = KernelCore::new(KernelConfig::minimal()); + for i in 0..10 { + core.perm_interner().intern(&format!("key{i}")); + } + assert_eq!(core.should_rebuild_perm(), None); +} + +#[test] +fn should_rebuild_perm_exceeds_threshold() { + let mut config = KernelConfig::minimal(); + config.perm_interner_max_entries = Some(2); + let core = KernelCore::new(config); + core.perm_interner().intern("a"); + core.perm_interner().intern("b"); + // 恰在阈值不触发(超阈值,非达到)。 + assert_eq!(core.should_rebuild_perm(), None); + core.perm_interner().intern("c"); + // 建议上限 = 阈值取 2 的幂后加倍:2 -> 4。 + assert_eq!(core.should_rebuild_perm(), Some(4)); +} + +#[test] +fn should_rebuild_perm_below_threshold() { + let mut config = KernelConfig::minimal(); + config.perm_interner_max_entries = Some(100); + let core = KernelCore::new(config); + core.perm_interner().intern("a"); + core.perm_interner().intern("b"); + assert_eq!(core.should_rebuild_perm(), None); +} + +#[test] +fn test_session_rebuild_shares_forges() { + let core = KernelCore::new(KernelConfig::minimal()); + let (i1, _) = core.perm_interner().intern("hello"); + let _s2 = KernelSession::new(&core); + let (i2, _) = core.perm_interner().intern("hello"); + assert_eq!(i1, i2); +} + +#[test] +fn snapshot_fresh_session_is_clean() { + let core = KernelCore::new(KernelConfig::minimal()); + let session = KernelSession::new(&core); + let dirty = session.dirty_since_snapshot(); + + assert!(!dirty.any()); + assert!(!dirty.any_builtin_dirty()); + assert!(!session.is_dirty_since_snapshot()); +} + +#[test] +fn snapshot_detects_array_dirty() { + let core = KernelCore::new(KernelConfig::minimal()); + let session = KernelSession::new(&core); + + unsafe { &mut *(session.builtin_world.array_proto.as_ptr() as *mut JsObject) }.bump_generation(); + let dirty = session.dirty_since_snapshot(); + + assert!(dirty.array); + assert!(dirty.any_builtin_dirty()); + assert!(session.is_dirty_since_snapshot()); + assert!(!dirty.global); + assert!(!dirty.object); +} + +#[test] +fn snapshot_detects_global_dirty() { + let core = KernelCore::new(KernelConfig::minimal()); + let session = KernelSession::new(&core); + + unsafe { &mut *(session.global_object.as_ptr() as *mut JsObject) }.bump_generation(); + let dirty = session.dirty_since_snapshot(); + + assert!(dirty.global); + assert!(dirty.any()); + assert!(!dirty.any_builtin_dirty()); +} + +#[test] +fn snapshot_detects_stub_dirty() { + let core = KernelCore::new(KernelConfig::minimal()); + let mut session = KernelSession::new(&core); + Arc::get_mut(&mut session.builtin_world) + .expect("fresh session owns its builtin world") + .stub_objects + .push(P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null()))); + session.record_snapshot(); + + Arc::get_mut(&mut session.builtin_world) + .expect("fresh session owns its builtin world") + .stub_objects + .push(P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null()))); + + let dirty = session.dirty_since_snapshot(); + assert!(dirty.stubs); + assert!(dirty.any_builtin_dirty()); + assert!(!dirty.global); +} + +#[test] +fn selective_reset_clean_keeps_builtin_world() { + let core = KernelCore::new(KernelConfig::minimal()); + let mut session = KernelSession::new(&core); + let world_ptr = Arc::as_ptr(&session.builtin_world); + + let dirty = session.selective_reset(&core); + + assert!(!dirty.any()); + assert!(std::ptr::eq(world_ptr, Arc::as_ptr(&session.builtin_world))); +} + +#[test] +fn selective_reset_rebuilds_global_only_when_global_dirty() { + let core = KernelCore::new(KernelConfig::minimal()); + let mut session = KernelSession::new(&core); + let world_ptr = Arc::as_ptr(&session.builtin_world); + let global_ptr = session.global_object.as_ptr(); + + unsafe { &mut *(session.global_object.as_ptr() as *mut JsObject) }.bump_generation(); + let dirty = session.selective_reset(&core); + + assert!(dirty.global); + assert!(!dirty.any_builtin_dirty()); + assert!(std::ptr::eq(world_ptr, Arc::as_ptr(&session.builtin_world))); + assert!(!std::ptr::eq(global_ptr, session.global_object.as_ptr())); +} + +#[test] +fn selective_reset_rebuilds_dirty_builtin_group() { + let core = KernelCore::new(KernelConfig::minimal()); + let mut session = KernelSession::new(&core); + let object_proto = session.builtin_world.object_proto.as_ptr(); + let array_proto = session.builtin_world.array_proto.as_ptr(); + let world_ptr = Arc::as_ptr(&session.builtin_world); + + unsafe { &mut *(session.builtin_world.array_proto.as_ptr() as *mut JsObject) }.bump_generation(); + let dirty = session.selective_reset(&core); + + assert!(dirty.array); + assert!(!std::ptr::eq(world_ptr, Arc::as_ptr(&session.builtin_world))); + assert!(std::ptr::eq(object_proto, session.builtin_world.object_proto.as_ptr())); + assert!(!std::ptr::eq(array_proto, session.builtin_world.array_proto.as_ptr())); + + let ctor_proto = session.builtin_world.array_constructor.get_prop_at(0).as_js_object_ptr(); + assert!(std::ptr::eq(ctor_proto, session.builtin_world.array_proto.as_ptr() as *mut JsObject)); +}