mirror of
https://github.com/arabianq/pipewire-soundpad.git
synced 2026-06-19 12:13:32 +00:00
feat: better testing (#131)
* add tests * update github actions to include testing step * optimization
This commit is contained in:
committed by
GitHub
parent
0476329798
commit
e91465365d
@@ -37,6 +37,9 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
toolchain: 1.94.1
|
toolchain: 1.94.1
|
||||||
|
|
||||||
|
- name: Run tests
|
||||||
|
run: cargo test --locked
|
||||||
|
|
||||||
- name: Extract all binary names
|
- name: Extract all binary names
|
||||||
id: cargo-meta
|
id: cargo-meta
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
@@ -217,3 +217,70 @@ impl SoundpadGui {
|
|||||||
// });
|
// });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use egui::{Key, Modifiers};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_chord_from_event() {
|
||||||
|
// Valid modifier + key
|
||||||
|
let mut mods = Modifiers::NONE;
|
||||||
|
mods.ctrl = true;
|
||||||
|
let chord = chord_from_event(&mods, &Key::A);
|
||||||
|
assert_eq!(chord, Some("Ctrl+A".to_string()));
|
||||||
|
|
||||||
|
// Multiple modifiers
|
||||||
|
mods.shift = true;
|
||||||
|
let chord = chord_from_event(&mods, &Key::F1);
|
||||||
|
assert_eq!(chord, Some("Ctrl+Shift+F1".to_string()));
|
||||||
|
|
||||||
|
// Missing modifiers (requires at least one modifier)
|
||||||
|
let no_mods = Modifiers::NONE;
|
||||||
|
let chord = chord_from_event(&no_mods, &Key::A);
|
||||||
|
assert_eq!(chord, None);
|
||||||
|
|
||||||
|
// Invalid keys (e.g. Escape or Enter shouldn't be accepted by chord_from_event)
|
||||||
|
mods.shift = false;
|
||||||
|
let chord = chord_from_event(&mods, &Key::Escape);
|
||||||
|
assert_eq!(chord, None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_chord() {
|
||||||
|
// Valid Ctrl+A
|
||||||
|
let res = parse_chord("Ctrl+A");
|
||||||
|
assert!(res.is_some());
|
||||||
|
let (mods, key) = res.unwrap();
|
||||||
|
assert!(mods.ctrl);
|
||||||
|
assert!(!mods.alt);
|
||||||
|
assert!(!mods.shift);
|
||||||
|
assert_eq!(key, Key::A);
|
||||||
|
|
||||||
|
// Valid Ctrl+Shift+F12
|
||||||
|
let res = parse_chord("Ctrl+Shift+F12");
|
||||||
|
assert!(res.is_some());
|
||||||
|
let (mods, key) = res.unwrap();
|
||||||
|
assert!(mods.ctrl);
|
||||||
|
assert!(mods.shift);
|
||||||
|
assert!(!mods.alt);
|
||||||
|
assert_eq!(key, Key::F12);
|
||||||
|
|
||||||
|
// Valid Ctrl+Alt+Shift+Super+B
|
||||||
|
let res = parse_chord("Ctrl+Alt+Shift+Super+B");
|
||||||
|
assert!(res.is_some());
|
||||||
|
let (mods, key) = res.unwrap();
|
||||||
|
assert!(mods.ctrl);
|
||||||
|
assert!(mods.alt);
|
||||||
|
assert!(mods.shift);
|
||||||
|
assert!(mods.command); // Super maps to command in egui Modifiers
|
||||||
|
assert_eq!(key, Key::B);
|
||||||
|
|
||||||
|
// Invalid keys/chords
|
||||||
|
assert!(parse_chord("").is_none());
|
||||||
|
assert!(parse_chord("Ctrl+").is_none());
|
||||||
|
assert!(parse_chord("Ctrl+Escape").is_none());
|
||||||
|
assert!(parse_chord("Invalid+A").is_none());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -294,3 +294,45 @@ pub async fn run() -> Result<()> {
|
|||||||
Err(e) => Err(anyhow!(e.to_string())),
|
Err(e) => Err(anyhow!(e.to_string())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_get_filtered_files() {
|
||||||
|
let mut gui = SoundpadGui {
|
||||||
|
app_state: AppState::default(),
|
||||||
|
config: GuiConfig::default(),
|
||||||
|
audio_player_state: AudioPlayerState::default(),
|
||||||
|
audio_player_state_shared: Arc::new(Mutex::new(AudioPlayerState::default())),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create some dummy paths
|
||||||
|
// We will mock path properties using standard Rust PathBuf
|
||||||
|
let dir_a = PathBuf::from("a_dir");
|
||||||
|
let file_b = PathBuf::from("b_file.mp3");
|
||||||
|
let file_c = PathBuf::from("c_file.wav");
|
||||||
|
let file_txt = PathBuf::from("invalid.txt");
|
||||||
|
|
||||||
|
gui.app_state.listed_files.insert(dir_a.clone());
|
||||||
|
gui.app_state.listed_files.insert(file_b.clone());
|
||||||
|
gui.app_state.listed_files.insert(file_c.clone());
|
||||||
|
gui.app_state.listed_files.insert(file_txt.clone());
|
||||||
|
|
||||||
|
// Note: is_dir() check in get_filtered_files relies on physical filesystem properties.
|
||||||
|
// On the real OS filesystem, these paths don't exist, so they are treated as files.
|
||||||
|
// Unsupported extensions (like .txt) will be filtered out.
|
||||||
|
// So we expect only file_b and file_c, sorted alphabetically.
|
||||||
|
let filtered = gui.get_filtered_files();
|
||||||
|
assert_eq!(filtered.len(), 2);
|
||||||
|
assert_eq!(filtered[0], file_b);
|
||||||
|
assert_eq!(filtered[1], file_c);
|
||||||
|
|
||||||
|
// Test search query
|
||||||
|
gui.app_state.search_query = "c_fi".to_string();
|
||||||
|
let filtered_search = gui.get_filtered_files();
|
||||||
|
assert_eq!(filtered_search.len(), 1);
|
||||||
|
assert_eq!(filtered_search[0], file_c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -30,3 +30,26 @@ impl SoundpadGui {
|
|||||||
self.draw_footer(ui);
|
self.draw_footer(ui);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_get_volume_icon() {
|
||||||
|
assert_eq!(SoundpadGui::get_volume_icon(0.8), ICON_VOLUME_UP.codepoint);
|
||||||
|
assert_eq!(SoundpadGui::get_volume_icon(0.0), ICON_VOLUME_OFF.codepoint);
|
||||||
|
assert_eq!(
|
||||||
|
SoundpadGui::get_volume_icon(-0.1),
|
||||||
|
ICON_VOLUME_OFF.codepoint
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
SoundpadGui::get_volume_icon(0.2),
|
||||||
|
ICON_VOLUME_MUTE.codepoint
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
SoundpadGui::get_volume_icon(0.5),
|
||||||
|
ICON_VOLUME_DOWN.codepoint
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -218,3 +218,82 @@ impl HotkeyConfig {
|
|||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_gui_config_default() {
|
||||||
|
let config = GuiConfig::default();
|
||||||
|
assert_eq!(config.scale_factor, 1.0);
|
||||||
|
assert_eq!(config.left_panel_width, 280.0);
|
||||||
|
assert!(!config.save_volume);
|
||||||
|
assert_eq!(config.preferred_theme, PreferredTheme::System);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_hotkey_config_operations() {
|
||||||
|
let mut config = HotkeyConfig::default();
|
||||||
|
assert!(config.slots.is_empty());
|
||||||
|
|
||||||
|
let req = Request::ping();
|
||||||
|
config.set_slot("slot1".to_string(), req.clone());
|
||||||
|
assert_eq!(config.slots.len(), 1);
|
||||||
|
assert_eq!(config.slots[0].slot, "slot1");
|
||||||
|
assert_eq!(config.slots[0].action, req);
|
||||||
|
assert!(config.slots[0].key_chord.is_none());
|
||||||
|
|
||||||
|
// Test find_slot
|
||||||
|
let found = config.find_slot("slot1");
|
||||||
|
assert!(found.is_some());
|
||||||
|
assert_eq!(found.unwrap().slot, "slot1");
|
||||||
|
|
||||||
|
// Test set_key_chord
|
||||||
|
let updated = config.set_key_chord("slot1", Some("Ctrl+A".to_string()));
|
||||||
|
assert!(updated);
|
||||||
|
assert_eq!(config.slots[0].key_chord.as_deref(), Some("Ctrl+A"));
|
||||||
|
|
||||||
|
// Test set_key_chord for non-existent slot
|
||||||
|
let updated_non_existent = config.set_key_chord("slot2", Some("Ctrl+B".to_string()));
|
||||||
|
assert!(!updated_non_existent);
|
||||||
|
|
||||||
|
// Test find_slot_mut
|
||||||
|
let found_mut = config.find_slot_mut("slot1");
|
||||||
|
assert!(found_mut.is_some());
|
||||||
|
found_mut.unwrap().key_chord = Some("Ctrl+B".to_string());
|
||||||
|
assert_eq!(config.slots[0].key_chord.as_deref(), Some("Ctrl+B"));
|
||||||
|
|
||||||
|
// Test slots_for_chord
|
||||||
|
let slots = config.slots_for_chord("Ctrl+B");
|
||||||
|
assert_eq!(slots.len(), 1);
|
||||||
|
assert_eq!(slots[0].slot, "slot1");
|
||||||
|
|
||||||
|
let empty_slots = config.slots_for_chord("Ctrl+A");
|
||||||
|
assert!(empty_slots.is_empty());
|
||||||
|
|
||||||
|
// Test remove_slot
|
||||||
|
let removed = config.remove_slot("slot1");
|
||||||
|
assert!(removed);
|
||||||
|
assert!(config.slots.is_empty());
|
||||||
|
|
||||||
|
let removed_non_existent = config.remove_slot("slot1");
|
||||||
|
assert!(!removed_non_existent);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_hotkey_config_conflicts() {
|
||||||
|
let mut config = HotkeyConfig::default();
|
||||||
|
config.set_slot("slot1".to_string(), Request::ping());
|
||||||
|
config.set_slot("slot2".to_string(), Request::ping());
|
||||||
|
config.set_slot("slot3".to_string(), Request::ping());
|
||||||
|
|
||||||
|
config.set_key_chord("slot1", Some("Ctrl+A".to_string()));
|
||||||
|
config.set_key_chord("slot2", Some("Ctrl+A".to_string())); // Conflict with slot1
|
||||||
|
config.set_key_chord("slot3", Some("Ctrl+B".to_string()));
|
||||||
|
|
||||||
|
let conflicts = config.find_conflicts();
|
||||||
|
assert_eq!(conflicts.len(), 1);
|
||||||
|
assert!(conflicts.contains(&("slot1", "slot2")) || conflicts.contains(&("slot2", "slot1")));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -72,3 +72,84 @@ impl AudioDevice {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_audio_device_new() {
|
||||||
|
let device = AudioDevice::new(
|
||||||
|
1,
|
||||||
|
Some("NickName"),
|
||||||
|
Some("Description"),
|
||||||
|
Some("Name"),
|
||||||
|
DeviceType::Input,
|
||||||
|
);
|
||||||
|
assert_eq!(device.id, 1);
|
||||||
|
assert_eq!(device.nick, "NickName");
|
||||||
|
assert_eq!(device.name, "Name");
|
||||||
|
assert_eq!(device.device_type, DeviceType::Input);
|
||||||
|
|
||||||
|
// Fallbacks for nick
|
||||||
|
let device_no_nick =
|
||||||
|
AudioDevice::new(2, None, Some("Desc"), Some("Name"), DeviceType::Output);
|
||||||
|
assert_eq!(device_no_nick.nick, "Desc");
|
||||||
|
|
||||||
|
let device_no_desc = AudioDevice::new(3, None, None, Some("Name"), DeviceType::Output);
|
||||||
|
assert_eq!(device_no_desc.nick, "Name");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_audio_device_add_port() {
|
||||||
|
let mut device = AudioDevice::new(1, None, None, Some("device-name"), DeviceType::Input);
|
||||||
|
|
||||||
|
let port_fl = Port {
|
||||||
|
node_id: 1,
|
||||||
|
port_id: 10,
|
||||||
|
name: "input_FL".to_string(),
|
||||||
|
};
|
||||||
|
let port_fr = Port {
|
||||||
|
node_id: 1,
|
||||||
|
port_id: 11,
|
||||||
|
name: "input_FR".to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
|
device.add_port(port_fl.clone());
|
||||||
|
device.add_port(port_fr.clone());
|
||||||
|
|
||||||
|
assert_eq!(device.input_fl, Some(port_fl));
|
||||||
|
assert_eq!(device.input_fr, Some(port_fr));
|
||||||
|
|
||||||
|
// Test output ports
|
||||||
|
let port_out_fl = Port {
|
||||||
|
node_id: 1,
|
||||||
|
port_id: 12,
|
||||||
|
name: "output_FL".to_string(),
|
||||||
|
};
|
||||||
|
let port_out_fr = Port {
|
||||||
|
node_id: 1,
|
||||||
|
port_id: 13,
|
||||||
|
name: "capture_FR".to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
|
device.add_port(port_out_fl.clone());
|
||||||
|
device.add_port(port_out_fr.clone());
|
||||||
|
|
||||||
|
assert_eq!(device.output_fl, Some(port_out_fl));
|
||||||
|
assert_eq!(device.output_fr, Some(port_out_fr));
|
||||||
|
|
||||||
|
// Test MONO ports
|
||||||
|
let mut device_mono =
|
||||||
|
AudioDevice::new(2, None, None, Some("mono-device"), DeviceType::Input);
|
||||||
|
let port_mono = Port {
|
||||||
|
node_id: 2,
|
||||||
|
port_id: 20,
|
||||||
|
name: "input_MONO".to_string(),
|
||||||
|
};
|
||||||
|
device_mono.add_port(port_mono.clone());
|
||||||
|
|
||||||
|
assert_eq!(device_mono.input_fl, Some(port_mono.clone()));
|
||||||
|
assert_eq!(device_mono.input_fr, Some(port_mono));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -238,3 +238,88 @@ impl Response {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_response_new() {
|
||||||
|
let res = Response::new(true, "success-msg");
|
||||||
|
assert!(res.status);
|
||||||
|
assert_eq!(res.message, "success-msg");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_request_constructors() {
|
||||||
|
// test ping
|
||||||
|
let req_ping = Request::ping();
|
||||||
|
assert_eq!(req_ping.name, "ping");
|
||||||
|
assert!(req_ping.args.is_empty());
|
||||||
|
|
||||||
|
// test kill
|
||||||
|
let req_kill = Request::kill();
|
||||||
|
assert_eq!(req_kill.name, "kill");
|
||||||
|
|
||||||
|
// test pause (with and without id)
|
||||||
|
let req_pause_no_id = Request::pause(None);
|
||||||
|
assert_eq!(req_pause_no_id.name, "pause");
|
||||||
|
assert!(req_pause_no_id.args.is_empty());
|
||||||
|
|
||||||
|
let req_pause_with_id = Request::pause(Some(42));
|
||||||
|
assert_eq!(req_pause_with_id.name, "pause");
|
||||||
|
assert_eq!(
|
||||||
|
req_pause_with_id.args.get("id").map(|s| s.as_str()),
|
||||||
|
Some("42")
|
||||||
|
);
|
||||||
|
|
||||||
|
// test play
|
||||||
|
let req_play = Request::play("/path/to/sound.mp3", true);
|
||||||
|
assert_eq!(req_play.name, "play");
|
||||||
|
assert_eq!(
|
||||||
|
req_play.args.get("file_path").map(|s| s.as_str()),
|
||||||
|
Some("/path/to/sound.mp3")
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
req_play.args.get("concurrent").map(|s| s.as_str()),
|
||||||
|
Some("true")
|
||||||
|
);
|
||||||
|
|
||||||
|
// test set_volume
|
||||||
|
let req_volume = Request::set_volume(0.8, Some(10));
|
||||||
|
assert_eq!(req_volume.name, "set_volume");
|
||||||
|
assert_eq!(
|
||||||
|
req_volume.args.get("volume").map(|s| s.as_str()),
|
||||||
|
Some("0.8")
|
||||||
|
);
|
||||||
|
assert_eq!(req_volume.args.get("id").map(|s| s.as_str()), Some("10"));
|
||||||
|
|
||||||
|
// test set_hotkey_action_and_key
|
||||||
|
let action = Request::ping();
|
||||||
|
let req_hotkey_action_and_key =
|
||||||
|
Request::set_hotkey_action_and_key("slot1", &action, "Ctrl+P");
|
||||||
|
assert_eq!(req_hotkey_action_and_key.name, "set_hotkey_action_and_key");
|
||||||
|
assert_eq!(
|
||||||
|
req_hotkey_action_and_key
|
||||||
|
.args
|
||||||
|
.get("slot")
|
||||||
|
.map(|s| s.as_str()),
|
||||||
|
Some("slot1")
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
req_hotkey_action_and_key
|
||||||
|
.args
|
||||||
|
.get("key_chord")
|
||||||
|
.map(|s| s.as_str()),
|
||||||
|
Some("Ctrl+P")
|
||||||
|
);
|
||||||
|
let action_json = serde_json::to_string(&action).unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
req_hotkey_action_and_key
|
||||||
|
.args
|
||||||
|
.get("action")
|
||||||
|
.map(|s| s.as_str()),
|
||||||
|
Some(action_json.as_str())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -199,3 +199,79 @@ pub async fn start_global_hotkey_listener() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_modifier_state() {
|
||||||
|
let mut state = ModifierState::new();
|
||||||
|
assert!(!state.any_active());
|
||||||
|
|
||||||
|
// Press Ctrl
|
||||||
|
state.update(KeyCode::KEY_LEFTCTRL, true);
|
||||||
|
assert!(state.ctrl);
|
||||||
|
assert!(state.any_active());
|
||||||
|
|
||||||
|
// Release Ctrl
|
||||||
|
state.update(KeyCode::KEY_LEFTCTRL, false);
|
||||||
|
assert!(!state.ctrl);
|
||||||
|
assert!(!state.any_active());
|
||||||
|
|
||||||
|
// Press multiple modifiers
|
||||||
|
state.update(KeyCode::KEY_RIGHTALT, true);
|
||||||
|
state.update(KeyCode::KEY_LEFTSHIFT, true);
|
||||||
|
assert!(state.alt);
|
||||||
|
assert!(state.shift);
|
||||||
|
assert!(state.any_active());
|
||||||
|
|
||||||
|
// Update a non-modifier key
|
||||||
|
state.update(KeyCode::KEY_A, true);
|
||||||
|
// Modifier states should remain unchanged
|
||||||
|
assert!(state.alt);
|
||||||
|
assert!(state.shift);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_is_modifier() {
|
||||||
|
assert!(ModifierState::is_modifier(KeyCode::KEY_LEFTCTRL));
|
||||||
|
assert!(ModifierState::is_modifier(KeyCode::KEY_RIGHTCTRL));
|
||||||
|
assert!(ModifierState::is_modifier(KeyCode::KEY_LEFTALT));
|
||||||
|
assert!(ModifierState::is_modifier(KeyCode::KEY_RIGHTALT));
|
||||||
|
assert!(ModifierState::is_modifier(KeyCode::KEY_LEFTSHIFT));
|
||||||
|
assert!(ModifierState::is_modifier(KeyCode::KEY_RIGHTSHIFT));
|
||||||
|
assert!(ModifierState::is_modifier(KeyCode::KEY_LEFTMETA));
|
||||||
|
assert!(ModifierState::is_modifier(KeyCode::KEY_RIGHTMETA));
|
||||||
|
|
||||||
|
assert!(!ModifierState::is_modifier(KeyCode::KEY_A));
|
||||||
|
assert!(!ModifierState::is_modifier(KeyCode::KEY_1));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_evdev_key_name() {
|
||||||
|
assert_eq!(evdev_key_name(KeyCode::KEY_A), Some("A"));
|
||||||
|
assert_eq!(evdev_key_name(KeyCode::KEY_Z), Some("Z"));
|
||||||
|
assert_eq!(evdev_key_name(KeyCode::KEY_0), Some("0"));
|
||||||
|
assert_eq!(evdev_key_name(KeyCode::KEY_F1), Some("F1"));
|
||||||
|
assert_eq!(evdev_key_name(KeyCode::KEY_F12), Some("F12"));
|
||||||
|
assert_eq!(evdev_key_name(KeyCode::KEY_ENTER), None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_build_chord() {
|
||||||
|
let mut modifiers = ModifierState::new();
|
||||||
|
|
||||||
|
assert_eq!(build_chord(&modifiers, "A"), "A");
|
||||||
|
|
||||||
|
modifiers.ctrl = true;
|
||||||
|
assert_eq!(build_chord(&modifiers, "A"), "Ctrl+A");
|
||||||
|
|
||||||
|
modifiers.shift = true;
|
||||||
|
assert_eq!(build_chord(&modifiers, "B"), "Ctrl+Shift+B");
|
||||||
|
|
||||||
|
modifiers.alt = true;
|
||||||
|
modifiers.meta = true;
|
||||||
|
assert_eq!(build_chord(&modifiers, "F5"), "Ctrl+Alt+Shift+Super+F5");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -139,3 +139,16 @@ pub fn start_app_state_thread(audio_player_state_shared: Arc<Mutex<AudioPlayerSt
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_format_time_pair() {
|
||||||
|
assert_eq!(format_time_pair(0.0, 0.0), "00:00/00:00");
|
||||||
|
assert_eq!(format_time_pair(5.4, 10.0), "00:05/00:10");
|
||||||
|
assert_eq!(format_time_pair(59.9, 125.1), "01:00/02:05");
|
||||||
|
assert_eq!(format_time_pair(3600.0, 7205.0), "60:00/120:05");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user