diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 71798b6e..a4540fe6 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2026-06-21" +channel = "nightly-2026-08-07" targets = [ "wasm32-unknown-unknown" ] \ No newline at end of file diff --git a/src/instructions/control/get_thread_timeout.rs b/src/instructions/control/get_thread_timeout.rs index 1f8a426f..c95a4eed 100644 --- a/src/instructions/control/get_thread_timeout.rs +++ b/src/instructions/control/get_thread_timeout.rs @@ -1,3 +1,5 @@ +//! This block must be called from within a thread spawned by `control_wait`, or it will trap. + use wasm_encoder::{FieldType, HeapType, StorageType}; use super::super::prelude::*; diff --git a/src/instructions/control/if_else.rs b/src/instructions/control/if_else.rs index 8d8b21f0..8dbf412d 100644 --- a/src/instructions/control/if_else.rs +++ b/src/instructions/control/if_else.rs @@ -85,4 +85,28 @@ pub fn const_fold( } } -// crate::instructions_test! {none; hq__if; @ super::Fields(None)} +#[cfg(test)] +mod test { + use super::super::super::tests::*; + use super::*; + + #[test] + fn fields_display_is_valid_json() { + let fields = make_fields(); + assert_valid_json(format!("{fields}")); + } + + pub fn make_fields() -> Fields { + let target = make_target(); + Fields { + branch_if: make_step(&target), + branch_else: make_step(&target), + } + } +} + +crate::instructions_test! ( +mod test2 for control_if_else(t) { + fields = super::test::make_fields(); +} +); diff --git a/src/instructions/control/loop.rs b/src/instructions/control/loop.rs index a169317e..807e4f5e 100644 --- a/src/instructions/control/loop.rs +++ b/src/instructions/control/loop.rs @@ -20,6 +20,9 @@ impl fmt::Display for Fields { if let Some(ref step) = self.first_condition { write!(f, r#""first_condition": {},"#, RefCell::borrow(step))?; } + if let Some(ref step) = self.pre_body { + write!(f, r#""pre_body": {},"#, RefCell::borrow(step))?; + } write!( f, r#" @@ -92,3 +95,102 @@ pub const fn const_fold( ) -> HQResult { Ok(NotFoldable) } + +#[cfg(test)] +mod test { + use super::super::super::tests::*; + use super::*; + use crate::ir::StepContext; + + #[test] + fn fields_display_is_valid_json() { + for ((fc, pb), fi) in [true, false] + .into_iter() + .cartesian_product([true, false]) + .cartesian_product([true, false]) + { + let fields = make_fields(fc, pb, fi); + assert_valid_json(format!("{fields}")); + } + } + + fn make_condition_step(context: &StepContext) -> Rc> { + Rc::new(RefCell::new(Step::new( + None, + context.clone(), + vec![crate::instructions::IrOpcode::hq_boolean( + crate::instructions::HqBooleanFields(true), + )], + Weak::new(), + false, + ))) + } + + pub fn make_fields(first_condition: bool, pre_body: bool, flip_if: bool) -> Fields { + let target = make_target(); + let context = make_context(&target); + Fields { + first_condition: if first_condition { + None + } else { + Some(make_condition_step(&context)) + }, + condition: make_condition_step(&context), + pre_body: if pre_body { + None + } else { + Some(make_step(&target)) + }, + body: make_step(&target), + flip_if, + } + } +} + +crate::instructions_test! ( +mod test_fc_pb_fi for control_loop { + fields = super::test::make_fields(true, true, true); +} +); + +crate::instructions_test! ( +mod test_fc_pb for control_loop { + fields = super::test::make_fields(true, true, false); +} +); + +crate::instructions_test! ( +mod test_fc_fi for control_loop { + fields = super::test::make_fields(true, false, true); +} +); + +crate::instructions_test! ( +mod test_fc for control_loop { + fields = super::test::make_fields(true, false, false); +} +); + +crate::instructions_test! ( +mod test_pb_fi for control_loop { + fields = super::test::make_fields(false, true, true); +} +); + +crate::instructions_test! ( +mod test_pb for control_loop { + fields = super::test::make_fields(false, true, false); +} +); + +crate::instructions_test! ( +mod test_fi for control_loop { + fields = super::test::make_fields(false, false, true); +} +); + +crate::instructions_test! ( +mod test_defaults for control_loop { + fields = super::test::make_fields(false, false, false); +} +); diff --git a/src/instructions/control/stop_all.rs b/src/instructions/control/stop_all.rs index 46a605a6..3b2ca327 100644 --- a/src/instructions/control/stop_all.rs +++ b/src/instructions/control/stop_all.rs @@ -1,6 +1,7 @@ use wasm_encoder::{ConstExpr, HeapType}; use super::super::prelude::*; +use crate::instructions_test; use crate::wasm::{GlobalExportable, GlobalMutable, ThreadsTable}; pub fn wasm(func: &StepFunc, _inputs: Rc<[IrType]>) -> HQResult> { @@ -43,3 +44,7 @@ pub const fn const_fold( ) -> HQResult { Ok(NotFoldable) } + +instructions_test!( + mod test for control_stop_all {} +); diff --git a/src/instructions/control/wait.rs b/src/instructions/control/wait.rs index ee8031c9..18ab64a5 100644 --- a/src/instructions/control/wait.rs +++ b/src/instructions/control/wait.rs @@ -1,6 +1,7 @@ use wasm_encoder::{AbstractHeapType, ConstExpr, FieldType, HeapType, StorageType}; use super::super::prelude::*; +use crate::instructions_test; use crate::ir::StepIndex; use crate::wasm::registries::functions::static_functions::SpawnThreadInStack; use crate::wasm::{GlobalExportable, GlobalMutable, StepFunc}; @@ -104,3 +105,44 @@ pub const fn const_fold( ) -> HQResult { Ok(NotFoldable) } + +#[cfg(test)] +mod test { + use super::super::super::tests::*; + use super::*; + use crate::wasm::registries::TypeRegistry; + use crate::wasm::{StepTarget, WasmFlags, WasmProject}; + + #[test] + fn fields_display_is_valid_json() { + let fields = make_fields(); + assert_valid_json(format!("{fields}")); + } + + pub fn make_fields() -> Fields { + Fields { + poll_step: StepIndex(0), + next_step: StepIndex(1), + } + } + + pub fn setup_project(wasm_proj: &WasmProject, flags: WasmFlags) { + let step_func = StepFunc::new_with_types( + Box::from([ValType::I32, TypeRegistry::STRUCT_REF]), + Box::from([]), + wasm_proj.registries(), + flags, + StepTarget::Sprite(0), + 0, + Rc::new(vec![]), + ); + wasm_proj.steps().borrow_mut().push(step_func); + } +} + +instructions_test!( + mod test2 for control_wait(t) { + fields = super::test::make_fields(); + setup = super::test::setup_project; + } +); diff --git a/src/instructions/data/addtolist.rs b/src/instructions/data/addtolist.rs index d985011e..d9f95fb1 100644 --- a/src/instructions/data/addtolist.rs +++ b/src/instructions/data/addtolist.rs @@ -77,64 +77,47 @@ pub const fn const_fold( Ok(NotFoldable) } +#[cfg(test)] +mod test { + pub use super::super::listcontents::test_utils::*; + use super::*; + use crate::instructions::tests::assert_valid_json; + use crate::wasm::WasmFlags; + + #[test] + fn fields_display_is_valid_json() { + let fields = make_fields(true, IrType::Any, flags_with_integers()); + assert_valid_json(format!("{fields}")); + } + + pub fn make_fields(mutable: bool, ty: IrType, flags: WasmFlags) -> Fields { + Fields { + list: make_list(mutable, ty, flags), + } + } +} + crate::instructions_test!( - int; - data_addtolist; - t @ super::Fields { - list: { - let list = crate::ir::RcList::new( - vec![], - &flags() - ).unwrap(); - *list.length_mutable().borrow_mut() = true; - list.add_type(IrType::Int); - list - }, - }; - { let mut flags = WasmFlags::new(unit_test_wasm_features()); flags.integers = Switch::On; flags } + + mod test_int for data_addtolist(t) { + fields = super::test::make_fields(true, IrType::Int, flags()); + flags = super::test::flags_with_integers(); + } + ); crate::instructions_test!( - float; - data_addtolist; - t @ super::Fields { - list: { - let list = crate::ir::RcList::new( - vec![], - &flags() - ).unwrap(); - *list.length_mutable().borrow_mut() = true; - list.add_type(IrType::Float); - list - }, + mod test_float for data_addtolist(t) { + fields = super::test::make_fields(true, IrType::Float, flags()); } ); + crate::instructions_test!( - string; - data_addtolist; - t @ super::Fields { - list: { - let list = crate::ir::RcList::new( - vec![crate::sb3::VarVal::String("hi".into())], - &flags() - ).unwrap(); - *list.length_mutable().borrow_mut() = true; - list.add_type(IrType::String); - list - }, + mod test_string for data_addtolist(t) { + fields = super::test::make_fields(true, IrType::String, flags()); } ); crate::instructions_test!( - any; - data_addtolist; - t @ super::Fields { - list: { - let list = crate::ir::RcList::new( - vec![], - &flags() - ).unwrap(); - *list.length_mutable().borrow_mut() = true; - list.add_type(IrType::Any); - list - }, + mod test_any for data_addtolist(t) { + fields = super::test::make_fields(true, IrType::String, flags()); } ); diff --git a/src/instructions/data/deletealloflist.rs b/src/instructions/data/deletealloflist.rs index 0d252f89..6913a3b2 100644 --- a/src/instructions/data/deletealloflist.rs +++ b/src/instructions/data/deletealloflist.rs @@ -48,18 +48,34 @@ pub const fn const_fold( Ok(NotFoldable) } +#[cfg(test)] +mod test { + pub use super::super::listcontents::test_utils::*; + use super::*; + use crate::instructions::tests::assert_valid_json; + use crate::wasm::WasmFlags; + + #[test] + fn fields_display_is_valid_json() { + let fields = make_fields(flags_with_integers()); + assert_valid_json(format!("{fields}")); + } + + pub fn make_fields(flags: WasmFlags) -> Fields { + Fields { + list: { + let list = + crate::ir::RcList::new(vec![crate::sb3::VarVal::Float(3.0)], &flags).unwrap(); + *list.length_mutable().borrow_mut() = true; + list.add_type(IrType::Any); + list + }, + } + } +} + crate::instructions_test!( - test; - data_deletealloflist; - @ super::Fields { - list: { - let list = crate::ir::RcList::new( - vec![crate::sb3::VarVal::Float(3.0)], - &flags() - ).unwrap(); - *list.length_mutable().borrow_mut() = true; - list.add_type(IrType::Any); - list - }, + mod test2 for data_deletealloflist { + fields = super::test::make_fields(flags()); } ); diff --git a/src/instructions/data/deleteoflist.rs b/src/instructions/data/deleteoflist.rs index df0be839..7a3a338d 100644 --- a/src/instructions/data/deleteoflist.rs +++ b/src/instructions/data/deleteoflist.rs @@ -83,64 +83,47 @@ pub const fn const_fold( Ok(NotFoldable) } +#[cfg(test)] +mod test { + pub use super::super::listcontents::test_utils::*; + use super::*; + use crate::instructions::tests::assert_valid_json; + use crate::wasm::WasmFlags; + + #[test] + fn fields_display_is_valid_json() { + let fields = make_fields(IrType::Any, flags_with_integers()); + assert_valid_json(format!("{fields}")); + } + + pub fn make_fields(ty: IrType, flags: WasmFlags) -> Fields { + Fields { + list: make_list(true, ty, flags), + } + } +} + crate::instructions_test!( - int_mut; - data_deleteoflist; - t @ super::Fields { - list: { - let list = crate::ir::RcList::new( - vec![], - &flags() - ).unwrap(); - *list.length_mutable().borrow_mut() = true; - list.add_type(IrType::Int); - list - }, - }; - { let mut flags = WasmFlags::new(unit_test_wasm_features()); flags.integers = Switch::On; flags } + mod test_int for data_deleteoflist(t) { + fields = super::test::make_fields(IrType::Int, flags()); + flags = super::test::flags_with_integers(); + } ); + crate::instructions_test!( - float_mut; - data_deleteoflist; - t @ super::Fields { - list: { - let list = crate::ir::RcList::new( - vec![], - &flags() - ).unwrap(); - *list.length_mutable().borrow_mut() = true; - list.add_type(IrType::Float); - list - }, + mod test_float for data_deleteoflist(t) { + fields = super::test::make_fields(IrType::Float, flags()); } ); + crate::instructions_test!( - string_mut; - data_deleteoflist; - t @ super::Fields { - list: { - let list = crate::ir::RcList::new( - vec![crate::sb3::VarVal::String("hi".into())], - &flags() - ).unwrap(); - *list.length_mutable().borrow_mut() = true; - list.add_type(IrType::String); - list - }, + mod test_string for data_deleteoflist(t) { + fields = super::test::make_fields(IrType::String, flags()); } ); + crate::instructions_test!( - any_mut; - data_deleteoflist; - t @ super::Fields { - list: { - let list = crate::ir::RcList::new( - vec![], - &flags() - ).unwrap(); - *list.length_mutable().borrow_mut() = true; - list.add_type(IrType::Any); - list - }, + mod test_any for data_deleteoflist(t) { + fields = super::test::make_fields(IrType::Any, flags()); } ); diff --git a/src/instructions/data/insertatlist.rs b/src/instructions/data/insertatlist.rs index b4fb7c8c..9413670f 100644 --- a/src/instructions/data/insertatlist.rs +++ b/src/instructions/data/insertatlist.rs @@ -113,64 +113,47 @@ pub const fn const_fold( Ok(NotFoldable) } +#[cfg(test)] +mod test { + pub use super::super::listcontents::test_utils::*; + use super::*; + use crate::instructions::tests::assert_valid_json; + use crate::wasm::WasmFlags; + + #[test] + fn fields_display_is_valid_json() { + let fields = make_fields(IrType::Any, flags_with_integers()); + assert_valid_json(format!("{fields}")); + } + + pub fn make_fields(ty: IrType, flags: WasmFlags) -> Fields { + Fields { + list: make_list(true, ty, flags), + } + } +} + crate::instructions_test!( - int_mut; - data_insertatlist; - t1, t2 @ super::Fields { - list: { - let list = crate::ir::RcList::new( - vec![], - &flags() - ).unwrap(); - *list.length_mutable().borrow_mut() = true; - list.add_type(IrType::Int); - list - }, - }; - { let mut flags = WasmFlags::new(unit_test_wasm_features()); flags.integers = Switch::On; flags } + mod test_int for data_insertatlist(t1, t2) { + fields = super::test::make_fields(IrType::Int, flags()); + flags = super::test::flags_with_integers(); + } ); + crate::instructions_test!( - float_mut; - data_insertatlist; - t1, t2 @ super::Fields { - list: { - let list = crate::ir::RcList::new( - vec![], - &flags() - ).unwrap(); - *list.length_mutable().borrow_mut() = true; - list.add_type(IrType::Float); - list - }, + mod test_float for data_insertatlist(t1, t2) { + fields = super::test::make_fields(IrType::Float, flags()); } ); + crate::instructions_test!( - string_mut; - data_insertatlist; - t1, t2 @ super::Fields { - list: { - let list = crate::ir::RcList::new( - vec![crate::sb3::VarVal::String("hi".into())], - &flags() - ).unwrap(); - *list.length_mutable().borrow_mut() = true; - list.add_type(IrType::String); - list - }, + mod test_string for data_insertatlist(t1, t2) { + fields = super::test::make_fields(IrType::String, flags()); } ); + crate::instructions_test!( - any_mut; - data_insertatlist; - t1, t2 @ super::Fields { - list: { - let list = crate::ir::RcList::new( - vec![], - &flags() - ).unwrap(); - *list.length_mutable().borrow_mut() = true; - list.add_type(IrType::Any); - list - }, + mod any_mut for data_insertatlist(t1, t2) { + fields = super::test::make_fields(IrType::Any, flags()); } ); diff --git a/src/instructions/data/itemoflist.rs b/src/instructions/data/itemoflist.rs index c2863bc0..5d0e3735 100644 --- a/src/instructions/data/itemoflist.rs +++ b/src/instructions/data/itemoflist.rs @@ -112,9 +112,8 @@ pub const fn const_fold( } crate::instructions_test!( - int_mut; - data_itemoflist; - t @ super::Fields { +mod int_mut for data_itemoflist(t) { + fields = super::Fields { list: { let list = crate::ir::RcList::new( vec![], @@ -125,12 +124,12 @@ crate::instructions_test!( list }, }; - { let mut flags = WasmFlags::new(unit_test_wasm_features()); flags.integers = Switch::On; flags } + flags = { let mut flags = WasmFlags::new(unit_test_wasm_features()); flags.integers = Switch::On; flags }; +} ); crate::instructions_test!( - float_mut; - data_itemoflist; - t @ super::Fields { +mod float_mut for data_itemoflist(t) { + fields = super::Fields { list: { let list = crate::ir::RcList::new( vec![], @@ -140,12 +139,12 @@ crate::instructions_test!( list.add_type(IrType::Float); list }, - } + }; +} ); crate::instructions_test!( - string_mut; - data_itemoflist; - t @ super::Fields { +mod string_mut for data_itemoflist(t) { + fields = super::Fields { list: { let list = crate::ir::RcList::new( vec![crate::sb3::VarVal::String("hi".into())], @@ -155,12 +154,12 @@ crate::instructions_test!( list.add_type(IrType::String); list }, - } + }; +} ); crate::instructions_test!( - any_mut; - data_itemoflist; - t @ super::Fields { +mod any_mut for data_itemoflist(t) { + fields = super::Fields { list: { let list = crate::ir::RcList::new( vec![], @@ -170,13 +169,13 @@ crate::instructions_test!( list.add_type(IrType::Any); list }, - } + }; +} ); crate::instructions_test!( - int_static; - data_itemoflist; - t @ super::Fields { +mod int_static for data_itemoflist(t) { + fields = super::Fields { list: { let list = crate::ir::RcList::new( vec![], @@ -186,13 +185,13 @@ crate::instructions_test!( list } }; - { let mut flags = WasmFlags::new(unit_test_wasm_features()); flags.integers = Switch::On; flags } + flags = { let mut flags = WasmFlags::new(unit_test_wasm_features()); flags.integers = Switch::On; flags }; +} ); crate::instructions_test!( - float_static; - data_itemoflist; - t @ super::Fields { +mod float_static for data_itemoflist(t) { + fields = super::Fields { list: { let list = crate::ir::RcList::new( vec![], @@ -201,13 +200,13 @@ crate::instructions_test!( list.add_type(IrType::Float); list } - } + }; +} ); crate::instructions_test!( - string_static; - data_itemoflist; - t @ super::Fields { +mod string_static for data_itemoflist(t) { + fields = super::Fields { list: { let list = crate::ir::RcList::new( vec![], @@ -216,13 +215,13 @@ crate::instructions_test!( list.add_type(IrType::String); list } - } + }; +} ); crate::instructions_test!( - any_static; - data_itemoflist; - t @ super::Fields { +mod any_static for data_itemoflist(t) { + fields = super::Fields { list: { let list = crate::ir::RcList::new( vec![], @@ -231,5 +230,6 @@ crate::instructions_test!( list.add_type(IrType::Any); list } - } + }; +} ); diff --git a/src/instructions/data/lengthoflist.rs b/src/instructions/data/lengthoflist.rs index 403483bd..53ff4688 100644 --- a/src/instructions/data/lengthoflist.rs +++ b/src/instructions/data/lengthoflist.rs @@ -62,33 +62,34 @@ pub const fn const_fold( Ok(NotFoldable) } +#[cfg(test)] +mod test { + pub use super::super::listcontents::test_utils::*; + use super::*; + use crate::instructions::tests::assert_valid_json; + use crate::wasm::WasmFlags; + + #[test] + fn fields_display_is_valid_json() { + let fields = make_fields(true, flags_with_integers()); + assert_valid_json(format!("{fields}")); + } + + pub fn make_fields(mutable: bool, flags: WasmFlags) -> Fields { + Fields { + list: make_list(mutable, IrType::Any, flags), + } + } +} + crate::instructions_test!( - _mut; - data_lengthoflist; - @ super::Fields { - list: { - let list = crate::ir::RcList::new( - vec![crate::sb3::VarVal::Float(3.0)], - &flags() - ).unwrap(); - *list.length_mutable().borrow_mut() = true; - list.add_type(IrType::Any); - list - }, + mod test_mut for data_lengthoflist { + fields = super::test::make_fields(true, flags()); } ); crate::instructions_test!( - _static; - data_lengthoflist; - @ super::Fields { - list: { - let list = crate::ir::RcList::new( - vec![], - &flags() - ).unwrap(); - list.add_type(IrType::Any); - list - } + mod test_static for data_lengthoflist { + fields = super::test::make_fields(false, flags()); } ); diff --git a/src/instructions/data/listcontents.rs b/src/instructions/data/listcontents.rs index 802645c3..e6e9f8c9 100644 --- a/src/instructions/data/listcontents.rs +++ b/src/instructions/data/listcontents.rs @@ -282,157 +282,107 @@ pub const fn const_fold( Ok(NotFoldable) } +#[cfg(test)] +pub mod test_utils { + use super::*; + use crate::wasm::WasmFlags; + use crate::wasm::flags::{Switch, unit_test_wasm_features}; + + pub fn make_list(mutable: bool, ty: IrType, flags: WasmFlags) -> RcList { + let list = crate::ir::RcList::new(vec![], &flags).unwrap(); + *list.length_mutable().borrow_mut() = mutable; + list.add_type(ty); + list + } + + pub fn flags_with_integers() -> WasmFlags { + let mut flags = WasmFlags::new(unit_test_wasm_features()); + flags.integers = Switch::On; + flags + } +} + +#[cfg(test)] +mod test { + pub use test_utils::*; + + use super::*; + use crate::instructions::tests::assert_valid_json; + use crate::wasm::WasmFlags; + + #[test] + fn fields_display_is_valid_json() { + let fields = make_fields(true, IrType::Any, super::test::flags_with_integers()); + assert_valid_json(format!("{fields}")); + } + + pub fn make_fields(mutable: bool, ty: IrType, flags: WasmFlags) -> Fields { + Fields { + list: make_list(mutable, ty, flags), + } + } +} + crate::instructions_test!( - int_mut; - data_listcontents; - @ super::Fields { - list: { - let list = crate::ir::RcList::new( - vec![], - &flags() - ).unwrap(); - *list.length_mutable().borrow_mut() = true; - list.add_type(IrType::Int); - list - }, - }; - { let mut flags = WasmFlags::new(unit_test_wasm_features()); flags.integers = Switch::On; flags } + mod test_int_mut for data_listcontents { + fields = super::test::make_fields(true, IrType::Int, flags()); + flags = super::test::flags_with_integers(); + } ); + crate::instructions_test!( - bool_mut; - data_listcontents; - @ super::Fields { - list: { - let list = crate::ir::RcList::new( - vec![], - &flags() - ).unwrap(); - *list.length_mutable().borrow_mut() = true; - list.add_type(IrType::Boolean); - list - }, - }; - { let mut flags = WasmFlags::new(unit_test_wasm_features()); flags.integers = Switch::On; flags } + mod test_bool_mut for data_listcontents { + fields = super::test::make_fields(true, IrType::Boolean, flags()); + flags = super::test::flags_with_integers(); + } ); + crate::instructions_test!( - float_mut; - data_listcontents; - @ super::Fields { - list: { - let list = crate::ir::RcList::new( - vec![], - &flags() - ).unwrap(); - *list.length_mutable().borrow_mut() = true; - list.add_type(IrType::Float); - list - }, + mod test_float_mut for data_listcontents { + fields = super::test::make_fields(true, IrType::Float, flags()); } ); + crate::instructions_test!( - string_mut; - data_listcontents; - @ super::Fields { - list: { - let list = crate::ir::RcList::new( - vec![crate::sb3::VarVal::String("hi".into())], - &flags() - ).unwrap(); - *list.length_mutable().borrow_mut() = true; - list.add_type(IrType::String); - list - }, + mod test_string_mut for data_listcontents { + fields = super::test::make_fields(true, IrType::String, flags()); } ); + crate::instructions_test!( - any_mut; - data_listcontents; - @ super::Fields { - list: { - let list = crate::ir::RcList::new( - vec![], - &flags() - ).unwrap(); - *list.length_mutable().borrow_mut() = true; - list.add_type(IrType::Any); - list - }, + mod test_any_mut for data_listcontents { + fields = super::test::make_fields(true, IrType::Any, flags()); } ); crate::instructions_test!( - int_static; - data_listcontents; - @ super::Fields { - list: { - let list = crate::ir::RcList::new( - vec![], - &flags() - ).unwrap(); - list.add_type(IrType::Int); - list - } - }; - { let mut flags = WasmFlags::new(unit_test_wasm_features()); flags.integers = Switch::On; flags } + mod test_int_static for data_listcontents { + fields = super::test::make_fields(false, IrType::Int, flags()); + flags = super::test::flags_with_integers(); + } ); crate::instructions_test!( - bool_static; - data_listcontents; - @ super::Fields { - list: { - let list = crate::ir::RcList::new( - vec![], - &flags() - ).unwrap(); - list.add_type(IrType::Boolean); - list - } - }; - { let mut flags = WasmFlags::new(unit_test_wasm_features()); flags.integers = Switch::On; flags } + mod test_bool_static for data_listcontents { + fields = super::test::make_fields(false, IrType::Boolean, flags()); + flags = super::test::flags_with_integers(); + } ); crate::instructions_test!( - float_static; - data_listcontents; - @ super::Fields { - list: { - let list = crate::ir::RcList::new( - vec![], - &flags() - ).unwrap(); - list.add_type(IrType::Float); - list - } + mod test_float_static for data_listcontents { + fields = super::test::make_fields(false, IrType::Float, flags()); } ); crate::instructions_test!( - string_static; - data_listcontents; - @ super::Fields { - list: { - let list = crate::ir::RcList::new( - vec![], - &flags() - ).unwrap(); - list.add_type(IrType::String); - list - } + mod test_string_static for data_listcontents { + fields = super::test::make_fields(false, IrType::String, flags()); } ); crate::instructions_test!( - any_static; - data_listcontents; - @ super::Fields { - list: { - let list = crate::ir::RcList::new( - vec![], - &flags() - ).unwrap(); - list.add_type(IrType::Any); - list - } + mod test_any_static for data_listcontents { + fields = super::test::make_fields(false, IrType::Any, flags()); } ); diff --git a/src/instructions/data/replaceitemoflist.rs b/src/instructions/data/replaceitemoflist.rs index 2b43546e..4b7e3254 100644 --- a/src/instructions/data/replaceitemoflist.rs +++ b/src/instructions/data/replaceitemoflist.rs @@ -94,125 +94,72 @@ pub const fn const_fold( Ok(NotFoldable) } +#[cfg(test)] +mod test { + pub use super::super::listcontents::test_utils::*; + use super::*; + use crate::instructions::tests::assert_valid_json; + use crate::wasm::WasmFlags; + + #[test] + fn fields_display_is_valid_json() { + let fields = make_fields(true, IrType::Any, flags_with_integers()); + assert_valid_json(format!("{fields}")); + } + + pub fn make_fields(mutable: bool, ty: IrType, flags: WasmFlags) -> Fields { + Fields { + list: make_list(mutable, ty, flags), + } + } +} + crate::instructions_test!( - int_mut; - data_replaceitemoflist; - t1, t2 @ super::Fields { - list: { - let list = crate::ir::RcList::new( - vec![], - &flags() - ).unwrap(); - *list.length_mutable().borrow_mut() = true; - list.add_type(IrType::Int); - list - }, - }; - { let mut flags = WasmFlags::new(unit_test_wasm_features()); flags.integers = Switch::On; flags } + mod test_int_mut for data_replaceitemoflist(t1, t2) { + fields = super::test::make_fields(true, IrType::Int, flags()); + flags = super::test::flags_with_integers(); + } ); + crate::instructions_test!( - float_mut; - data_replaceitemoflist; - t1, t2 @ super::Fields { - list: { - let list = crate::ir::RcList::new( - vec![], - &flags() - ).unwrap(); - *list.length_mutable().borrow_mut() = true; - list.add_type(IrType::Float); - list - }, + mod test_float_mut for data_replaceitemoflist(t1, t2) { + fields = super::test::make_fields(true, IrType::Float, flags()); } ); + crate::instructions_test!( - string_mut; - data_replaceitemoflist; - t1, t2 @ super::Fields { - list: { - let list = crate::ir::RcList::new( - vec![crate::sb3::VarVal::String("hi".into())], - &flags() - ).unwrap(); - *list.length_mutable().borrow_mut() = true; - list.add_type(IrType::String); - list - }, + mod test_string_mut for data_replaceitemoflist(t1, t2) { + fields = super::test::make_fields(true, IrType::String, flags()); } ); + crate::instructions_test!( - any_mut; - data_replaceitemoflist; - t1, t2 @ super::Fields { - list: { - let list = crate::ir::RcList::new( - vec![], - &flags() - ).unwrap(); - *list.length_mutable().borrow_mut() = true; - list.add_type(IrType::Any); - list - }, + mod test_any_mut for data_replaceitemoflist(t1, t2) { + fields = super::test::make_fields(true, IrType::Any, flags()); } ); crate::instructions_test!( - int_static; - data_replaceitemoflist; - t1, t2 @ super::Fields { - list: { - let list = crate::ir::RcList::new( - vec![], - &flags() - ).unwrap(); - list.add_type(IrType::Int); - list - } - }; - { let mut flags = WasmFlags::new(unit_test_wasm_features()); flags.integers = Switch::On; flags } + mod test_int_static for data_replaceitemoflist(t1, t2) { + fields = super::test::make_fields(false, IrType::Int, flags()); + flags = super::test::flags_with_integers(); + } ); crate::instructions_test!( - float_static; - data_replaceitemoflist; - t1, t2 @ super::Fields { - list: { - let list = crate::ir::RcList::new( - vec![], - &flags() - ).unwrap(); - list.add_type(IrType::Float); - list - } + mod test_float_static for data_replaceitemoflist(t1, t2) { + fields = super::test::make_fields(false, IrType::Float, flags()); } ); crate::instructions_test!( - string_static; - data_replaceitemoflist; - t1, t2 @ super::Fields { - list: { - let list = crate::ir::RcList::new( - vec![], - &flags() - ).unwrap(); - list.add_type(IrType::String); - list - } + mod test_string_static for data_replaceitemoflist(t1, t2) { + fields = super::test::make_fields(false, IrType::String, flags()); } ); crate::instructions_test!( - any_static; - data_replaceitemoflist; - t1, t2 @ super::Fields { - list: { - let list = crate::ir::RcList::new( - vec![], - &flags() - ).unwrap(); - list.add_type(IrType::Any); - list - } + mod test_any_static for data_replaceitemoflist(t1, t2) { + fields = super::test::make_fields(false, IrType::Any, flags()); } ); diff --git a/src/instructions/data/setvariableto.rs b/src/instructions/data/setvariableto.rs index 35b32ad0..10a4fa3d 100644 --- a/src/instructions/data/setvariableto.rs +++ b/src/instructions/data/setvariableto.rs @@ -136,122 +136,78 @@ pub fn const_fold( Ok(NotFoldable) } +#[cfg(test)] +mod test { + use super::super::variable::test_util::*; + use super::*; + use crate::instructions::tests::assert_valid_json; + use crate::wasm::WasmFlags; + use crate::wasm::flags::unit_test_wasm_features; + + #[test] + fn fields_display_is_valid_json() { + let fields = make_fields( + IrType::Any, + crate::sb3::VarVal::Float(0.0), + true, + WasmFlags::new(unit_test_wasm_features()), + ); + assert_valid_json(format!("{fields}")); + } + + pub fn make_fields(ty: IrType, initial: VarVal, local_write: bool, flags: WasmFlags) -> Fields { + Fields { + var: make_var(ty, initial, None, flags), + local_write: RefCell::new(local_write), + first_write: RefCell::new(false), + } + } +} + crate::instructions_test!( - any_global; - data_setvariableto; - t @ super::Fields { - var: RefCell::new( - crate::ir::RcVar::new( - IrType::Any, - &crate::sb3::VarVal::Float(0.0), - None, - &flags() - ).unwrap()), - local_write: RefCell::new(false), first_write: RefCell::new(false) + mod test_any_global for data_setvariableto(t) { + fields = super::test::make_fields(IrType::Any, crate::sb3::VarVal::Float(0.0), false, flags()); } ); crate::instructions_test!( - float_global; - data_setvariableto; - t @ super::Fields { - var: RefCell::new( - crate::ir::RcVar::new( - IrType::Float, - &crate::sb3::VarVal::Float(0.0), - None, - &flags() - ).unwrap()), - local_write: RefCell::new(false), first_write: RefCell::new(false) + mod test_float_global for data_setvariableto(t) { + fields = super::test::make_fields(IrType::Float, crate::sb3::VarVal::Float(0.0), false, flags()); } ); crate::instructions_test!( - string_global; - data_setvariableto; - t @ super::Fields { - var: RefCell::new( - crate::ir::RcVar::new( - IrType::String, - &crate::sb3::VarVal::String("".into()), - None, - &flags() - ).unwrap()), - local_write: RefCell::new(false), first_write: RefCell::new(false) + mod test_string_global for data_setvariableto(t) { + fields = super::test::make_fields(IrType::String, crate::sb3::VarVal::String("".into()), false, flags()); } ); crate::instructions_test!( - int_global; - data_setvariableto; - t @ super::Fields { - var: RefCell::new( - crate::ir::RcVar::new( - IrType::Int, - &crate::sb3::VarVal::Int(1), - None, - &flags() - ).unwrap()), - local_write: RefCell::new(false), first_write: RefCell::new(false) + mod test_int_global for data_setvariableto(t) { + fields = super::test::make_fields(IrType::Int, crate::sb3::VarVal::Int(0), false, flags()); } ); crate::instructions_test!( - any_local; - data_setvariableto; - t @ super::Fields { - var: RefCell::new( - crate::ir::RcVar::new( - IrType::Any, - &crate::sb3::VarVal::Float(0.0), - None, - &flags() - ).unwrap()), - local_write: RefCell::new(true), first_write: RefCell::new(false) + mod test_any_local for data_setvariableto(t) { + fields = super::test::make_fields(IrType::Any, crate::sb3::VarVal::Float(0.0), true, flags()); } ); crate::instructions_test!( - float_local; - data_setvariableto; - t @ super::Fields { - var: RefCell::new( - crate::ir::RcVar::new( - IrType::Float, - &crate::sb3::VarVal::Float(0.0), - None, - &flags() - ).unwrap()), - local_write: RefCell::new(true), first_write: RefCell::new(false) + mod test_float_local for data_setvariableto(t) { + fields = super::test::make_fields(IrType::Float, crate::sb3::VarVal::Float(0.0), true, flags()); } ); crate::instructions_test!( - string_local; - data_setvariableto; - t @ super::Fields { - var: RefCell::new( - crate::ir::RcVar::new( - IrType::String, - &crate::sb3::VarVal::String("".into()), - None, - &flags() - ).unwrap()), - local_write: RefCell::new(true), first_write: RefCell::new(false) + mod test_string_local for data_setvariableto(t) { + fields = super::test::make_fields(IrType::String, crate::sb3::VarVal::String("".into()), true, flags()); } ); crate::instructions_test!( - int_local; - data_setvariableto; - t @ super::Fields { - var: RefCell::new( - crate::ir::RcVar::new( - IrType::Int, - &crate::sb3::VarVal::Int(1), - None, - &flags() - ).unwrap()), - local_write: RefCell::new(true), first_write: RefCell::new(false) + mod test_int_local for data_setvariableto(t) { + fields = super::test::make_fields(IrType::Int, crate::sb3::VarVal::Int(0), true, flags()); } ); diff --git a/src/instructions/data/teevariable.rs b/src/instructions/data/teevariable.rs index 40d6418d..e9e30a17 100644 --- a/src/instructions/data/teevariable.rs +++ b/src/instructions/data/teevariable.rs @@ -135,136 +135,82 @@ pub fn const_fold( Ok(NotFoldable) } +#[cfg(test)] +mod test { + use super::super::variable::test_util::*; + use super::*; + use crate::instructions::tests::assert_valid_json; + use crate::wasm::WasmFlags; + use crate::wasm::flags::unit_test_wasm_features; + + #[test] + fn fields_display_is_valid_json() { + let fields = make_fields( + IrType::Any, + crate::sb3::VarVal::Float(0.0), + true, + WasmFlags::new(unit_test_wasm_features()), + ); + assert_valid_json(format!("{fields}")); + } + + pub fn make_fields( + ty: IrType, + initial: VarVal, + local_read_write: bool, + flags: WasmFlags, + ) -> Fields { + Fields { + var: make_var(ty, initial, None, flags), + local_read_write: RefCell::new(local_read_write), + } + } +} + crate::instructions_test!( - any_global; - data_teevariable; - t - @ super::Fields { - var: RefCell::new( - crate::ir::RcVar::new( - IrType::Any, - &crate::sb3::VarVal::Float(0.0), - None, - &flags() - ).unwrap()) - , - local_read_write: RefCell::new(false), + mod test_any_global for data_teevariable(t) { + fields = super::test::make_fields(IrType::Any, crate::sb3::VarVal::Float(0.0), false, flags()); } ); crate::instructions_test!( - float_global; - data_teevariable; - t - @ super::Fields { - var: RefCell::new( - crate::ir::RcVar::new( - IrType::Float, - &crate::sb3::VarVal::Float(0.0), - None, - &flags() - ).unwrap()) - , - local_read_write: RefCell::new(false), + mod test_float_global for data_teevariable(t) { + fields = super::test::make_fields(IrType::Float, crate::sb3::VarVal::Float(0.0), false, flags()); } ); crate::instructions_test!( - string_global; - data_teevariable; - t - @ super::Fields { - var: RefCell::new( - crate::ir::RcVar::new( - IrType::String, - &crate::sb3::VarVal::String("".into()), - None, - &flags() - ).unwrap()) - , - local_read_write: RefCell::new(false), + mod test_string_global for data_teevariable(t) { + fields = super::test::make_fields(IrType::String, crate::sb3::VarVal::String("".into()), false, flags()); } ); crate::instructions_test!( - int_global; - data_teevariable; - t - @ super::Fields { - var: RefCell::new( - crate::ir::RcVar::new( - IrType::Int, - &crate::sb3::VarVal::Int(1), - None, - &flags() - ).unwrap()) - , - local_read_write: RefCell::new(false), + mod test_int_global for data_teevariable(t) { + fields = super::test::make_fields(IrType::Int, crate::sb3::VarVal::Int(0), false, flags()); } ); crate::instructions_test!( - any_local; - data_teevariable; - t - @ super::Fields { - var: RefCell::new( - crate::ir::RcVar::new( - IrType::Any, - &crate::sb3::VarVal::Float(0.0), - None, - &flags() - ).unwrap() - ), - local_read_write: RefCell::new(true), + mod test_any_local for data_teevariable(t) { + fields = super::test::make_fields(IrType::Any, crate::sb3::VarVal::Float(0.0), true, flags()); } ); crate::instructions_test!( - float_local; - data_teevariable; - t - @ super::Fields { - var: RefCell::new( - crate::ir::RcVar::new( - IrType::Float, - &crate::sb3::VarVal::Float(0.0), - None, - &flags() - ).unwrap() - ), - local_read_write: RefCell::new(true), + mod test_float_local for data_teevariable(t) { + fields = super::test::make_fields(IrType::Float, crate::sb3::VarVal::Float(0.0), true, flags()); } ); crate::instructions_test!( - string_local; - data_teevariable; - t - @ super::Fields { - var: RefCell::new( - crate::ir::RcVar::new( - IrType::String, - &crate::sb3::VarVal::String("".into()), - None, - &flags() - ).unwrap()), - local_read_write: RefCell::new(true), + mod test_string_local for data_teevariable(t) { + fields = super::test::make_fields(IrType::String, crate::sb3::VarVal::String("".into()), true, flags()); } ); crate::instructions_test!( - int_local; - data_teevariable; - t - @ super::Fields { - var: RefCell::new( - crate::ir::RcVar::new( - IrType::Int, - &crate::sb3::VarVal::Int(1), - None, - &flags() - ).unwrap()), - local_read_write: RefCell::new(true), + mod test_int_local for data_teevariable(t) { + fields = super::test::make_fields(IrType::Int, crate::sb3::VarVal::Int(0), true, flags()); } ); diff --git a/src/instructions/data/variable.rs b/src/instructions/data/variable.rs index 1c622dac..486e991b 100644 --- a/src/instructions/data/variable.rs +++ b/src/instructions/data/variable.rs @@ -76,141 +76,94 @@ pub fn const_fold( } } +#[cfg(test)] +pub mod test_util { + use super::*; + use crate::ir::{IrMonitor, RcVar}; + use crate::wasm::WasmFlags; + + pub fn make_var( + ty: IrType, + initial: crate::sb3::VarVal, + monitor: Option, + flags: WasmFlags, + ) -> RefCell { + RefCell::new(crate::ir::RcVar::new(ty, &initial, monitor, &flags).unwrap()) + } +} + +#[cfg(test)] +mod test { + use test_util::*; + + use super::*; + use crate::instructions::tests::assert_valid_json; + use crate::wasm::WasmFlags; + use crate::wasm::flags::unit_test_wasm_features; + + #[test] + fn fields_display_is_valid_json() { + let fields = make_fields( + IrType::Any, + crate::sb3::VarVal::Float(0.0), + true, + WasmFlags::new(unit_test_wasm_features()), + ); + assert_valid_json(format!("{fields}")); + } + + pub fn make_fields(ty: IrType, initial: VarVal, local_read: bool, flags: WasmFlags) -> Fields { + Fields { + var: make_var(ty, initial, None, flags), + local_read: RefCell::new(local_read), + } + } +} + crate::instructions_test!( - any_global; - data_variable; - @ super::Fields { - var: RefCell::new - ( - crate::ir::RcVar::new( - IrType::Any, - &crate::sb3::VarVal::Float(0.0), - None, - &flags() - ).unwrap() - ) - , - local_read: RefCell::new(false) + mod test_any_global for data_variable { + fields = super::test::make_fields(IrType::Any, crate::sb3::VarVal::Float(0.0), false, flags()); } ); crate::instructions_test!( - float_global; - data_variable; - @ super::Fields { - var: RefCell::new( - crate::ir::RcVar::new( - IrType::Float, - &crate::sb3::VarVal::Float(0.0), - None, - &flags() - ).unwrap() - ), - local_read: RefCell::new(false) + mod test_float_global for data_variable { + fields = super::test::make_fields(IrType::Float, crate::sb3::VarVal::Float(0.0), false, flags()); } ); crate::instructions_test!( - string_global; - data_variable; - @ super::Fields { - var: RefCell::new - ( - crate::ir::RcVar::new( - IrType::String, - &crate::sb3::VarVal::String("".into()), - None, - &flags() - ).unwrap() - ) - , - local_read: RefCell::new(false) + mod test_string_global for data_variable { + fields = super::test::make_fields(IrType::String, crate::sb3::VarVal::String("".into()), false, flags()); } ); crate::instructions_test!( - int_global; - data_variable; - @ super::Fields { - var: RefCell::new - ( - crate::ir::RcVar::new( - IrType::Int, - &crate::sb3::VarVal::Int(1), - None, - &flags() - ).unwrap() - ) - , - local_read: RefCell::new(false) + mod test_int_global for data_variable { + fields = super::test::make_fields(IrType::Int, crate::sb3::VarVal::Int(0), false, flags()); } ); crate::instructions_test!( - any_local; - data_variable; - @ super::Fields { - var: RefCell::new - ( - crate::ir::RcVar::new( - IrType::Any, - &crate::sb3::VarVal::Float(0.0), - None, - &flags() - ).unwrap() - ) - , - local_read: RefCell::new(true) + mod test_any_local for data_variable { + fields = super::test::make_fields(IrType::Any, crate::sb3::VarVal::Float(0.0), true, flags()); } ); crate::instructions_test!( - float_local; - data_variable; - @ super::Fields { - var: RefCell::new - ( - crate::ir::RcVar::new( - IrType::Float, - &crate::sb3::VarVal::Float(0.0), - None, - &flags() - ).unwrap() - ) - , - local_read: RefCell::new(true) + mod test_float_local for data_variable { + fields = super::test::make_fields(IrType::Float, crate::sb3::VarVal::Float(0.0), true, flags()); } ); crate::instructions_test!( - string_local; - data_variable; - @ super::Fields { - var: RefCell::new( - crate::ir::RcVar::new( - IrType::String, - &crate::sb3::VarVal::String("".into()), - None, - &flags() - ).unwrap() - - ), - local_read: RefCell::new(true) + mod test_string_local for data_variable { + fields = super::test::make_fields(IrType::String, crate::sb3::VarVal::String("".into()), true, flags()); } ); crate::instructions_test!( - int_local; - data_variable; - @ super::Fields { - var: RefCell::new( - crate::ir::RcVar::new( - IrType::Int, - &crate::sb3::VarVal::Int(1), - None, - &flags() - ).unwrap() - ), - local_read: RefCell::new(true) + mod test_int_local for data_variable { + fields = super::test::make_fields(IrType::Int, crate::sb3::VarVal::Int(0), true, flags()); } ); diff --git a/src/instructions/data/visvariable.rs b/src/instructions/data/visvariable.rs index 012ce495..014a7280 100644 --- a/src/instructions/data/visvariable.rs +++ b/src/instructions/data/visvariable.rs @@ -69,21 +69,38 @@ pub const fn const_fold( Ok(NotFoldable) } +#[cfg(test)] +mod test { + use super::super::variable::test_util::*; + use super::*; + use crate::instructions::tests::assert_valid_json; + use crate::wasm::WasmFlags; + use crate::wasm::flags::unit_test_wasm_features; + + #[test] + fn fields_display_is_valid_json() { + let fields = make_fields(WasmFlags::new(unit_test_wasm_features())); + assert_valid_json(format!("{fields}")); + } + + pub fn make_fields(flags: WasmFlags) -> Fields { + Fields { + var: make_var( + IrType::Any, + crate::sb3::VarVal::Float(0.0), + Some(crate::ir::IrMonitor { + id: "".into(), + is_ever_visible: RefCell::new(true), + }), + flags, + ), + visible: true, + } + } +} + crate::instructions_test!( - test; - data_visvariable; - @ super::Fields { - var: RefCell::new( - crate::ir::RcVar::new( - IrType::Any, - &crate::sb3::VarVal::Float(0.0), - Some(crate::ir::IrMonitor { - id: "".into(), - is_ever_visible: RefCell::new(true,) - }), - &flags() - ).unwrap()) - , - visible: true + mod test2 for data_visvariable { + fields = super::test::make_fields(flags()); } ); diff --git a/src/instructions/event/broadcast.rs b/src/instructions/event/broadcast.rs index fba38342..32aa9752 100644 --- a/src/instructions/event/broadcast.rs +++ b/src/instructions/event/broadcast.rs @@ -1,4 +1,5 @@ use super::super::prelude::*; +use crate::instructions_test; use crate::wasm::StepFunc; #[derive(Clone, Debug)] @@ -9,7 +10,7 @@ impl fmt::Display for Fields { write!( f, r#"{{ - "broadcast": "{:}", + "broadcast": "{:}" }}"#, self.0 ) @@ -43,3 +44,25 @@ pub const fn const_fold( ) -> HQResult { Ok(NotFoldable) } + +#[cfg(test)] +mod test { + use super::*; + use crate::instructions::tests::assert_valid_json; + + #[test] + fn fields_display_is_valid_json() { + let fields = make_fields(); + assert_valid_json(format!("{fields}")); + } + + pub fn make_fields() -> Fields { + Fields("".into()) + } +} + +instructions_test!( + mod test2 for event_broadcast { + fields = super::test::make_fields(); + } +); diff --git a/src/instructions/event/broadcast_and_wait.rs b/src/instructions/event/broadcast_and_wait.rs index f222da93..3923b3fc 100644 --- a/src/instructions/event/broadcast_and_wait.rs +++ b/src/instructions/event/broadcast_and_wait.rs @@ -1,6 +1,7 @@ use wasm_encoder::{HeapType, StorageType}; use super::super::prelude::*; +use crate::instructions_test; use crate::ir::StepIndex; use crate::wasm::StepFunc; @@ -67,3 +68,45 @@ pub const fn const_fold( ) -> HQResult { Ok(NotFoldable) } + +#[cfg(test)] +mod test { + use super::*; + use crate::instructions::tests::assert_valid_json; + use crate::wasm::registries::TypeRegistry; + use crate::wasm::{StepTarget, WasmFlags, WasmProject}; + + #[test] + fn fields_display_is_valid_json() { + let fields = make_fields(); + assert_valid_json(format!("{fields}")); + } + + pub fn make_fields() -> Fields { + Fields { + broadcast: "".into(), + poll_step: StepIndex(0), + next_step: StepIndex(0), + } + } + + pub fn setup_project(wasm_proj: &WasmProject, flags: WasmFlags) { + let step_func = StepFunc::new_with_types( + Box::from([ValType::I32, TypeRegistry::STRUCT_REF]), + Box::from([]), + wasm_proj.registries(), + flags, + StepTarget::Sprite(0), + 0, + Rc::new(vec![]), + ); + wasm_proj.steps().borrow_mut().push(step_func); + } +} + +instructions_test!( + mod test2 for event_broadcast_and_wait { + fields = super::test::make_fields(); + setup = super::test::setup_project; + } +); diff --git a/src/instructions/hq/boolean.rs b/src/instructions/hq/boolean.rs index 2a1dd1f6..584419eb 100644 --- a/src/instructions/hq/boolean.rs +++ b/src/instructions/hq/boolean.rs @@ -52,5 +52,25 @@ pub fn const_fold( )]))) } -crate::instructions_test! {tests_false; hq_boolean; @ super::Fields(false)} -crate::instructions_test! {tests_true; hq_boolean; @ super::Fields(true)} +#[cfg(test)] +mod tests { + use super::*; + use crate::instructions::tests::assert_valid_json; + + #[test] + fn fields_display_is_valid_json() { + assert_valid_json(format!("{}", Fields(true))); + } +} + +crate::instructions_test! ( + mod tests_false for hq_boolean { + fields = super::Fields(false); + } +); + +crate::instructions_test! ( + mod tests_true for hq_boolean { + fields = super::Fields(true); + } +); diff --git a/src/instructions/hq/box.rs b/src/instructions/hq/box.rs index 23def6c3..ad14493b 100644 --- a/src/instructions/hq/box.rs +++ b/src/instructions/hq/box.rs @@ -53,4 +53,24 @@ pub fn const_fold( }) } -crate::instructions_test! {tests; hq_box; t @ super::Fields { output_ty: IrType::Any }} +#[cfg(test)] +mod test { + use super::*; + use crate::instructions::tests::assert_valid_json; + + #[test] + fn fields_display_is_valid_json() { + assert_valid_json(format!( + "{}", + Fields { + output_ty: IrType::Any, + } + )); + } +} + +crate::instructions_test! ( + mod tests for hq_box(t) { + fields = super::Fields { output_ty: IrType::Any }; + } +); diff --git a/src/instructions/hq/cast.rs b/src/instructions/hq/cast.rs index af04f297..ce84a4bc 100644 --- a/src/instructions/hq/cast.rs +++ b/src/instructions/hq/cast.rs @@ -346,7 +346,37 @@ pub fn const_fold( }) } -crate::instructions_test! {float; hq_cast; t @ super::Fields(IrType::Float)} -crate::instructions_test! {string; hq_cast; t @ super::Fields(IrType::String)} -crate::instructions_test! {int; hq_cast; t @ super::Fields(IrType::Int)} -crate::instructions_test! {boolean; hq_cast; t @ super::Fields(IrType::Boolean)} +#[cfg(test)] +mod test { + use super::*; + use crate::instructions::tests::assert_valid_json; + + #[test] + fn fields_display_is_valid_json() { + assert_valid_json(format!("{}", Fields(IrType::Float))); + } +} + +crate::instructions_test! ( + mod test_float for hq_cast(t) { + fields = super::Fields(IrType::Float); + } +); + +crate::instructions_test! ( + mod test_string for hq_cast(t) { + fields = super::Fields(IrType::String); + } +); + +crate::instructions_test! ( + mod test_int for hq_cast(t) { + fields = super::Fields(IrType::Int); + } +); + +crate::instructions_test! ( + mod test_boolean for hq_cast(t) { + fields = super::Fields(IrType::Boolean); + } +); diff --git a/src/instructions/hq/color_rgb.rs b/src/instructions/hq/color_rgb.rs index e8e1b3d3..89bbebfa 100644 --- a/src/instructions/hq/color_rgb.rs +++ b/src/instructions/hq/color_rgb.rs @@ -54,4 +54,19 @@ pub const fn const_fold( Ok(NotFoldable) } -crate::instructions_test! {tests; hq_color_rgb; @ super::Fields { r: 134, g: 56, b: 109 }} +#[cfg(test)] +mod test { + use super::*; + use crate::instructions::tests::assert_valid_json; + + #[test] + fn fields_display_is_valid_json() { + assert_valid_json(format!("{}", Fields { r: 1, g: 2, b: 3 })); + } +} + +crate::instructions_test! ( + mod tests for hq_color_rgb { + fields = super::Fields { r: 134, g: 56, b: 109 }; + } +); diff --git a/src/instructions/hq/drop.rs b/src/instructions/hq/drop.rs index 17feaa94..88f44195 100644 --- a/src/instructions/hq/drop.rs +++ b/src/instructions/hq/drop.rs @@ -18,4 +18,6 @@ pub fn const_fold(_inputs: &[ConstFoldItem], _state: &mut ConstFoldState) -> HQR Ok(ConstFold::Folded(Rc::from([]))) } -crate::instructions_test! {tests; hq_drop; t} +crate::instructions_test! ( + mod tests for hq_drop(t) {} +); diff --git a/src/instructions/hq/dup.rs b/src/instructions/hq/dup.rs index f5bbed5a..7f3458c4 100644 --- a/src/instructions/hq/dup.rs +++ b/src/instructions/hq/dup.rs @@ -24,4 +24,6 @@ pub const fn const_fold( Ok(NotFoldable) } -crate::instructions_test! {tests; hq_dup; t} +crate::instructions_test! ( + mod tests for hq_dup(t) {} +); diff --git a/src/instructions/hq/float.rs b/src/instructions/hq/float.rs index 48a93e0e..e35b3508 100644 --- a/src/instructions/hq/float.rs +++ b/src/instructions/hq/float.rs @@ -58,4 +58,19 @@ pub fn const_fold( )]))) } -crate::instructions_test! {tests; hq_float; @ super::Fields(0.0)} +#[cfg(test)] +mod test { + use super::*; + use crate::instructions::tests::assert_valid_json; + + #[test] + fn fields_display_is_valid_json() { + assert_valid_json(format!("{}", Fields(0.0))); + } +} + +crate::instructions_test! ( + mod tests for hq_float { + fields = super::Fields(0.0); + } +); diff --git a/src/instructions/hq/integer.rs b/src/instructions/hq/integer.rs index efe0639f..88534486 100644 --- a/src/instructions/hq/integer.rs +++ b/src/instructions/hq/integer.rs @@ -53,4 +53,19 @@ pub fn const_fold( )]))) } -crate::instructions_test! {tests; hq_integer; @ super::Fields(0)} +#[cfg(test)] +mod test { + use super::*; + use crate::instructions::tests::assert_valid_json; + + #[test] + fn fields_display_is_valid_json() { + assert_valid_json(format!("{}", Fields(0))); + } +} + +crate::instructions_test! ( + mod tests for hq_integer { + fields = super::Fields(0); + } +); diff --git a/src/instructions/hq/swap.rs b/src/instructions/hq/swap.rs index 97854c83..8eb951ca 100644 --- a/src/instructions/hq/swap.rs +++ b/src/instructions/hq/swap.rs @@ -32,4 +32,6 @@ pub const fn const_fold( Ok(NotFoldable) } -crate::instructions_test! {tests; hq_swap; t1, t2} +crate::instructions_test! ( + mod tests for hq_swap(t1, t2) {} +); diff --git a/src/instructions/hq/text.rs b/src/instructions/hq/text.rs index 48d2f5c2..6d03b6aa 100644 --- a/src/instructions/hq/text.rs +++ b/src/instructions/hq/text.rs @@ -60,4 +60,19 @@ pub fn const_fold( )]))) } -crate::instructions_test! {tests; hq_text; @ super::Fields("hello, world!".into())} +#[cfg(test)] +mod test { + use super::*; + use crate::instructions::tests::assert_valid_json; + + #[test] + fn fields_display_is_valid_json() { + assert_valid_json(format!("{}", Fields("".into()))); + } +} + +crate::instructions_test! ( + mod tests for hq_text { + fields = super::Fields("hello, world!".into()); + } +); diff --git a/src/instructions/hq/yield.rs b/src/instructions/hq/yield.rs index 790c4e8b..6f04d8de 100644 --- a/src/instructions/hq/yield.rs +++ b/src/instructions/hq/yield.rs @@ -1,6 +1,7 @@ use wasm_encoder::{BlockType, ConstExpr, HeapType}; use super::super::prelude::*; +use crate::instructions_test; use crate::ir::{Step, StepIndex}; use crate::wasm::{GlobalExportable, GlobalMutable, StepFunc, ThreadsTable}; @@ -193,30 +194,67 @@ pub const fn const_fold( Ok(NotFoldable) } -crate::instructions_test! {none; hq_yield; @ super::Fields { mode: super::YieldMode::None }} - -crate::instructions_test! {ret; hq_yield; @ super::Fields { mode: super::YieldMode::Return }} - -// crate::instructions_test! { -// schedule; -// hq_yield; -// @ super::Fields { -// mode: super::YieldMode::Schedule( -// crate::rc::Rc::downgrade(&crate::ir::Step::new_empty( -// &crate::rc::Rc::downgrade(&Rc::new(crate::ir::IrProject::new(BTreeMap::default(), BTreeMap::default(), Box::from([])))), -// true, -// Rc::new( -// crate::ir::Target::new( -// false, -// BTreeMap::default(), -// BTreeMap::default(), -// crate::rc::Rc::downgrade(&Rc::new(crate::ir::IrProject::new(BTreeMap::default(), BTreeMap::default(), Box::from([])))), -// RefCell::default(), -// 0, -// Box::from([]) -// ) -// ) -// ).unwrap()) -// ) -// } -// } +#[cfg(test)] +mod test { + use super::super::super::tests::*; + use super::*; + use crate::instructions::tests::assert_valid_json; + + #[test] + fn fields_display_is_valid_json() { + let target = make_target(); + for mode in [ + YieldMode::None, + YieldMode::Return, + make_schedule(), + YieldMode::Inline(Rc::new(RefCell::new(Step::new_empty( + Weak::new(), + false, + target, + )))), + ] { + assert_valid_json(format!("{}", Fields { mode })); + } + } + + pub fn make_schedule() -> YieldMode { + YieldMode::Schedule(StepIndex(0)) + } + + pub fn make_inline() -> YieldMode { + let target = make_target(); + YieldMode::Inline(Rc::new(RefCell::new(Step::new_empty( + Weak::new(), + false, + target, + )))) + } +} + +instructions_test! ( + mod test_none for hq_yield { + fields = super::Fields { mode: super::YieldMode::None }; + } +); + +instructions_test! ( + mod test_return for hq_yield { + fields = super::Fields { mode: super::YieldMode::Return }; + } +); + +instructions_test! ( + mod test_schedule for hq_yield { + fields = super::Fields { + mode: super::test::make_schedule() + }; + } +); + +instructions_test!( + mod test_inline for hq_yield { + fields = super::Fields { + mode: super::test::make_inline() + }; + } +); diff --git a/src/instructions/looks/backdropnumber.rs b/src/instructions/looks/backdropnumber.rs index fb677d80..e5c01fb2 100644 --- a/src/instructions/looks/backdropnumber.rs +++ b/src/instructions/looks/backdropnumber.rs @@ -33,4 +33,6 @@ pub const fn const_fold( Ok(NotFoldable) } -crate::instructions_test! {tests; looks_backdropnumber; ; } +crate::instructions_test! ( + mod tests for looks_backdropnumber {} +); diff --git a/src/instructions/looks/costumename.rs b/src/instructions/looks/costumename.rs index 266be5d5..57ecc9a3 100644 --- a/src/instructions/looks/costumename.rs +++ b/src/instructions/looks/costumename.rs @@ -64,4 +64,6 @@ pub const fn const_fold( Ok(NotFoldable) } -// crate::instructions_test! {tests; looks_costumename; ; } +crate::instructions_test! ( + mod tests for looks_costumename {} +); diff --git a/src/instructions/looks/costumenumber.rs b/src/instructions/looks/costumenumber.rs index b4f75e00..68fe3020 100644 --- a/src/instructions/looks/costumenumber.rs +++ b/src/instructions/looks/costumenumber.rs @@ -39,4 +39,6 @@ pub const fn const_fold( Ok(NotFoldable) } -crate::instructions_test! {tests; looks_costumenumber; ; } +crate::instructions_test! ( + mod tests for looks_costumenumber {} +); diff --git a/src/instructions/looks/say.rs b/src/instructions/looks/say.rs index 43d8ba9f..db940437 100644 --- a/src/instructions/looks/say.rs +++ b/src/instructions/looks/say.rs @@ -96,5 +96,30 @@ pub const fn const_fold( Ok(NotFoldable) } -crate::instructions_test! {tests_debug; looks_say; t @ super::Fields { debug: true, target_idx: 0 }} -crate::instructions_test! {tests_non_debug; looks_say; t @ super::Fields { debug: false, target_idx: 0, }} +#[cfg(test)] +mod test { + use super::*; + use crate::instructions::tests::assert_valid_json; + + #[test] + fn fields_display_is_valid_json() { + assert_valid_json(format!( + "{}", + Fields { + debug: false, + target_idx: 0 + } + )); + } +} + +crate::instructions_test! ( + mod tests_debug for looks_say(t) { + fields = super::Fields { debug: true, target_idx: 0 }; + } +); +crate::instructions_test! ( + mod tests_non_debug for looks_say(t) { + fields = super::Fields { debug: false, target_idx: 0, }; + } +); diff --git a/src/instructions/looks/setsizeto.rs b/src/instructions/looks/setsizeto.rs index 56bf24e5..28488252 100644 --- a/src/instructions/looks/setsizeto.rs +++ b/src/instructions/looks/setsizeto.rs @@ -55,4 +55,6 @@ pub const fn const_fold( Ok(NotFoldable) } -crate::instructions_test! {tests; looks_setsizeto; t ; } +crate::instructions_test! ( + mod tests for looks_setsizeto(t) {} +); diff --git a/src/instructions/looks/setvisible.rs b/src/instructions/looks/setvisible.rs index 23689dd5..8ddd8a0e 100644 --- a/src/instructions/looks/setvisible.rs +++ b/src/instructions/looks/setvisible.rs @@ -52,4 +52,6 @@ pub const fn const_fold( Ok(NotFoldable) } -crate::instructions_test! {tests; looks_setvisible; t ; } +crate::instructions_test! ( + mod tests for looks_setvisible(t) {} +); diff --git a/src/instructions/looks/size.rs b/src/instructions/looks/size.rs index 92baba17..4184ce2b 100644 --- a/src/instructions/looks/size.rs +++ b/src/instructions/looks/size.rs @@ -37,4 +37,6 @@ pub const fn const_fold( Ok(NotFoldable) } -crate::instructions_test! {tests; looks_size; ; } +crate::instructions_test! ( + mod tests for looks_size {} +); diff --git a/src/instructions/looks/switchbackdropto.rs b/src/instructions/looks/switchbackdropto.rs index 84ab68eb..821e7464 100644 --- a/src/instructions/looks/switchbackdropto.rs +++ b/src/instructions/looks/switchbackdropto.rs @@ -64,4 +64,6 @@ pub const fn const_fold( Ok(NotFoldable) } -crate::instructions_test! {tests; looks_switchbackdropto; t ; } +crate::instructions_test! ( + mod tests for looks_switchbackdropto(t) {} +); diff --git a/src/instructions/looks/switchcostumeto.rs b/src/instructions/looks/switchcostumeto.rs index 3795d50c..bce84e18 100644 --- a/src/instructions/looks/switchcostumeto.rs +++ b/src/instructions/looks/switchcostumeto.rs @@ -76,4 +76,6 @@ pub const fn const_fold( Ok(NotFoldable) } -crate::instructions_test! {tests; looks_switchcostumeto; t ; } +crate::instructions_test! ( + mod tests for looks_switchcostumeto(t) {} +); diff --git a/src/instructions/looks/think.rs b/src/instructions/looks/think.rs index d4eb8726..8edf9975 100644 --- a/src/instructions/looks/think.rs +++ b/src/instructions/looks/think.rs @@ -96,5 +96,30 @@ pub const fn const_fold( Ok(NotFoldable) } -crate::instructions_test! {tests_debug; looks_think; t @ super::Fields { debug: true, target_idx: 0 }} -crate::instructions_test! {tests_non_debug; looks_think; t @ super::Fields { debug: false, target_idx: 0, }} +#[cfg(test)] +mod test { + use super::*; + use crate::instructions::tests::assert_valid_json; + + #[test] + fn fields_display_is_valid_json() { + assert_valid_json(format!( + "{}", + Fields { + debug: false, + target_idx: 0 + } + )); + } +} + +crate::instructions_test! ( + mod tests_debug for looks_think(t) { + fields = super::Fields { debug: true, target_idx: 0 }; + } +); +crate::instructions_test! ( + mod tests_non_debug for looks_think(t) { + fields = super::Fields { debug: false, target_idx: 0, }; + } +); diff --git a/src/instructions/motion/direction.rs b/src/instructions/motion/direction.rs index a6102437..828eefe5 100644 --- a/src/instructions/motion/direction.rs +++ b/src/instructions/motion/direction.rs @@ -38,4 +38,6 @@ pub const fn const_fold( Ok(NotFoldable) } -crate::instructions_test! {tests; motion_direction; } +crate::instructions_test! ( + mod tests for motion_direction {} +); diff --git a/src/instructions/motion/gotoxy.rs b/src/instructions/motion/gotoxy.rs index 937b4718..5f29c7f8 100644 --- a/src/instructions/motion/gotoxy.rs +++ b/src/instructions/motion/gotoxy.rs @@ -161,4 +161,6 @@ pub const fn const_fold( Ok(NotFoldable) } -crate::instructions_test! {tests; motion_gotoxy; t1, t2 ; } +crate::instructions_test! ( + mod tests for motion_gotoxy(t1,t2) {} +); diff --git a/src/instructions/motion/pointindirection.rs b/src/instructions/motion/pointindirection.rs index e21ce3c8..9b07dbe8 100644 --- a/src/instructions/motion/pointindirection.rs +++ b/src/instructions/motion/pointindirection.rs @@ -56,4 +56,6 @@ pub const fn const_fold( Ok(NotFoldable) } -crate::instructions_test! {tests; motion_pointindirection; t } +crate::instructions_test! ( + mod tests for motion_pointindirection(t) {} +); diff --git a/src/instructions/motion/setx.rs b/src/instructions/motion/setx.rs index d9995fc7..1590505c 100644 --- a/src/instructions/motion/setx.rs +++ b/src/instructions/motion/setx.rs @@ -170,4 +170,6 @@ pub const fn const_fold( Ok(NotFoldable) } -crate::instructions_test! {tests; motion_setx; t ; } +crate::instructions_test! ( + mod tests for motion_setx(t) {} +); diff --git a/src/instructions/motion/sety.rs b/src/instructions/motion/sety.rs index aa4eeed6..72a759bd 100644 --- a/src/instructions/motion/sety.rs +++ b/src/instructions/motion/sety.rs @@ -170,4 +170,6 @@ pub const fn const_fold( Ok(NotFoldable) } -crate::instructions_test! {tests; motion_setx; t ; } +crate::instructions_test! ( + mod tests for motion_setx(t) {} +); diff --git a/src/instructions/motion/xposition.rs b/src/instructions/motion/xposition.rs index fc260381..cee4ae65 100644 --- a/src/instructions/motion/xposition.rs +++ b/src/instructions/motion/xposition.rs @@ -38,4 +38,6 @@ pub const fn const_fold( Ok(NotFoldable) } -crate::instructions_test! {tests; motion_xposition; } +crate::instructions_test! ( + mod tests for motion_xposition {} +); diff --git a/src/instructions/motion/yposition.rs b/src/instructions/motion/yposition.rs index 5d77a6e4..602c2424 100644 --- a/src/instructions/motion/yposition.rs +++ b/src/instructions/motion/yposition.rs @@ -38,4 +38,6 @@ pub const fn const_fold( Ok(NotFoldable) } -crate::instructions_test! {tests; motion_yposition; } +crate::instructions_test! ( + mod tests for motion_yposition {} +); diff --git a/src/instructions/operator/abs.rs b/src/instructions/operator/abs.rs index c95a98e8..9774abb8 100644 --- a/src/instructions/operator/abs.rs +++ b/src/instructions/operator/abs.rs @@ -74,4 +74,6 @@ pub const fn const_fold( Ok(NotFoldable) } -crate::instructions_test! {tests; operator_abs; t } +crate::instructions_test! ( + mod tests for operator_abs(t) {} +); diff --git a/src/instructions/operator/acos.rs b/src/instructions/operator/acos.rs index d86015ef..82ebad96 100644 --- a/src/instructions/operator/acos.rs +++ b/src/instructions/operator/acos.rs @@ -34,4 +34,6 @@ pub const fn const_fold( Ok(NotFoldable) } -crate::instructions_test! {tests; operator_acos; t } +crate::instructions_test! ( + mod tests for operator_acos(t) {} +); diff --git a/src/instructions/operator/add.rs b/src/instructions/operator/add.rs index 32e2a35c..008f01f7 100644 --- a/src/instructions/operator/add.rs +++ b/src/instructions/operator/add.rs @@ -86,4 +86,6 @@ pub const fn const_fold( Ok(NotFoldable) } -crate::instructions_test! {tests; operator_add; t1, t2 ;} +crate::instructions_test! ( + mod tests for operator_add(t1,t2) {} +); diff --git a/src/instructions/operator/and.rs b/src/instructions/operator/and.rs index 64a5bdd7..531ac111 100644 --- a/src/instructions/operator/and.rs +++ b/src/instructions/operator/and.rs @@ -21,4 +21,6 @@ pub const fn const_fold( Ok(NotFoldable) } -crate::instructions_test! {tests; operator_and; t1, t2 ;} +crate::instructions_test! ( + mod tests for operator_and(t1,t2) {} +); diff --git a/src/instructions/operator/asin.rs b/src/instructions/operator/asin.rs index 3f5fd9ef..272eb7b0 100644 --- a/src/instructions/operator/asin.rs +++ b/src/instructions/operator/asin.rs @@ -34,4 +34,6 @@ pub const fn const_fold( Ok(NotFoldable) } -crate::instructions_test! {tests; operator_asin; t } +crate::instructions_test! ( + mod tests for operator_asin(t) {} +); diff --git a/src/instructions/operator/atan.rs b/src/instructions/operator/atan.rs index 83b3b3cb..8160665a 100644 --- a/src/instructions/operator/atan.rs +++ b/src/instructions/operator/atan.rs @@ -34,4 +34,6 @@ pub const fn const_fold( Ok(NotFoldable) } -crate::instructions_test! {tests; operator_atan; t } +crate::instructions_test! ( + mod tests for operator_atan(t) {} +); diff --git a/src/instructions/operator/ceiling.rs b/src/instructions/operator/ceiling.rs index 9a6193c4..915d723d 100644 --- a/src/instructions/operator/ceiling.rs +++ b/src/instructions/operator/ceiling.rs @@ -61,4 +61,6 @@ pub const fn const_fold( Ok(NotFoldable) } -crate::instructions_test! {tests; operator_ceiling; t } +crate::instructions_test! ( + mod tests for operator_ceiling(t) {} +); diff --git a/src/instructions/operator/contains.rs b/src/instructions/operator/contains.rs index ce351ea3..1da4264d 100644 --- a/src/instructions/operator/contains.rs +++ b/src/instructions/operator/contains.rs @@ -29,4 +29,6 @@ pub const fn const_fold( Ok(NotFoldable) } -crate::instructions_test! {tests; operator_contains; t1, t2 ;} +crate::instructions_test! ( + mod tests for operator_contains(t1,t2) {} +); diff --git a/src/instructions/operator/cos.rs b/src/instructions/operator/cos.rs index e597c175..854786cf 100644 --- a/src/instructions/operator/cos.rs +++ b/src/instructions/operator/cos.rs @@ -41,4 +41,6 @@ pub const fn const_fold( Ok(NotFoldable) } -crate::instructions_test! {tests; operator_cos; t } +crate::instructions_test! ( + mod tests for operator_cos(t) {} +); diff --git a/src/instructions/operator/divide.rs b/src/instructions/operator/divide.rs index 3c1d73bf..8cb5d559 100644 --- a/src/instructions/operator/divide.rs +++ b/src/instructions/operator/divide.rs @@ -50,4 +50,6 @@ pub const fn const_fold( Ok(NotFoldable) } -crate::instructions_test! {tests; operator_divide; t1, t2 ;} +crate::instructions_test! ( + mod tests for operator_divide(t1,t2) {} +); diff --git a/src/instructions/operator/equals.rs b/src/instructions/operator/equals.rs index a72e59f3..d9c68156 100644 --- a/src/instructions/operator/equals.rs +++ b/src/instructions/operator/equals.rs @@ -400,4 +400,6 @@ pub const fn const_fold( Ok(NotFoldable) } -crate::instructions_test! {tests; operator_equals; t1, t2 ;} +crate::instructions_test! ( + mod tests for operator_equals(t1,t2) {} +); diff --git a/src/instructions/operator/exp.rs b/src/instructions/operator/exp.rs index 6b97ce37..ce96e0de 100644 --- a/src/instructions/operator/exp.rs +++ b/src/instructions/operator/exp.rs @@ -38,4 +38,6 @@ pub const fn const_fold( Ok(NotFoldable) } -crate::instructions_test! {tests; operator_exp; t } +crate::instructions_test! ( + mod tests for operator_exp(t) {} +); diff --git a/src/instructions/operator/floor.rs b/src/instructions/operator/floor.rs index 627f54de..390e7e10 100644 --- a/src/instructions/operator/floor.rs +++ b/src/instructions/operator/floor.rs @@ -61,4 +61,6 @@ pub const fn const_fold( Ok(NotFoldable) } -crate::instructions_test! {tests; operator_floor; t } +crate::instructions_test! ( + mod tests for operator_floor(t) {} +); diff --git a/src/instructions/operator/gt.rs b/src/instructions/operator/gt.rs index 3efa060c..5528e052 100644 --- a/src/instructions/operator/gt.rs +++ b/src/instructions/operator/gt.rs @@ -326,4 +326,6 @@ pub fn const_fold(inputs: &[ConstFoldItem], _state: &mut ConstFoldState) -> HQRe ) } -crate::instructions_test! {tests; operator_lt; t1, t2 ;} +crate::instructions_test! ( + mod tests for operator_lt(t1,t2) {} +); diff --git a/src/instructions/operator/join.rs b/src/instructions/operator/join.rs index b18fbafc..6e39d57d 100644 --- a/src/instructions/operator/join.rs +++ b/src/instructions/operator/join.rs @@ -34,4 +34,6 @@ pub const fn const_fold( Ok(NotFoldable) } -crate::instructions_test! {tests; operator_join; t1, t2 ;} +crate::instructions_test! ( + mod tests for operator_join(t1,t2) {} +); diff --git a/src/instructions/operator/length.rs b/src/instructions/operator/length.rs index 8e2b5587..4821fe3b 100644 --- a/src/instructions/operator/length.rs +++ b/src/instructions/operator/length.rs @@ -26,4 +26,6 @@ pub const fn const_fold( Ok(NotFoldable) } -crate::instructions_test! {tests; operator_length; t ;} +crate::instructions_test! ( + mod tests for operator_length(t) {} +); diff --git a/src/instructions/operator/letter_of.rs b/src/instructions/operator/letter_of.rs index 75f68257..912900e2 100644 --- a/src/instructions/operator/letter_of.rs +++ b/src/instructions/operator/letter_of.rs @@ -47,4 +47,6 @@ pub const fn const_fold( Ok(NotFoldable) } -crate::instructions_test! {tests; operator_letter_of; t1, t2 ;} +crate::instructions_test! ( + mod tests for operator_letter_of(t1,t2) {} +); diff --git a/src/instructions/operator/ln.rs b/src/instructions/operator/ln.rs index e1767e46..e02fb6d0 100644 --- a/src/instructions/operator/ln.rs +++ b/src/instructions/operator/ln.rs @@ -42,4 +42,6 @@ pub const fn const_fold( Ok(NotFoldable) } -crate::instructions_test! {tests; operator_ln; t } +crate::instructions_test! ( + mod tests for operator_ln(t) {} +); diff --git a/src/instructions/operator/log.rs b/src/instructions/operator/log.rs index 6bd87020..47dbfb7c 100644 --- a/src/instructions/operator/log.rs +++ b/src/instructions/operator/log.rs @@ -40,4 +40,6 @@ pub const fn const_fold( Ok(NotFoldable) } -crate::instructions_test! {tests; operator_log; t } +crate::instructions_test! ( + mod tests for operator_log(t) {} +); diff --git a/src/instructions/operator/lt.rs b/src/instructions/operator/lt.rs index 2ee40276..b90a2343 100644 --- a/src/instructions/operator/lt.rs +++ b/src/instructions/operator/lt.rs @@ -287,4 +287,6 @@ pub const fn const_fold( Ok(NotFoldable) } -crate::instructions_test! {tests; operator_lt; t1, t2 ;} +crate::instructions_test! ( + mod tests for operator_lt(t1,t2) {} +); diff --git a/src/instructions/operator/modulo.rs b/src/instructions/operator/modulo.rs index 1d1fcf8d..8a09a785 100644 --- a/src/instructions/operator/modulo.rs +++ b/src/instructions/operator/modulo.rs @@ -187,4 +187,6 @@ pub const fn const_fold( Ok(NotFoldable) } -crate::instructions_test! {tests; operator_modulo; t1, t2 ;} +crate::instructions_test! ( + mod tests for operator_modulo(t1,t2) {} +); diff --git a/src/instructions/operator/multiply.rs b/src/instructions/operator/multiply.rs index 4f200c68..4a05770f 100644 --- a/src/instructions/operator/multiply.rs +++ b/src/instructions/operator/multiply.rs @@ -90,4 +90,6 @@ pub const fn const_fold( Ok(NotFoldable) } -crate::instructions_test! {tests; operator_multiply; t1, t2 ;} +crate::instructions_test! ( + mod tests for operator_multiply(t1,t2) {} +); diff --git a/src/instructions/operator/not.rs b/src/instructions/operator/not.rs index 5db046b4..7e325d24 100644 --- a/src/instructions/operator/not.rs +++ b/src/instructions/operator/not.rs @@ -21,4 +21,6 @@ pub const fn const_fold( Ok(NotFoldable) } -crate::instructions_test! {tests; operator_not; t ;} +crate::instructions_test! ( + mod tests for operator_not(t) {} +); diff --git a/src/instructions/operator/or.rs b/src/instructions/operator/or.rs index 46d68965..85082323 100644 --- a/src/instructions/operator/or.rs +++ b/src/instructions/operator/or.rs @@ -21,4 +21,6 @@ pub const fn const_fold( Ok(NotFoldable) } -crate::instructions_test! {tests; operator_or; t1, t2 ;} +crate::instructions_test! ( + mod tests for operator_or(t1,t2) {} +); diff --git a/src/instructions/operator/pow10.rs b/src/instructions/operator/pow10.rs index fa63ec59..32a74862 100644 --- a/src/instructions/operator/pow10.rs +++ b/src/instructions/operator/pow10.rs @@ -38,4 +38,6 @@ pub const fn const_fold( Ok(NotFoldable) } -crate::instructions_test! {tests; operator_pow10; t } +crate::instructions_test! ( + mod tests for operator_pow10(t) {} +); diff --git a/src/instructions/operator/random.rs b/src/instructions/operator/random.rs index cf7e984f..f8177954 100644 --- a/src/instructions/operator/random.rs +++ b/src/instructions/operator/random.rs @@ -193,4 +193,6 @@ pub const fn const_fold( Ok(NotFoldable) } -crate::instructions_test! {tests; operator_random; t1, t2 ;} +crate::instructions_test! ( + mod tests for operator_random(t1,t2) {} +); diff --git a/src/instructions/operator/round.rs b/src/instructions/operator/round.rs index 5f2c297a..00668df6 100644 --- a/src/instructions/operator/round.rs +++ b/src/instructions/operator/round.rs @@ -38,4 +38,6 @@ pub const fn const_fold( Ok(NotFoldable) } -crate::instructions_test! {tests; operator_round; t } +crate::instructions_test! ( + mod tests for operator_round(t) {} +); diff --git a/src/instructions/operator/sin.rs b/src/instructions/operator/sin.rs index 6690f514..20a982a6 100644 --- a/src/instructions/operator/sin.rs +++ b/src/instructions/operator/sin.rs @@ -41,4 +41,6 @@ pub const fn const_fold( Ok(NotFoldable) } -crate::instructions_test! {tests; operator_sin; t } +crate::instructions_test! ( + mod tests for operator_sin(t) {} +); diff --git a/src/instructions/operator/sqrt.rs b/src/instructions/operator/sqrt.rs index 55fe0820..b2be43ed 100644 --- a/src/instructions/operator/sqrt.rs +++ b/src/instructions/operator/sqrt.rs @@ -32,4 +32,6 @@ pub const fn const_fold( Ok(NotFoldable) } -crate::instructions_test! {tests; operator_sqrt; t } +crate::instructions_test! ( + mod tests for operator_sqrt(t) {} +); diff --git a/src/instructions/operator/subtract.rs b/src/instructions/operator/subtract.rs index ae139110..45e21c4c 100644 --- a/src/instructions/operator/subtract.rs +++ b/src/instructions/operator/subtract.rs @@ -88,4 +88,6 @@ pub const fn const_fold( Ok(NotFoldable) } -crate::instructions_test! {tests; operator_subtract; t1, t2 ;} +crate::instructions_test! ( + mod tests for operator_subtract(t1,t2) {} +); diff --git a/src/instructions/operator/tan.rs b/src/instructions/operator/tan.rs index e2eca02f..98194225 100644 --- a/src/instructions/operator/tan.rs +++ b/src/instructions/operator/tan.rs @@ -38,4 +38,6 @@ pub const fn const_fold( Ok(NotFoldable) } -crate::instructions_test! {tests; operator_tan; t } +crate::instructions_test! ( + mod tests for operator_tan(t) {} +); diff --git a/src/instructions/pen/changecolorparamby.rs b/src/instructions/pen/changecolorparamby.rs index ad890996..f6596c60 100644 --- a/src/instructions/pen/changecolorparamby.rs +++ b/src/instructions/pen/changecolorparamby.rs @@ -147,4 +147,6 @@ pub const fn const_fold( Ok(NotFoldable) } -crate::instructions_test! {tests_colour; pen_changecolorparamby; t1, t2 } +crate::instructions_test! ( + mod tests_colour for pen_changecolorparamby(t1,t2) {} +); diff --git a/src/instructions/pen/clear.rs b/src/instructions/pen/clear.rs index 9ca24e01..afbf0b2e 100644 --- a/src/instructions/pen/clear.rs +++ b/src/instructions/pen/clear.rs @@ -25,4 +25,6 @@ pub const fn const_fold( Ok(NotFoldable) } -crate::instructions_test! {tests; pen_clear; ; } +crate::instructions_test! ( + mod tests for pen_clear {} +); diff --git a/src/instructions/pen/pendown.rs b/src/instructions/pen/pendown.rs index c5b1ad20..7a5b1ad2 100644 --- a/src/instructions/pen/pendown.rs +++ b/src/instructions/pen/pendown.rs @@ -95,4 +95,6 @@ pub const fn const_fold( Ok(NotFoldable) } -crate::instructions_test! {tests; pen_pendown; ; } +crate::instructions_test! ( + mod tests for pen_pendown {} +); diff --git a/src/instructions/pen/penup.rs b/src/instructions/pen/penup.rs index 30e4b88c..1f62b673 100644 --- a/src/instructions/pen/penup.rs +++ b/src/instructions/pen/penup.rs @@ -37,4 +37,6 @@ pub const fn const_fold( Ok(NotFoldable) } -crate::instructions_test! {tests; pen_penup; ; } +crate::instructions_test! ( + mod tests for pen_penup {} +); diff --git a/src/instructions/pen/setpencolorparamto.rs b/src/instructions/pen/setpencolorparamto.rs index 38b09457..9dc3cd92 100644 --- a/src/instructions/pen/setpencolorparamto.rs +++ b/src/instructions/pen/setpencolorparamto.rs @@ -119,4 +119,6 @@ pub const fn const_fold( Ok(NotFoldable) } -crate::instructions_test! {tests_colour; pen_setpencolorparamto; t1, t2 } +crate::instructions_test! ( + mod tests_colour for pen_setpencolorparamto(t1,t2) {} +); diff --git a/src/instructions/pen/setpencolortocolor.rs b/src/instructions/pen/setpencolortocolor.rs index 7dd9f7ec..12450fd4 100644 --- a/src/instructions/pen/setpencolortocolor.rs +++ b/src/instructions/pen/setpencolortocolor.rs @@ -122,4 +122,6 @@ pub const fn const_fold( Ok(NotFoldable) } -crate::instructions_test! {tests; pen_setpencolortocolor; t ; } +crate::instructions_test! ( + mod tests for pen_setpencolortocolor(t) {} +); diff --git a/src/instructions/pen/setpensizeto.rs b/src/instructions/pen/setpensizeto.rs index c1d553b0..3442e323 100644 --- a/src/instructions/pen/setpensizeto.rs +++ b/src/instructions/pen/setpensizeto.rs @@ -44,4 +44,6 @@ pub const fn const_fold( Ok(NotFoldable) } -crate::instructions_test! {tests; pen_setpensizeto; t ; } +crate::instructions_test! ( + mod tests for pen_setpensizeto(t) {} +); diff --git a/src/instructions/procedures/argument.rs b/src/instructions/procedures/argument.rs index 3b4dd5d7..be757b32 100644 --- a/src/instructions/procedures/argument.rs +++ b/src/instructions/procedures/argument.rs @@ -37,7 +37,6 @@ pub fn wasm( arg_vars, }: &Fields, ) -> HQResult> { - #[expect(clippy::redundant_else, reason = "false positive")] if *in_warped { hq_assert!( WasmProject::ir_type_to_wasm(*arg_var.possible_types()) @@ -118,3 +117,27 @@ pub const fn const_fold( ) -> HQResult { Ok(NotFoldable) } + +#[cfg(test)] +mod test { + use super::super::super::tests::*; + use super::*; + use crate::wasm::WasmFlags; + use crate::wasm::flags::unit_test_wasm_features; + + #[test] + fn fields_display_is_valid_json() { + let fields = make_fields(true, WasmFlags::new(unit_test_wasm_features())); + assert_valid_json(format!("{fields}")); + } + + pub fn make_fields(in_warped: bool, flags: WasmFlags) -> Fields { + let var = RcVar::new(IrType::Any, &VarVal::Float(0.0), None, &flags).unwrap(); + Fields { + index: 0, + arg_var: var.clone(), + in_warped, + arg_vars: Rc::new(RefCell::new(vec![var])), + } + } +} diff --git a/src/instructions/procedures/call_nonwarp.rs b/src/instructions/procedures/call_nonwarp.rs index 869f805d..54347734 100644 --- a/src/instructions/procedures/call_nonwarp.rs +++ b/src/instructions/procedures/call_nonwarp.rs @@ -1,6 +1,7 @@ use wasm_encoder::{FieldType, HeapType, Instruction as WInstruction, StorageType}; use super::super::prelude::*; +use crate::instructions_test; use crate::ir::{Proc, StepIndex}; use crate::wasm::registries::functions::static_functions::SpawnThreadInStack; use crate::wasm::{StepFunc, WasmProject}; @@ -133,3 +134,77 @@ pub const fn const_fold( ) -> HQResult { Ok(NotFoldable) } + +#[cfg(test)] +mod test { + use super::super::super::tests::*; + use super::*; + use crate::ir::{PartialStep, StepIndex}; + + #[test] + fn fields_display_is_valid_json() { + let fields = make_fields(2); + assert_valid_json(format!("{fields}")); + } + + pub fn test_project_setup(wasm_proj: &WasmProject, flags: crate::wasm::WasmFlags) { + let proc_step_func = StepFunc::new_with_types( + Box::from([ + ValType::I32, + crate::wasm::registries::TypeRegistry::STRUCT_REF, + ]), + vec![].into(), + Rc::clone(&wasm_proj.registries()), + flags, + crate::wasm::StepTarget::Sprite(0), + 0, + Rc::new(vec![]), + ); + wasm_proj.steps().borrow_mut().push(proc_step_func); + } + + pub fn make_fields(num_inputs: usize) -> super::Fields { + super::Fields { + proc: { + let target = make_target(); + let proc = Rc::new(super::Proc::new( + format!("foo {}", core::iter::repeat_n("%s", num_inputs).join(" ")).into(), + RefCell::new(None), + RefCell::new(None), + None, + false, + Box::new([]), + Box::new([]), + Rc::clone(&target), + false, + )); + let specific_proc = proc.new_specific_proc(); + *specific_proc.first_step_mut() = PartialStep::Finished(StepIndex(0)); + *proc.nonwarped_specific_proc_mut() = Some(specific_proc); + proc + }, + next_step: super::StepIndex(0), + } + } +} + +instructions_test!( + mod test_nullary for procedures_call_nonwarp { + fields = super::test::make_fields(0); + setup = super::test::test_project_setup; + } +); + +instructions_test!( + mod test_unary for procedures_call_nonwarp(t) { + fields = super::test::make_fields(1); + setup = super::test::test_project_setup; + } +); + +instructions_test!( + mod test_ternary for procedures_call_nonwarp(t1, t2, t3) { + fields = super::test::make_fields(3); + setup = super::test::test_project_setup; + } +); diff --git a/src/instructions/procedures/call_warp.rs b/src/instructions/procedures/call_warp.rs index ae6e2a3b..d5579f8f 100644 --- a/src/instructions/procedures/call_warp.rs +++ b/src/instructions/procedures/call_warp.rs @@ -1,6 +1,7 @@ use wasm_encoder::Instruction as WInstruction; use super::super::prelude::*; +use crate::instructions_test; use crate::ir::Proc; use crate::wasm::{StepFunc, WasmProject}; @@ -105,3 +106,105 @@ pub const fn const_fold( ) -> HQResult { Ok(NotFoldable) } + +#[cfg(test)] +mod test { + use super::super::super::tests::*; + use super::*; + use crate::ir::{PartialStep, StepIndex}; + + #[test] + fn fields_display_is_valid_json() { + let fields = make_fields(&[IrType::Any]); + assert_valid_json(format!("{fields}")); + } + + pub fn test_project_setup( + wasm_proj: &WasmProject, + flags: crate::wasm::WasmFlags, + inputs: &[IrType], + ) { + let proc_step_func = StepFunc::new_with_types( + inputs + .iter() + .map(|ty| WasmProject::ir_type_to_wasm(*ty)) + .chain([ + ValType::I32, + crate::wasm::registries::TypeRegistry::STRUCT_REF, + ]) + .collect(), + vec![].into(), + Rc::clone(&wasm_proj.registries()), + flags, + crate::wasm::StepTarget::Sprite(0), + 0, + Rc::new(vec![]), + ); + wasm_proj.steps().borrow_mut().push(proc_step_func); + } + + pub fn make_fields(inputs: &[IrType]) -> super::Fields { + super::Fields { + proc: { + let target = make_target(); + let proc = Rc::new(super::Proc::new( + format!("foo {}", core::iter::repeat_n("%s", inputs.len()).join(" ")).into(), + RefCell::new(None), + RefCell::new(None), + None, + false, + Box::new([]), + Box::new([]), + Rc::clone(&target), + false, + )); + let specific_proc = proc.new_specific_proc(); + *specific_proc.first_step_mut() = PartialStep::Finished(StepIndex(0)); + *proc.warped_specific_proc_mut() = Some(specific_proc); + proc + }, + } + } +} + +instructions_test!( + mod test_nullary for procedures_call_warp { + fields = super::test::make_fields(&[]); + setup = |proj, flags| super::test::test_project_setup(proj, flags, &[]); + } +); + +instructions_test!( + mod test_unary_string for procedures_call_warp(t) { + fields = super::test::make_fields(&[IrType::String]); + setup = |proj, flags| super::test::test_project_setup(proj, flags, &[IrType::String]); + } +); + +instructions_test!( + mod test_unary_int for procedures_call_warp(t) { + fields = super::test::make_fields(&[IrType::Int]); + setup = |proj, flags| super::test::test_project_setup(proj, flags, &[IrType::Int]); + } +); + +instructions_test!( + mod test_unary_float for procedures_call_warp(t) { + fields = super::test::make_fields(&[IrType::Float]); + setup = |proj, flags| super::test::test_project_setup(proj, flags, &[IrType::Float]); + } +); + +instructions_test!( + mod test_unary_bool for procedures_call_warp(t) { + fields = super::test::make_fields(&[IrType::Boolean]); + setup = |proj, flags| super::test::test_project_setup(proj, flags, &[IrType::Boolean]); + } +); + +instructions_test!( + mod test_unary_any for procedures_call_warp(t) { + fields = super::test::make_fields(&[IrType::Any]); + setup = |proj, flags| super::test::test_project_setup(proj, flags, &[IrType::Any]); + } +); diff --git a/src/instructions/sensing/answer.rs b/src/instructions/sensing/answer.rs index e8827639..2e3eb28a 100644 --- a/src/instructions/sensing/answer.rs +++ b/src/instructions/sensing/answer.rs @@ -36,4 +36,6 @@ pub const fn const_fold( Ok(NotFoldable) } -crate::instructions_test! {tests; sensing_answer; ;} +crate::instructions_test! ( + mod tests for sensing_answer {} +); diff --git a/src/instructions/sensing/askandwait.rs b/src/instructions/sensing/askandwait.rs index 7547a44f..5c2f4a95 100644 --- a/src/instructions/sensing/askandwait.rs +++ b/src/instructions/sensing/askandwait.rs @@ -93,7 +93,43 @@ pub const fn const_fold( Ok(NotFoldable) } -// crate::instructions_test! { tests; sensing_askandwait; t @ super::Fields { -// poll_step: super::StepIndex(0), -// next_step: super::StepIndex(0), -// }} +#[cfg(test)] +mod test { + use super::super::super::tests::*; + use super::*; + use crate::wasm::registries::TypeRegistry; + use crate::wasm::{StepTarget, WasmFlags, WasmProject}; + + #[test] + fn fields_display_is_valid_json() { + let fields = make_fields(); + assert_valid_json(format!("{fields}")); + } + + pub fn make_fields() -> Fields { + Fields { + poll_step: StepIndex(0), + next_step: StepIndex(0), + } + } + + pub fn setup_project(wasm_proj: &WasmProject, flags: WasmFlags) { + let step_func = StepFunc::new_with_types( + Box::from([ValType::I32, TypeRegistry::STRUCT_REF]), + Box::from([]), + wasm_proj.registries(), + flags, + StepTarget::Sprite(0), + 0, + Rc::new(vec![]), + ); + wasm_proj.steps().borrow_mut().push(step_func); + } +} + +crate::instructions_test! ( + mod tests for sensing_askandwait(t) { + fields = super::test::make_fields(); + setup = super::test::setup_project; + } +); diff --git a/src/instructions/sensing/dayssince2000.rs b/src/instructions/sensing/dayssince2000.rs index 3cfdace0..906e5430 100644 --- a/src/instructions/sensing/dayssince2000.rs +++ b/src/instructions/sensing/dayssince2000.rs @@ -26,4 +26,6 @@ pub const fn const_fold( Ok(NotFoldable) } -crate::instructions_test! {tests; sensing_dayssince2000; ;} +crate::instructions_test! ( + mod tests for sensing_dayssince2000 {} +); diff --git a/src/instructions/sensing/keypressed.rs b/src/instructions/sensing/keypressed.rs index b0fb0bc9..5822d5c1 100644 --- a/src/instructions/sensing/keypressed.rs +++ b/src/instructions/sensing/keypressed.rs @@ -25,4 +25,6 @@ pub const fn const_fold( Ok(NotFoldable) } -crate::instructions_test! {tests; sensing_keypressed; t ;} +crate::instructions_test! ( + mod tests for sensing_keypressed(t) {} +); diff --git a/src/instructions/sensing/mousedown.rs b/src/instructions/sensing/mousedown.rs index f6c46e82..a849edc1 100644 --- a/src/instructions/sensing/mousedown.rs +++ b/src/instructions/sensing/mousedown.rs @@ -35,4 +35,6 @@ pub const fn const_fold( Ok(NotFoldable) } -crate::instructions_test! {tests; sensing_mousedown; ;} +crate::instructions_test! ( + mod tests for sensing_mousedown {} +); diff --git a/src/instructions/sensing/mousex.rs b/src/instructions/sensing/mousex.rs index 3b738091..83cd8140 100644 --- a/src/instructions/sensing/mousex.rs +++ b/src/instructions/sensing/mousex.rs @@ -35,4 +35,6 @@ pub const fn const_fold( Ok(NotFoldable) } -crate::instructions_test! {tests; sensing_mousex; ;} +crate::instructions_test! ( + mod tests for sensing_mousex {} +); diff --git a/src/instructions/sensing/mousey.rs b/src/instructions/sensing/mousey.rs index 9272fbdc..bc14f835 100644 --- a/src/instructions/sensing/mousey.rs +++ b/src/instructions/sensing/mousey.rs @@ -35,4 +35,6 @@ pub const fn const_fold( Ok(NotFoldable) } -crate::instructions_test! {tests; sensing_mousey; ;} +crate::instructions_test! ( + mod tests for sensing_mousey {} +); diff --git a/src/instructions/sensing/reset_timer.rs b/src/instructions/sensing/reset_timer.rs index d280533e..91cfb86f 100644 --- a/src/instructions/sensing/reset_timer.rs +++ b/src/instructions/sensing/reset_timer.rs @@ -36,4 +36,6 @@ pub const fn const_fold( Ok(NotFoldable) } -crate::instructions_test! {tests; sensing_reset_timer; ;} +crate::instructions_test! ( + mod tests for sensing_reset_timer {} +); diff --git a/src/instructions/sensing/timer.rs b/src/instructions/sensing/timer.rs index ff42f6e9..3b08246c 100644 --- a/src/instructions/sensing/timer.rs +++ b/src/instructions/sensing/timer.rs @@ -35,4 +35,6 @@ pub const fn const_fold( Ok(NotFoldable) } -crate::instructions_test! {tests; sensing_timer; ;} +crate::instructions_test! ( + mod tests for sensing_timer {} +); diff --git a/src/instructions/tests.rs b/src/instructions/tests.rs index 2c93e17f..00cd5a7d 100644 --- a/src/instructions/tests.rs +++ b/src/instructions/tests.rs @@ -1,52 +1,60 @@ /// Generates unit tests for instructions files. /// -/// Takes a module name, followed by a semicolon, -/// collowed by the full name of the opcode (in the form of `_`), followed by an optional -/// comma-separated list of arbitrary identifiers corresponding to the number of inputs the block -/// takes, optionally followed by a semicolon and an expression for a sensible default for any fields, -/// optionally followed by a semicolon and a `WasmFlags` configuration (defaults to `Default::default()`). -/// If multiple field values or flags configurations need to be tested, the macro can be repeated with -/// different module names. +/// For a block `peppa_pig` which takes 0 inputs, +/// ```ignore +/// instructions_test!(mod test for peppa_pig {}); +/// ``` /// /// Example: /// For a block `foo_bar`, which takes 2 inputs, with Fields(bool), /// ```ignore -/// instructions_test!(test; foo_bar; t1, t2 @ super::Fields(true)); -/// instructions_test!(test; foo_bar; t1, t2 @ super::Fields(false)); +/// instructions_test!(mod test_true for foo_bar(t1, t2) { +/// fields = super::Fields(true); +/// }); +/// instructions_test!(mod test_false for foo_bar(t1, t2) { +/// fields = super::Fields(false); +/// }); /// ``` #[macro_export] macro_rules! instructions_test { - {$module:ident; $opcode:ident; $($type_arg:ident $(,)?)* $(@$fields:expr)? $(;)?} => { - $crate::instructions_test!{$module; $opcode; $($type_arg,)* $(@$fields)? ; WasmFlags::new(unit_test_wasm_features())} - }; - {$module:ident; $opcode:ident; $($type_arg:ident $(,)?)* $(@ $fields:expr)? ; $flags:expr} => { + { + mod $module:ident for $opcode:ident$(($($type_arg:ident $(,)?)*))? { + $(fields = $fields:expr;)? + $(flags = $flags:expr;)? + $(setup = $setup:expr;)? + } + } => { #[cfg(test)] mod $module { - fn flags() -> $crate::wasm::WasmFlags { - $flags - } + #![expect(clippy::allow_attributes, reason = "might not always trigger")] - use super::{wasm, output_type, acceptable_inputs}; + use super::{output_type, acceptable_inputs}; use $crate::prelude::*; - use $crate::ir::{IrType, ReturnType}; - use wasm_encoder::ValType; - use $crate::wasm::{StepFunc, Registries, WasmProject, WasmFlags, StepTarget, ExternalEnvironment}; - #[expect(clippy::allow_attributes, reason = "might not always trigger")] + use $crate::ir::IrType; + use $crate::instructions::IrOpcode; + use $crate::wasm::{StepFunc, Registries, WasmProject, WasmFlags, StepTarget, ExternalEnvironment, InternalInstruction}; #[allow(unused, reason = "it might not be unused")] use $crate::wasm::flags::{Switch, unit_test_wasm_features}; - #[expect(clippy::allow_attributes, reason = "might not always trigger")] + fn flags() -> $crate::wasm::WasmFlags { + #[allow(unused_mut, reason = "may not be unused")] + #[allow(unused_assignments, reason = "may not be unused")] + let mut flags = WasmFlags::new(unit_test_wasm_features()); + $(flags = $flags;)? + flags + } + #[allow(unused_macros, reason = "it is not unused")] macro_rules! ident_as_irtype { ( $_:ident ) => { IrType }; } - fn types_iter(base_only: bool) -> impl Iterator { + fn types_iter(base_only: bool) -> impl Iterator { // we need to collect this iterator into a Vec because it doesn't implement clone for some reason, // which makes itertools angry - $(let $type_arg = IrType::flags().map(|(_, ty)| *ty).collect::>();)* - itertools::iproduct!($($type_arg,)*).filter(move |($($type_arg,)*)| { - let types: &[&IrType] = &[$($type_arg,)*]; + $($(let $type_arg = IrType::flags().map(|(_, ty)| *ty).collect::>();)*)? + itertools::iproduct!($($($type_arg,)*)?).filter(move |($($($type_arg,)*)?)| { + let types: &[&IrType] = &[$($($type_arg,)*)?]; for (i, input) in (*types).into_iter().enumerate() { // non-base types should be handled and unboxed by a wrapper function // contained in src/instructions/input_switcher.rs @@ -65,136 +73,60 @@ macro_rules! instructions_test { #[test] fn output_type_fails_when_wasm_fails() { - for ($($type_arg,)*) in types_iter(true) { - let output_type_result = output_type(Rc::from([$($type_arg,)*]), $(&$fields)?); + for ($($($type_arg,)*)?) in types_iter(true) { + let types = &[$($($type_arg,)*)?]; + #[allow(unused_mut, reason = "may not be unused")] + #[allow(unused, reason = "might not be unused")] + let mut proj = WasmProject::new(flags(), ExternalEnvironment::WebBrowser, vec![vec!["".into()]]); + $($setup(&mut proj, flags());)? + let output_type_result = output_type(types.clone().into(), $(&$fields)?); let registries = Rc::new(Registries::default()); - let step_func = StepFunc::new(Rc::clone(®istries), flags(), StepTarget::Sprite(0), 0, Rc::new(vec![])); - let wasm_result = wasm(&step_func, Rc::from([$($type_arg,)*]), $(&$fields)?); + let step_func = StepFunc::new(Rc::clone(®istries), flags(), StepTarget::Sprite(0), 0, Rc::clone(proj.costume_names())); + let wasm_result = wasm(&step_func, types); match (output_type_result.clone(), wasm_result.clone()) { - (Err(..), Ok(..)) | (Ok(..), Err(..)) => panic!("output_type result doesn't match wasm result for type(s) {:?}:\noutput_type: {:?},\nwasm: {:?}", ($($type_arg,)*), output_type_result, wasm_result), + (Err(..), Ok(..)) | (Ok(..), Err(..)) => panic!("output_type result doesn't match wasm result for type(s) {:?}:\noutput_type: {:?},\nwasm: {:?}", ($($($type_arg,)*)?), output_type_result, wasm_result), (Err(HQError { err_type: e1, .. }), Err(HQError { err_type: e2, .. })) if e1 != e2 => { - panic!("output_type result doesn't match wasm result for type(s) {:?}:\noutput_type: {:?},\nwasm: {:?}", ($($type_arg,)*), output_type_result, wasm_result); + panic!("output_type result doesn't match wasm result for type(s) {:?}:\noutput_type: {:?},\nwasm: {:?}", ($($($type_arg,)*)?), output_type_result, wasm_result); } _ => (), } } } - #[test] - fn wasm_output_type_matches_expected_output_type() -> HQResult<()> { - for ($($type_arg,)*) in types_iter(true) { - - let Ok(output_type) = output_type(Rc::from([$($type_arg,)*]), $(&$fields)?) else { - println!("skipping failed output_type"); - continue; - }; - let proj = WasmProject::new(flags(), ExternalEnvironment::WebBrowser); - let registries = proj.registries(); - let types: &[IrType] = &[$($type_arg,)*]; - let params = [ValType::I32, $crate::wasm::registries::TypeRegistry::STRUCT_REF].into_iter().chain([$($type_arg,)*].into_iter().map(WasmProject::ir_type_to_wasm)).collect::>(); - let result = match output_type { - ReturnType::Singleton(output) => vec![WasmProject::ir_type_to_wasm(output)], - ReturnType::MultiValue(outputs) => outputs.iter().copied().map(WasmProject::ir_type_to_wasm).collect(), - ReturnType::None => vec![], - }; - let step_func = StepFunc::new_with_types(params.into(), result.into(), Rc::clone(®istries), flags(), StepTarget::Sprite(0), 0, Rc::new(vec![])); - let Ok(wasm) = wasm(&step_func, Rc::from([$($type_arg,)*]), $(&$fields)?) else { - println!("skipping failed wasm"); - continue; - }; - for (i, _) in types.iter().enumerate() { - step_func.add_instructions([$crate::wasm::InternalInstruction::Immediate(wasm_encoder::Instruction::LocalGet((i + 2).try_into().unwrap()))])? - } - step_func.add_instructions(wasm)?; - - proj.steps() - .borrow_mut() - .push(step_func); - - let wasm_bytes = proj.finish().unwrap().wasm_bytes; + fn wasm(step_func: &StepFunc, types: &[IrType]) -> HQResult> { + super::wasm(step_func, types.clone().into(), $(&$fields)?) + } - println!("{}", wasmprinter::print_bytes(wasm_bytes.clone()).unwrap()); - wasmparser::validate(&wasm_bytes).map_err(|err| make_hq_bug!("invalid wasm module with types {:?}. Original error message: {}", ($($type_arg,)*), err.message()))?; + #[test] + fn wasm_output_type_matches_expected_output_type() -> HQResult<()> { + for ($($($type_arg,)*)?) in types_iter(true) { + let types: &[IrType] = &[$($($type_arg,)*)?]; + #[allow(unused_mut, reason = "may not be unused")] + let mut proj = WasmProject::new(flags(), ExternalEnvironment::WebBrowser, vec![vec!["".into()]]); + $($setup(&mut proj, flags());)? + let output_type2 = || output_type(Rc::from([$($($type_arg,)*)?]), $(&$fields)?); + $crate::instructions::tests::wasm_output_type_matches_expected_output_type(proj, types, output_type2, wasm, flags())?; } Ok(()) } + fn wrap_instructions(step_func: &StepFunc, types: &[IrType], opcodes: Vec) -> HQResult> { + $crate::instructions::wrap_instructions(step_func, types.clone().into(), &opcodes) + } + #[test] fn wasm_output_type_matches_wrapped_expected_output_type() -> HQResult<()> { - for ($($type_arg,)*) in types_iter(false) { - let Ok(output_type) = $crate::instructions::boxed_output_type( + for ($($($type_arg,)*)?) in types_iter(false) { + let types: &[IrType] = &[$($($type_arg,)*)?]; + #[allow(unused_mut, reason = "may not be unused")] + let mut proj = WasmProject::new(flags(), ExternalEnvironment::WebBrowser, vec![vec!["".into()]]); + $($setup(&mut proj, flags());)? + let output_type2 = || $crate::instructions::boxed_output_type( |inputs| output_type(inputs, $(&$fields)?), - Rc::from([$($type_arg,)*]), - ) else { - println!("skipping failed output_type"); - continue; - }; - println!("{output_type:?}"); - let proj = WasmProject::new(flags(), ExternalEnvironment::WebBrowser); - let registries = proj.registries(); - let types: &[IrType] = &[$($type_arg,)*]; - let params = [ValType::I32, $crate::wasm::registries::TypeRegistry::STRUCT_REF] - .into_iter() - .chain( - [$($type_arg,)*] - .into_iter() - .map(WasmProject::ir_type_to_wasm) - ) - .collect::>(); - let result = vec![]; - let step_func = StepFunc::new_with_types( - params.into(), - result.into(), - Rc::clone(®istries), - flags(), - StepTarget::Sprite(0), - 0, - Rc::new(vec![]) + types.clone().into(), ); - let drops = match output_type { - ReturnType::Singleton(_) => 1, - ReturnType::MultiValue(outs) => outs.len(), - ReturnType::None => 0, - }; - let test_opcodes = [$crate::instructions::IrOpcode::$opcode$(($fields))?] - .into_iter() - .chain(core::iter::repeat_n($crate::instructions::IrOpcode::hq_drop, drops)) - .collect::>(); - let wasm = $crate::instructions::wrap_instructions( - &step_func, - Rc::from([$($type_arg,)*]), - &test_opcodes, - )?; - // println!("{wasm:?}"); - for (i, _) in types.iter().enumerate() { - step_func.add_instructions( - [$crate::wasm::InternalInstruction::Immediate( - wasm_encoder::Instruction::LocalGet( - (i + 2).try_into().unwrap() - ) - )] - )? - } - step_func.add_instructions(wasm)?; - - // println!("{:?}", step_func.instructions().borrow()); - - proj.steps() - .borrow_mut() - .push(step_func); - - let wasm_bytes = proj.finish().unwrap().wasm_bytes; - - println!("{}", wasmprinter::print_bytes(wasm_bytes.clone()).unwrap()); - - wasmparser::validate(&wasm_bytes).map_err(|err| - make_hq_bug!( - "invalid wasm module with types {:?}. Original error message: {}", - ($($type_arg,)*), - err.message() - ) - )?; + $crate::instructions::tests::wasm_output_type_matches_wrapped_expected_output_type(proj, types, output_type2, wrap_instructions, flags(), IrOpcode::$opcode$(($fields))?)?; } Ok(()) } @@ -290,3 +222,188 @@ macro_rules! instructions_test { } } } + +#[cfg(test)] +pub use test_util::*; + +#[cfg(test)] +mod test_util { + use wasm_encoder::ValType; + + use crate::instructions::IrOpcode; + use crate::ir::{IrType, ReturnType, Step, StepContext, Target}; + use crate::prelude::*; + use crate::wasm::registries::TypeRegistry; + use crate::wasm::{InternalInstruction, StepFunc, StepTarget, WasmFlags, WasmProject}; + + pub fn make_target() -> Rc { + Rc::new(Target::new( + false, + BTreeMap::default(), + BTreeMap::default(), + Weak::new(), + RefCell::default(), + 0, + Box::default(), + )) + } + + pub fn make_context(target: &Rc) -> StepContext { + StepContext { + target: Rc::clone(target), + warp: false, + proc_context: None, + debug: false, + } + } + + pub fn make_step(target: &Rc) -> Rc> { + Rc::new(RefCell::new(Step::new_empty( + Weak::new(), + false, + Rc::clone(target), + ))) + } + + pub fn assert_valid_json>(test: S) { + assert!(serde_json::from_str::(&test).is_ok()); + } + + pub fn wasm_output_type_matches_expected_output_type( + proj: WasmProject, + types: &[IrType], + output_type: OT, + wasm: W, + flags: WasmFlags, + ) -> HQResult<()> + where + OT: FnOnce() -> HQResult, + W: FnOnce(&StepFunc, &[IrType]) -> HQResult>, + { + let Ok(output_type) = output_type() else { + println!("skipping failed output_type"); + return Ok(()); + }; + let registries = proj.registries(); + let params = types + .iter() + .copied() + .map(WasmProject::ir_type_to_wasm) + .chain([ValType::I32, TypeRegistry::STRUCT_REF]) + .collect::>(); + let result = match output_type { + ReturnType::Singleton(output) => vec![WasmProject::ir_type_to_wasm(output)], + ReturnType::MultiValue(outputs) => outputs + .iter() + .copied() + .map(WasmProject::ir_type_to_wasm) + .collect(), + ReturnType::None => vec![], + }; + let step_func = StepFunc::new_with_types( + params.into(), + result.into(), + Rc::clone(®istries), + flags, + StepTarget::Sprite(0), + 0, + Rc::clone(proj.costume_names()), + ); + let Ok(wasm) = wasm(&step_func, types) else { + println!("skipping failed wasm"); + return Ok(()); + }; + for (i, _) in types.iter().enumerate() { + step_func.add_instructions([crate::wasm::InternalInstruction::Immediate( + wasm_encoder::Instruction::LocalGet(i.try_into().unwrap()), + )])?; + } + step_func.add_instructions(wasm)?; + + proj.steps().borrow_mut().push(step_func); + + let wasm_bytes = proj.finish().unwrap().wasm_bytes; + + println!("{}", wasmprinter::print_bytes(wasm_bytes.clone()).unwrap()); + + wasmparser::validate(&wasm_bytes).map_err(|err| { + make_hq_bug!( + "invalid wasm module with types {:?}. Original error message: {}", + types, + err.message() + ) + })?; + + Ok(()) + } + + pub fn wasm_output_type_matches_wrapped_expected_output_type( + proj: WasmProject, + types: &[IrType], + output_type: OT, + wasm: W, + flags: WasmFlags, + opcode: IrOpcode, + ) -> HQResult<()> + where + OT: FnOnce() -> HQResult, + W: FnOnce(&StepFunc, &[IrType], Vec) -> HQResult>, + { + let Ok(output_type) = output_type() else { + println!("skipping failed output_type"); + return Ok(()); + }; + println!("{output_type:?}"); + let registries = proj.registries(); + let params = types + .iter() + .copied() + .map(WasmProject::ir_type_to_wasm) + .chain([ValType::I32, TypeRegistry::STRUCT_REF]) + .collect::>(); + let result = vec![]; + let step_func = StepFunc::new_with_types( + params.into(), + result.into(), + Rc::clone(®istries), + flags, + StepTarget::Sprite(0), + 0, + Rc::clone(proj.costume_names()), + ); + let drops = match output_type { + ReturnType::Singleton(_) => 1, + ReturnType::MultiValue(outs) => outs.len(), + ReturnType::None => 0, + }; + let test_opcodes = core::iter::once(opcode) + .chain(core::iter::repeat_n(IrOpcode::hq_drop, drops)) + .collect::>(); + let wasm = wasm(&step_func, types, test_opcodes)?; + // println!("{wasm:?}"); + for (i, _) in types.iter().enumerate() { + step_func.add_instructions([InternalInstruction::Immediate( + wasm_encoder::Instruction::LocalGet(i.try_into().unwrap()), + )])?; + } + step_func.add_instructions(wasm)?; + + // println!("{:?}", step_func.instructions().borrow()); + + proj.steps().borrow_mut().push(step_func); + + let wasm_bytes = proj.finish().unwrap().wasm_bytes; + + println!("{}", wasmprinter::print_bytes(wasm_bytes.clone()).unwrap()); + + wasmparser::validate(&wasm_bytes).map_err(|err| { + make_hq_bug!( + "invalid wasm module with types {:?}. Original error message: {}", + types, + err.message() + ) + })?; + + Ok(()) + } +} diff --git a/src/ir/proc.rs b/src/ir/proc.rs index 85f3bdba..f1207ad7 100644 --- a/src/ir/proc.rs +++ b/src/ir/proc.rs @@ -34,6 +34,11 @@ impl SpecificProc { Ok(self.first_step.try_borrow()?) } + #[cfg(test)] + pub fn first_step_mut(&self) -> RefMut<'_, PartialStep> { + self.first_step.borrow_mut() + } + #[must_use] pub fn arg_vars(&self) -> Rc>> { Rc::clone(&self.arg_vars) @@ -74,10 +79,20 @@ impl Proc { self.warped_specific_proc.borrow() } + #[cfg(test)] + pub fn warped_specific_proc_mut(&self) -> RefMut<'_, Option> { + self.warped_specific_proc.borrow_mut() + } + pub fn nonwarped_specific_proc(&self) -> Ref<'_, Option> { self.nonwarped_specific_proc.borrow() } + #[cfg(test)] + pub fn nonwarped_specific_proc_mut(&self) -> RefMut<'_, Option> { + self.nonwarped_specific_proc.borrow_mut() + } + pub fn proccode(&self) -> &str { &self.proccode } @@ -247,20 +262,44 @@ impl Proc { }; let arg_ids = Self::string_vec_mutation(mutations, "argumentids")?; let arg_names = Self::string_vec_mutation(mutations, "argumentnames")?; - Ok(Rc::new(Self { - proccode: proccode.as_str().into(), - warped_specific_proc: RefCell::new(None), - nonwarped_specific_proc: RefCell::new(None), + Ok(Rc::new(Self::new( + proccode.as_str().into(), + RefCell::new(None), + RefCell::new(None), + first_step_id, + debug, + arg_ids, + arg_names, + target, + warp, + ))) + } + + pub const fn new( + proccode: Box, + warped_specific_proc: RefCell>, + nonwarped_specific_proc: RefCell>, + first_step_id: Option>, + debug: bool, + arg_ids: Box<[Box]>, + arg_names: Box<[Box]>, + target: Rc, + always_warped: bool, + ) -> Self { + Self { + warped_specific_proc, + nonwarped_specific_proc, first_step_id, + proccode, debug, arg_ids, arg_names, target, - always_warped: warp, - })) + always_warped, + } } - fn new_specific_proc(&self) -> SpecificProc { + pub fn new_specific_proc(&self) -> SpecificProc { SpecificProc { first_step: RefCell::new(PartialStep::None), arg_vars: arg_vars_from_proccode(&self.proccode), diff --git a/src/wasm/func.rs b/src/wasm/func.rs index a9b9349c..44cfc4f2 100644 --- a/src/wasm/func.rs +++ b/src/wasm/func.rs @@ -463,15 +463,11 @@ impl StepFunc { let target_index = step.try_borrow()?.context().target().index(); let step_func = if let Some(ref proc_context) = step.try_borrow()?.context().proc_context { let params = if step.try_borrow()?.context().warp { - let arg_types = (*proc_context.arg_vars) + (*proc_context.arg_vars) .borrow() .iter() .map(|var| WasmProject::ir_type_to_wasm(*var.possible_types())) - .collect::>(); - arg_types - .iter() - .chain(&[ValType::I32, TypeRegistry::STRUCT_REF]) - .copied() + .chain([ValType::I32, TypeRegistry::STRUCT_REF]) .collect() } else { Box::from([ValType::I32, TypeRegistry::STRUCT_REF]) diff --git a/src/wasm/project.rs b/src/wasm/project.rs index dddedf72..b3ecb3bf 100644 --- a/src/wasm/project.rs +++ b/src/wasm/project.rs @@ -39,7 +39,11 @@ impl WasmProject { )] #[allow(dead_code, reason = "not dead in test mode")] #[must_use] - pub fn new(flags: WasmFlags, environment: ExternalEnvironment) -> Self { + pub fn new( + flags: WasmFlags, + environment: ExternalEnvironment, + costume_names: Vec>>, + ) -> Self { Self { flags, steps: Rc::new(RefCell::new(Vec::new())), @@ -47,7 +51,7 @@ impl WasmProject { environment, registries: Rc::new(Registries::default()), target_names: vec![], - costume_names: Rc::new(vec![]), + costume_names: Rc::new(costume_names), } } @@ -56,6 +60,11 @@ impl WasmProject { Rc::clone(&self.registries) } + #[must_use] + pub const fn costume_names(&self) -> &Rc>>> { + &self.costume_names + } + #[must_use] pub const fn environment(&self) -> ExternalEnvironment { self.environment @@ -525,7 +534,6 @@ impl WasmProject { .events .keys() .filter_map(|e| { - #[expect(clippy::redundant_else, reason = "false positive")] if let Event::SpriteClicked(index) = e { Some( i32::try_from(*index)