diff --git a/src/mir/builder/control_flow/joinir/patterns/policies/p5b_escape_derived_policy.rs b/src/mir/builder/control_flow/joinir/patterns/policies/p5b_escape_derived_policy.rs index 06f8fadd..a91d7f7d 100644 --- a/src/mir/builder/control_flow/joinir/patterns/policies/p5b_escape_derived_policy.rs +++ b/src/mir/builder/control_flow/joinir/patterns/policies/p5b_escape_derived_policy.rs @@ -199,6 +199,7 @@ fn is_var_named(node: &ASTNode, name: &str) -> bool { mod tests { use super::*; use crate::ast::{BinaryOperator, Span}; + use crate::tests::helpers::joinir_env::with_joinir_env_lock; fn var(name: &str) -> ASTNode { ASTNode::Variable { @@ -306,51 +307,53 @@ mod tests { #[test] fn strict_rejects_when_local_init_missing() { - // escape pattern exists, but `local ch = ...` is absent -> strict should reject - let body = vec![ - ASTNode::If { - condition: Box::new(binop(BinaryOperator::Equal, var("ch"), str_lit("\""))), - then_body: vec![ASTNode::Break { span: Span::unknown() }], - else_body: None, - span: Span::unknown(), - }, - ASTNode::If { - condition: Box::new(binop(BinaryOperator::Equal, var("ch"), str_lit("\\"))), - then_body: vec![ - assignment(var("i"), binop(BinaryOperator::Add, var("i"), int_lit(1))), - assignment( - var("ch"), - method_call( - "s", - "substring", - vec![var("i"), binop(BinaryOperator::Add, var("i"), int_lit(1))], + with_joinir_env_lock(|| { + // escape pattern exists, but `local ch = ...` is absent -> strict should reject + let body = vec![ + ASTNode::If { + condition: Box::new(binop(BinaryOperator::Equal, var("ch"), str_lit("\""))), + then_body: vec![ASTNode::Break { span: Span::unknown() }], + else_body: None, + span: Span::unknown(), + }, + ASTNode::If { + condition: Box::new(binop(BinaryOperator::Equal, var("ch"), str_lit("\\"))), + then_body: vec![ + assignment(var("i"), binop(BinaryOperator::Add, var("i"), int_lit(1))), + assignment( + var("ch"), + method_call( + "s", + "substring", + vec![var("i"), binop(BinaryOperator::Add, var("i"), int_lit(1))], + ), ), - ), - ], - else_body: None, - span: Span::unknown(), - }, - assignment(var("i"), binop(BinaryOperator::Add, var("i"), int_lit(1))), - ]; + ], + else_body: None, + span: Span::unknown(), + }, + assignment(var("i"), binop(BinaryOperator::Add, var("i"), int_lit(1))), + ]; - let prev = std::env::var("HAKO_JOINIR_STRICT").ok(); - std::env::set_var("HAKO_JOINIR_STRICT", "1"); - let decision = classify_p5b_escape_derived(&body, "i"); - if let Some(v) = prev { - std::env::set_var("HAKO_JOINIR_STRICT", v); - } else { - std::env::remove_var("HAKO_JOINIR_STRICT"); - } - - match decision { - P5bEscapeDerivedDecision::Reject(reason) => { - assert!( - reason.contains("missing_local_init"), - "unexpected reason: {}", - reason - ); + let prev = std::env::var("HAKO_JOINIR_STRICT").ok(); + std::env::set_var("HAKO_JOINIR_STRICT", "1"); + let decision = classify_p5b_escape_derived(&body, "i"); + if let Some(v) = prev { + std::env::set_var("HAKO_JOINIR_STRICT", v); + } else { + std::env::remove_var("HAKO_JOINIR_STRICT"); } - other => panic!("expected Reject, got {:?}", other), - } + + match decision { + P5bEscapeDerivedDecision::Reject(reason) => { + assert!( + reason.contains("missing_local_init"), + "unexpected reason: {}", + reason + ); + } + other => panic!("expected Reject, got {:?}", other), + } + }); } } diff --git a/src/runtime/plugin_loader_v2/enabled/loader/library.rs b/src/runtime/plugin_loader_v2/enabled/loader/library.rs index f3d85149..2d8a41c2 100644 --- a/src/runtime/plugin_loader_v2/enabled/loader/library.rs +++ b/src/runtime/plugin_loader_v2/enabled/loader/library.rs @@ -197,6 +197,7 @@ fn candidate_paths(base: &Path) -> Vec { mod tests { use super::*; use crate::config::nyash_toml_v2::{NyashConfigV2, PluginPaths}; + use crate::tests::helpers::joinir_env::with_joinir_env_lock; use std::env; struct EnvGuard { @@ -228,6 +229,15 @@ mod tests { } } + fn ensure_ring0_initialized() { + use crate::runtime::ring0::{default_ring0, GLOBAL_RING0}; + use std::sync::Arc; + + if GLOBAL_RING0.get().is_none() { + let _ = GLOBAL_RING0.set(Arc::new(default_ring0())); + } + } + fn loader_with_missing_library(path: &str) -> PluginLoaderV2 { let mut libraries = HashMap::new(); libraries.insert( @@ -250,22 +260,31 @@ mod tests { #[test] fn load_all_plugins_strict_fails_on_missing_library() { - let _guard = EnvGuard::set("HAKO_JOINIR_STRICT", "1"); - let loader = loader_with_missing_library("/nonexistent/libnyash_filebox_plugin"); + with_joinir_env_lock(|| { + ensure_ring0_initialized(); + let _guard = EnvGuard::set("HAKO_JOINIR_STRICT", "1"); + let loader = loader_with_missing_library("/nonexistent/libnyash_filebox_plugin"); - let result = load_all_plugins(&loader); - assert!(result.is_err(), "strict mode must fail when library is missing"); + let result = load_all_plugins(&loader); + assert!( + result.is_err(), + "strict mode must fail when library is missing" + ); + }); } #[test] fn load_all_plugins_best_effort_continues_on_missing_library() { - let _guard = EnvGuard::unset("HAKO_JOINIR_STRICT"); - let loader = loader_with_missing_library("/nonexistent/libnyash_filebox_plugin"); + with_joinir_env_lock(|| { + ensure_ring0_initialized(); + let _guard = EnvGuard::unset("HAKO_JOINIR_STRICT"); + let loader = loader_with_missing_library("/nonexistent/libnyash_filebox_plugin"); - let result = load_all_plugins(&loader); - assert!( - result.is_ok(), - "non-strict mode should continue even when a library is missing" - ); + let result = load_all_plugins(&loader); + assert!( + result.is_ok(), + "non-strict mode should continue even when a library is missing" + ); + }); } } diff --git a/src/tests/helpers/joinir_env.rs b/src/tests/helpers/joinir_env.rs index f2fb95d9..013e0a06 100644 --- a/src/tests/helpers/joinir_env.rs +++ b/src/tests/helpers/joinir_env.rs @@ -4,6 +4,18 @@ //! //! Note: JoinIR Core は常時 ON。`NYASH_JOINIR_CORE` は deprecated なので、セットは互換目的だけ。 +#[cfg(test)] +use std::sync::Mutex; + +#[cfg(test)] +static JOINIR_ENV_LOCK: Mutex<()> = Mutex::new(()); + +#[cfg(test)] +pub fn with_joinir_env_lock(f: F) { + let _guard = JOINIR_ENV_LOCK.lock().expect("joinir env lock poisoned"); + f(); +} + /// Core ON (joinir_core_enabled = true) にする。 #[allow(dead_code)] pub fn set_core_on() { diff --git a/src/tests/mod.rs b/src/tests/mod.rs index 715df585..366e1730 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -1,4 +1,4 @@ -mod helpers; +pub mod helpers; #[cfg(feature = "aot-plan-import")] pub mod aot_plan_import;