mirror of
https://github.com/storytold/soundcraft.git
synced 2026-10-24 02:26:46 -06:00
* Build: line tables only for workspace crates, no debug info for dependencies Full debug info made most of the dev and test target size and link time. Line tables keep file and line numbers in backtraces; dependency frames lose them. * Tests: build each crate's integration tests as one binary Each tests/*.rs file was its own test binary: 98 binaries, each linking the crate and its dependencies. The files are now modules of tests/it/main.rs, one binary per crate, which cuts link time and target size. Filter by module: `cargo test -p <crate> --test it <module>::`. Binaries with their own main (harness = false) in clap-host and vst3-host stay separate, as do the ui-egui tests that switch the process-wide Light/Dark palette and recovery.rs, whose autosave locks leak into child processes other tests start. * Xtask: run tests with nextest, doctests apart, and no examples in the test build cargo xtask ci runs the tests with cargo nextest when it is installed, else cargo test with a notice, and doctests with cargo test --doc. The test build leaves out examples (--lib --bins --tests); clippy --all-targets still compiles them. Test binaries with harness = false run under cargo test: their own main cannot answer nextest's --list. clippy and the wasm check keep going past a failing crate. cargo xtask test runs the test step alone.
116 lines
5.7 KiB
Rust
116 lines
5.7 KiB
Rust
use egui::os::OperatingSystem;
|
|
use egui::{Key, Modifiers};
|
|
use serde_json::json;
|
|
use soundcraft_ui_egui::{MainWindow, Services, SoundApp, shortcuts};
|
|
|
|
fn press(ctx: &egui::Context, app: &mut SoundApp, key: Key, modifiers: Modifiers) {
|
|
let events = [true, false].map(|pressed| egui::Event::Key { key, physical_key: None, pressed, repeat: false, modifiers }).to_vec();
|
|
ctx.run_ui(egui::RawInput { events, ..Default::default() }, |ui| shortcuts::handle(app, ui.ctx())).textures_delta.clear();
|
|
}
|
|
|
|
#[test]
|
|
fn ctrl_shift_arrows_nudge_the_selected_clip_gain() {
|
|
let pc_ctrl = Modifiers { ctrl: true, command: true, ..Modifiers::NONE };
|
|
for (os, ctrl) in [(OperatingSystem::Mac, Modifiers::CTRL), (OperatingSystem::Windows, pc_ctrl), (OperatingSystem::Nix, pc_ctrl)] {
|
|
let mut app = SoundApp::new(soundcraft_engine::demo::demo_engine(), None, Services::default());
|
|
let kick = app.engine.session().track_by_name("Kick").unwrap().clips()[0].id;
|
|
app.engine.execute("edit.select", &json!({"clips": [kick.0]})).unwrap();
|
|
let ctx = egui::Context::default();
|
|
ctx.set_os(os);
|
|
let ctrl_shift = Modifiers { shift: true, ..ctrl };
|
|
press(&ctx, &mut app, Key::ArrowUp, ctrl_shift);
|
|
press(&ctx, &mut app, Key::ArrowUp, ctrl_shift);
|
|
press(&ctx, &mut app, Key::ArrowDown, ctrl_shift);
|
|
assert_eq!(app.engine.session().find_clip(kick).unwrap().1.gain_db, 1.0, "{os:?}");
|
|
}
|
|
}
|
|
|
|
fn type_in_app(ctx: &egui::Context, app: &mut SoundApp, keys: &[(Key, Modifiers)]) {
|
|
let events = keys
|
|
.iter()
|
|
.flat_map(|&(key, modifiers)| [true, false].map(|pressed| egui::Event::Key { key, physical_key: None, pressed, repeat: false, modifiers }))
|
|
.collect();
|
|
ctx.run_ui(egui::RawInput { events, ..Default::default() }, |ui| {
|
|
app.logic(ui.ctx());
|
|
app.ui(ui);
|
|
})
|
|
.textures_delta
|
|
.clear();
|
|
}
|
|
|
|
#[test]
|
|
fn tab_leaves_the_keys_to_the_shortcuts() {
|
|
let mut app = SoundApp::new(soundcraft_engine::demo::demo_engine(), None, Services::default());
|
|
let ctx = egui::Context::default();
|
|
for _ in 0..3 {
|
|
type_in_app(&ctx, &mut app, &[]);
|
|
}
|
|
for tab in [Modifiers::NONE, Modifiers::SHIFT] {
|
|
type_in_app(&ctx, &mut app, &[(Key::Tab, tab)]);
|
|
assert_eq!(ctx.memory(|m| m.focused()), None, "{tab:?}");
|
|
let zoom = app.engine.session().edit.zoom.samples_per_px;
|
|
type_in_app(&ctx, &mut app, &[(Key::T, Modifiers::NONE)]);
|
|
assert_eq!(app.engine.session().edit.zoom.samples_per_px, zoom / 2.0, "{tab:?}");
|
|
type_in_app(&ctx, &mut app, &[(Key::R, Modifiers::NONE)]);
|
|
assert_eq!(app.engine.session().edit.zoom.samples_per_px, zoom, "{tab:?}");
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn bare_plus_and_minus_nudge_the_selected_clip_in_edit() {
|
|
// A laptop keyboard has no dedicated "+": typing it needs Shift, which is already claimed by
|
|
// the Grid-value shortcut (#125 above). So nudge must fire on the bare, unshifted key the "+"
|
|
// symbol sits on, same as "-" already does; `Key::Plus` stays bound too for a keyboard (e.g. a
|
|
// numpad) that does send it on its own.
|
|
let mut app = SoundApp::new(soundcraft_engine::demo::demo_engine(), None, Services::default());
|
|
let kick = app.engine.session().track_by_name("Kick").unwrap().clips()[0].id;
|
|
app.engine.execute("edit.select", &json!({"clips": [kick.0]})).unwrap();
|
|
let ctx = egui::Context::default();
|
|
let start = |app: &SoundApp| app.engine.session().find_clip(kick).unwrap().1.start;
|
|
let original = start(&app);
|
|
|
|
press(&ctx, &mut app, Key::Minus, Modifiers::NONE);
|
|
let after_minus = start(&app);
|
|
assert!(after_minus < original, "bare Minus must nudge left");
|
|
|
|
press(&ctx, &mut app, Key::Equals, Modifiers::NONE);
|
|
assert_eq!(start(&app), original, "bare Equals must nudge back right, same step as Minus");
|
|
|
|
press(&ctx, &mut app, Key::Plus, Modifiers::NONE);
|
|
assert!(start(&app) > original, "Key::Plus (e.g. a numpad +) must still nudge right");
|
|
|
|
// Shift+Equals is the pre-existing, separate Grid-value shortcut: it must not also nudge.
|
|
let before_shift = start(&app);
|
|
let grid = app.engine.session().edit.grid;
|
|
press(&ctx, &mut app, Key::Equals, Modifiers::SHIFT);
|
|
assert_eq!(start(&app), before_shift, "Shift+Equals steps the Grid value, not the clip");
|
|
assert_ne!(app.engine.session().edit.grid, grid, "Shift+Equals must still step the Grid value");
|
|
|
|
// Alt+Equals is the registered `window.event_list` shortcut: it must not also nudge.
|
|
let before_alt = start(&app);
|
|
assert!(!app.ui.show_event_list);
|
|
press(&ctx, &mut app, Key::Equals, Modifiers::ALT);
|
|
assert_eq!(start(&app), before_alt, "Alt+Equals opens the MIDI Event List, not a nudge");
|
|
assert!(app.ui.show_event_list, "Alt+Equals must still open the MIDI Event List");
|
|
}
|
|
|
|
#[test]
|
|
fn cmd_equals_toggles_mix_and_edit_without_zooming() {
|
|
let mac_cmd = Modifiers { mac_cmd: true, command: true, ..Modifiers::NONE };
|
|
let pc_ctrl = Modifiers { ctrl: true, command: true, ..Modifiers::NONE };
|
|
for (os, cmd) in [(OperatingSystem::Mac, mac_cmd), (OperatingSystem::Windows, pc_ctrl), (OperatingSystem::Nix, pc_ctrl)] {
|
|
let mut app = SoundApp::new(soundcraft_engine::demo::demo_engine(), None, Services::default());
|
|
let ctx = egui::Context::default();
|
|
ctx.set_os(os);
|
|
ctx.set_zoom_factor(1.25);
|
|
press(&ctx, &mut app, Key::Equals, cmd);
|
|
assert_eq!(app.ui.window, MainWindow::Mix, "{os:?}");
|
|
press(&ctx, &mut app, Key::Equals, cmd);
|
|
press(&ctx, &mut app, Key::Num0, cmd);
|
|
press(&ctx, &mut app, Key::Minus, cmd);
|
|
ctx.run_ui(egui::RawInput::default(), |_| {}).textures_delta.clear();
|
|
assert_eq!(app.ui.window, MainWindow::Edit, "{os:?}");
|
|
assert_eq!(ctx.zoom_factor(), 1.25, "{os:?}");
|
|
}
|
|
}
|