diff --git a/crates/cmd_prompt/Cargo.toml b/crates/cmd_prompt/Cargo.toml index 1878509..d76152e 100644 --- a/crates/cmd_prompt/Cargo.toml +++ b/crates/cmd_prompt/Cargo.toml @@ -6,7 +6,6 @@ edition = "2024" [dependencies] bevy = '0.18.0' bevy-inspector-egui = "0.36.0" -q_test_harness = {path = "../test_harness"} bevy_dylib={optional=true, version="0.18.0"} clap = { version = "4.5.53", features = ["derive"] } cosmic-text = "0.16.0" @@ -20,6 +19,9 @@ tiny_bail = "0.7.0" variadics_please = "1.1.0" serde = { version = "1.0.228", features = ["derive"] } +[dev-dependencies] +q_test_harness = {path = "../test_harness", version="^0.1"} + [features] dylib= ["bevy/dynamic_linking", "dep:bevy_dylib"] diff --git a/crates/cmd_prompt/assets/console.env b/crates/cmd_prompt/assets/console.env new file mode 100644 index 0000000..1ff9b82 --- /dev/null +++ b/crates/cmd_prompt/assets/console.env @@ -0,0 +1,2 @@ +FOO=BAR +HI=HELLO diff --git a/crates/cmd_prompt/assets/console.history b/crates/cmd_prompt/assets/console.history new file mode 100644 index 0000000..8a1218a --- /dev/null +++ b/crates/cmd_prompt/assets/console.history @@ -0,0 +1,5 @@ +1 +2 +3 +4 +5 diff --git a/crates/cmd_prompt/src/actions/actions/history.rs b/crates/cmd_prompt/src/actions/actions/history.rs index 1744146..ffef9eb 100644 --- a/crates/cmd_prompt/src/actions/actions/history.rs +++ b/crates/cmd_prompt/src/actions/actions/history.rs @@ -72,6 +72,7 @@ mod test { use bevy::input::ButtonState; use bevy::input::keyboard::Key; use bevy::input::keyboard::KeyboardInput; + use bevy::input_focus::InputFocus; use q_test_harness::prelude::*; fn key_input(key_code: KeyCode, logical_key: Key, state: ButtonState) -> KeyboardInput { @@ -104,6 +105,13 @@ mod test { fn test_history() { let mut app = App::new(); app.add_plugins(test_harness::plugin); + app.add_systems( + Startup, + |mut commands: Commands, mut focus: ResMut| { + let id = commands.spawn(Console).id(); + focus.0 = Some(id); + }, + ); for step in 0..3 { app.add_step( step, diff --git a/crates/cmd_prompt/src/assets.rs b/crates/cmd_prompt/src/assets.rs index 9b1ec00..eb082e5 100644 --- a/crates/cmd_prompt/src/assets.rs +++ b/crates/cmd_prompt/src/assets.rs @@ -11,12 +11,12 @@ mod assets_impl { /// Environment variables for this console. Saved as '.env' files on disk. /// Follows conventional '.env' format. - #[derive(Asset, Default, Component, Debug, Deref, DerefMut, Reflect, Clone)] + #[derive(Asset, Default, Component, Debug, Deref, DerefMut, Reflect, Clone, PartialEq)] pub struct ConsoleEnvVars(pub HashMap); /// Command history of this [Console]. Saved as '.history' files on disk. /// Simple line-separated list of executed commands. - #[derive(Default, Asset, Debug, Deref, DerefMut, Reflect, Clone)] + #[derive(Default, Asset, Debug, Deref, DerefMut, Reflect, Clone, PartialEq)] pub struct ConsoleHistory(pub Vec); } pub use assets_impl::*; @@ -174,7 +174,10 @@ mod loaders { let mut buf = String::new(); reader.read_to_string(&mut buf).await?; // todo: not memory efficient - let vec = buf.split('\n').map(|s| s.to_owned()).collect::>(); + let vec = buf + .split('\n') + .filter_map(|s| (!s.is_empty()).then_some(s.to_owned())) + .collect::>(); Ok(ConsoleHistory(vec)) } @@ -199,3 +202,103 @@ pub fn plugin(app: &mut App) { ConsoleAssetHandle::::check_assets, ); } + +#[cfg(test)] +mod test { + use bevy::asset::AssetLoadFailedEvent; + + use super::*; + + fn test_asset_load( + path: String, + callback: impl IntoSystem>, (), M> + 'static, + ) { + let mut app = App::new(); + app.add_plugins(crate::test_harness::plugin); + let callback = app.register_system(callback); + app.add_systems(Startup, move |mut commands: Commands| { + info!("spawning..."); + commands.spawn(ConsoleAssetHandle::::new(path.to_string())); + }); + app.add_systems( + Update, + |mut commands: Commands, + mut reader: MessageReader>, + this: Query<&ConsoleAssetHandle>| { + info!("reading fail msgs..."); + let this = this.single().unwrap(); + for msg in reader.read() { + if this.handle().id() == msg.id + && let AssetLoadError::AssetReaderError(asset_reader_error) = &msg.error + { + error!(?asset_reader_error); + commands.write_message(AppExit::error()); + } + } + }, + ); + app.add_systems( + Update, + move |mut reader: MessageReader>, + this: Query<&ConsoleAssetHandle>, + assets: Res>, + mut commands: Commands| { + info!("reading event msgs..."); + let this = this.single().unwrap(); + for msg in reader.read() { + debug!(?msg); + if let AssetEvent::LoadedWithDependencies { id } = msg + && this.handle().id() == *id + { + let handle = this.handle(); + if let Some(asset) = assets.get(handle) + && *asset != T::default() + { + commands.run_system_with(callback, *id); + } + } + } + }, + ); + assert!(app.run().is_success()) + } + + #[test] + fn test_env_var_load() { + test_asset_load( + "console.env".to_string(), + |input: In>, + assets: Res>, + mut commands: Commands| { + let asset = assets.get(*input).unwrap(); + info!(?asset); + let mut ok = true; + ok = ok && asset.get("FOO") == Some(&"BAR".to_string()); + ok = ok && asset.get("HI") == Some(&"HELLO".to_string()); + if ok { + commands.write_message(AppExit::Success); + } else { + commands.write_message(AppExit::error()); + } + }, + ); + } + #[test] + fn test_history_load() { + test_asset_load( + "console.history".to_string(), + |input: In>, + assets: Res>, + mut commands: Commands| { + let asset = assets.get(*input).unwrap(); + info!(?asset); + let ok = asset.0 == ["1", "2", "3", "4", "5"]; + if ok { + commands.write_message(AppExit::Success); + } else { + commands.write_message(AppExit::error()); + } + }, + ); + } +} diff --git a/crates/cmd_prompt/src/test_harness.rs b/crates/cmd_prompt/src/test_harness.rs index 20e0b64..ee0b37e 100644 --- a/crates/cmd_prompt/src/test_harness.rs +++ b/crates/cmd_prompt/src/test_harness.rs @@ -1,6 +1,6 @@ use bevy::{ - image::TextureAtlasPlugin, input::InputPlugin, input_focus::InputFocus, - render::texture::TexturePlugin, text::TextPlugin, ui::UiPlugin, + image::TextureAtlasPlugin, input::InputPlugin, render::texture::TexturePlugin, + text::TextPlugin, ui::UiPlugin, }; use q_test_harness::{TestRunnerPlugin, TestRunnerTimeout}; @@ -9,7 +9,6 @@ use crate::prelude::*; pub fn plugin(app: &mut App) { app.add_plugins(( TestRunnerPlugin::default(), - ConsolePlugin, DefaultPickingPlugins, WindowPlugin { primary_window: None, @@ -22,12 +21,7 @@ pub fn plugin(app: &mut App) { TextureAtlasPlugin, ImagePlugin::default(), TexturePlugin, + ConsolePlugin, )); - app.add_systems(Startup, setup); app.insert_resource(TestRunnerTimeout(1.)); } - -fn setup(mut commands: Commands, mut focus: ResMut) { - let id = commands.spawn(Console).id(); - focus.0 = Some(id); -}