From 0551d4f40bae927bedb5704af648c4d9eda52e5e Mon Sep 17 00:00:00 2001 From: Will Medrano Date: Fri, 13 Sep 2024 08:03:50 -0700 Subject: [PATCH] Overhaul testing. --- Cargo.toml | 1 + src/client/async_client.rs | 9 +- src/client/mod.rs | 7 - src/client/test.rs | 262 ------------------------ src/client/test_callback.rs | 256 ------------------------ src/lib.rs | 3 + src/port/audio.rs | 53 ----- src/port/midi.rs | 309 ---------------------------- src/port/mod.rs | 6 - src/port/test_client.rs | 388 ------------------------------------ src/port/test_port.rs | 201 ------------------- src/ringbuffer.rs | 134 ------------- src/tests/client.rs | 7 + src/tests/mod.rs | 7 + src/transport.rs | 315 ----------------------------- 15 files changed, 19 insertions(+), 1939 deletions(-) delete mode 100644 src/client/test.rs delete mode 100644 src/client/test_callback.rs delete mode 100644 src/port/test_client.rs delete mode 100644 src/port/test_port.rs create mode 100644 src/tests/client.rs create mode 100644 src/tests/mod.rs diff --git a/Cargo.toml b/Cargo.toml index 7f6c57c90..a1015ad69 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,7 @@ log = { version = "0.4", optional = true} [dev-dependencies] crossbeam-channel = "0.5" +ctor = "0.2" [features] default = ["dynamic_loading", "log"] diff --git a/src/client/async_client.rs b/src/client/async_client.rs index d22c388f4..fe6a0b554 100644 --- a/src/client/async_client.rs +++ b/src/client/async_client.rs @@ -7,7 +7,7 @@ use std::sync::atomic::AtomicBool; use super::callbacks::clear_callbacks; use super::callbacks::{CallbackContext, NotificationHandler, ProcessHandler}; use crate::client::client_impl::Client; -use crate::client::common::{sleep_on_test, CREATE_OR_DESTROY_CLIENT_MUTEX}; +use crate::client::common::CREATE_OR_DESTROY_CLIENT_MUTEX; use crate::Error; /// A JACK client that is processing data asynchronously, in real-time. @@ -56,7 +56,6 @@ where pub fn new(client: Client, notification_handler: N, process_handler: P) -> Result { let _m = CREATE_OR_DESTROY_CLIENT_MUTEX.lock().ok(); unsafe { - sleep_on_test(); let mut callback_context = Box::new(CallbackContext { client, notification: notification_handler, @@ -64,11 +63,7 @@ where is_valid: AtomicBool::new(true), }); CallbackContext::register_callbacks(&mut callback_context)?; - sleep_on_test(); let res = j::jack_activate(callback_context.client.raw()); - for _ in 0..4 { - sleep_on_test(); - } match res { 0 => Ok(AsyncClient { callback: Some(callback_context), @@ -117,13 +112,11 @@ impl AsyncClient { let client = cb.client.raw(); // deactivate - sleep_on_test(); if j::jack_deactivate(client) != 0 { return Err(Error::ClientDeactivationError); } // clear the callbacks - sleep_on_test(); clear_callbacks(client)?; // done, take ownership of callback if cb.is_valid.load(std::sync::atomic::Ordering::Relaxed) { diff --git a/src/client/mod.rs b/src/client/mod.rs index 971513bcf..b89faf076 100644 --- a/src/client/mod.rs +++ b/src/client/mod.rs @@ -18,10 +18,3 @@ pub use self::client_status::ClientStatus; pub use self::common::CLIENT_NAME_SIZE; pub use self::handler_impls::ClosureProcessHandler; - -// client.rs excluding functionality that involves ports or callbacks -#[cfg(test)] -mod test; - -#[cfg(test)] -mod test_callback; diff --git a/src/client/test.rs b/src/client/test.rs deleted file mode 100644 index 3eb10f753..000000000 --- a/src/client/test.rs +++ /dev/null @@ -1,262 +0,0 @@ -use crate::client::*; -use crate::jack_enums::Error; -use crate::{ClosureProcessHandler, Control, RingBuffer}; - -fn open_test_client(name: &str) -> (Client, ClientStatus) { - Client::new(name, ClientOptions::NO_START_SERVER).unwrap() -} - -#[test] -fn time_can_get_time() { - open_test_client("tcgt").0.time(); -} - -#[test] -fn time_is_monotonically_increasing() { - let c = open_test_client("tcgt").0; - let initial_t = c.time(); - std::thread::sleep(std::time::Duration::from_millis(100)); - let later_t = c.time(); - assert!(initial_t < later_t); -} - -#[test] -fn client_valid_client_name_size() { - assert!(*CLIENT_NAME_SIZE > 0); -} - -#[test] -fn client_can_open() { - open_test_client("client_can_open"); -} - -#[test] -#[should_panic] -fn client_fails_to_open_with_large_name() { - let name = (0..=*CLIENT_NAME_SIZE) - .map(|_| "a") - .collect::>() - .join("_"); - Client::new(&name, ClientOptions::NO_START_SERVER).unwrap(); - // fails on travis, switched to should_panic for a catch all - // assert_eq!(Client::new(&name, ClientOptions::NO_START_SERVER).err(), - // Some(Error::ClientError(client_status::FAILURE | - // client_status::SERVER_ERROR))); -} - -#[test] -fn client_can_be_named() { - let name = "client_can_be_named"; - let (c, _) = open_test_client(name); - assert_eq!(c.name(), name); -} - -#[test] -fn client_can_activate() { - let (c, _) = open_test_client("client_can_activate"); - let _ac = c.activate_async((), ()).unwrap(); -} - -#[test] -fn client_can_set_buffer_size() { - let (c, _) = open_test_client("client_can_set_buffer_size"); - let initial_size = c.buffer_size(); - let new_size = 2 * initial_size; - c.set_buffer_size(new_size).unwrap(); - assert_eq!(c.buffer_size(), new_size); - c.set_buffer_size(initial_size).unwrap(); - assert_eq!(c.buffer_size(), initial_size); -} - -#[test] -fn client_detects_bad_buffer_size() { - let (c, _) = open_test_client("client_detects_bad_buffer_size"); - let initial_size = c.buffer_size(); - assert_eq!(c.set_buffer_size(0), Err(Error::SetBufferSizeError)); - c.set_buffer_size(initial_size).unwrap(); - assert_eq!(c.buffer_size(), initial_size); -} - -#[test] -fn client_can_deactivate() { - let (c, _) = open_test_client("client_can_deactivate"); - let a = c.activate_async((), ()).unwrap(); - a.deactivate().unwrap(); -} - -#[test] -fn client_knows_buffer_size() { - let (c, _) = open_test_client("client_knows_buffer_size"); - assert!(c.buffer_size() > 0); -} - -#[test] -fn client_knows_sample_rate() { - let (c, _) = open_test_client("client_knows_sample_rate"); - // 44100 - As started by dummy_jack_server.sh - assert_eq!(c.sample_rate(), 44100); -} - -#[test] -fn client_knows_cpu_load() { - let (c, _) = open_test_client("client_knows_cpu_load"); - let _load = c.cpu_load(); -} - -#[test] -fn client_can_estimate_frame_times() { - let (c, _) = open_test_client("client_knows_frame_times"); - let current_frame_time = c.frame_time(); - let time = c.frames_to_time(44_100); - let frames = c.time_to_frames(1_000_000); - assert!(current_frame_time > 0); - assert!(time > 0); - assert!(frames > 0); -} - -#[test] -fn client_debug_printing() { - let (c, _) = open_test_client("client_has_debug_string"); - let got = format!("{c:?}"); - assert_ne!("", got); -} - -#[test] -fn client_can_use_ringbuffer() { - let (c, _) = open_test_client("client_can_use_ringbuffer"); - - let ringbuf = RingBuffer::new(1024).unwrap(); - let (mut reader, mut writer) = ringbuf.into_reader_writer(); - - let buf = [0_u8, 1, 2, 3]; - let mut sent = false; - let _a = c - .activate_async( - (), - ClosureProcessHandler::new(move |_, _| { - if !sent { - for (item, bufitem) in writer.peek_iter().zip(buf.iter()) { - *item = *bufitem; - } - - writer.advance(buf.len()); - sent = true; - } - Control::Continue - }), - ) - .unwrap(); - - // spin until realtime closure has been run - while reader.space() == 0 {} - - let mut outbuf = [0_u8; 8]; - let num = reader.read_buffer(&mut outbuf); - assert_eq!(num, buf.len()); - - assert_eq!(outbuf[..num], buf[..]); -} - -#[test] -fn client_uuid() { - let (c1, _) = open_test_client("uuidtest-client1"); - let (c2, _) = open_test_client("uuidtest-client2"); - - let uuid1s = c1.uuid_string(); - let uuid2s = c2.uuid_string(); - assert_ne!(uuid1s, uuid2s); - - assert_eq!( - c1.name_by_uuid_str(&uuid1s), - Some("uuidtest-client1".to_string()) - ); - assert_eq!( - c2.name_by_uuid_str(&uuid1s), - Some("uuidtest-client1".to_string()) - ); - - assert_eq!( - c1.name_by_uuid_str(&uuid2s), - Some("uuidtest-client2".to_string()) - ); - assert_eq!( - c2.name_by_uuid_str(&uuid2s), - Some("uuidtest-client2".to_string()) - ); - - //create and then dealloc a client, get the uuid. - let uuid3s = { - let (c3, _) = open_test_client("uuidtest-client3"); - c3.uuid_string() - }; - assert_eq!(c1.name_by_uuid_str(&uuid3s), None); - assert_eq!(c2.name_by_uuid_str(&uuid3s), None); -} - -#[cfg(feature = "metadata")] -#[test] -fn client_numeric_uuid() { - let (c1, _) = open_test_client("numeric-uuid-client1"); - let (c2, _) = open_test_client("numeric-uuid-client2"); - - let ac1 = c1.activate_async((), ()).unwrap(); - let ac2 = c2.activate_async((), ()).unwrap(); - - let c1 = ac1.as_client(); - let c2 = ac2.as_client(); - - let uuid1 = c1.uuid(); - let uuid2 = c2.uuid(); - assert_ne!(uuid1, uuid2); - assert_ne!(0, uuid1); - assert_ne!(0, uuid2); - - let uuid1s = c1.uuid_string(); - let uuid2s = c2.uuid_string(); - assert_ne!(uuid1s, uuid2s); - - assert_eq!(c1.name_by_uuid(0), None); - assert_eq!(c2.name_by_uuid(0), None); - - assert_eq!( - c1.name_by_uuid(uuid1), - Some("numeric-uuid-client1".to_string()) - ); - assert_eq!( - c2.name_by_uuid(uuid1), - Some("numeric-uuid-client1".to_string()) - ); - assert_eq!( - c1.name_by_uuid_str(&uuid1s), - Some("numeric-uuid-client1".to_string()) - ); - assert_eq!( - c2.name_by_uuid_str(&uuid1s), - Some("numeric-uuid-client1".to_string()) - ); - - assert_eq!( - c1.name_by_uuid(uuid2), - Some("numeric-uuid-client2".to_string()) - ); - assert_eq!( - c2.name_by_uuid(uuid2), - Some("numeric-uuid-client2".to_string()) - ); - assert_eq!( - c1.name_by_uuid_str(&uuid2s), - Some("numeric-uuid-client2".to_string()) - ); - assert_eq!( - c2.name_by_uuid_str(&uuid2s), - Some("numeric-uuid-client2".to_string()) - ); - - //create and then dealloc a client, get the uuid. - let uuid3 = { - let (c3, _) = open_test_client("numeric-uuid-client3"); - c3.uuid() - }; - assert_eq!(c1.name_by_uuid(uuid3), None); - assert_eq!(c2.name_by_uuid(uuid3), None); -} diff --git a/src/client/test_callback.rs b/src/client/test_callback.rs deleted file mode 100644 index fe0f9ae81..000000000 --- a/src/client/test_callback.rs +++ /dev/null @@ -1,256 +0,0 @@ -use std::sync::atomic::{AtomicUsize, Ordering}; -use std::{ptr, thread, time}; - -use super::*; -use crate::{AudioIn, Client, Control, Frames, NotificationHandler, PortId, ProcessHandler}; - -#[derive(Debug, Default)] -pub struct Counter { - pub induce_xruns: bool, - pub thread_init_count: AtomicUsize, - pub frames_processed: usize, - pub process_thread: Option, - pub buffer_size_thread_history: Vec, - pub buffer_size_change_history: Vec, - pub registered_client_history: Vec, - pub unregistered_client_history: Vec, - pub port_register_history: Vec, - pub port_unregister_history: Vec, - pub xruns_count: usize, - pub last_frame_time: Frames, - pub frames_since_cycle_start: Frames, -} - -impl NotificationHandler for Counter { - fn thread_init(&self, _: &Client) { - self.thread_init_count.fetch_add(1, Ordering::Relaxed); - } - - fn client_registration(&mut self, _: &Client, name: &str, is_registered: bool) { - if is_registered { - self.registered_client_history.push(name.to_string()) - } else { - self.unregistered_client_history.push(name.to_string()) - } - } - - fn port_registration(&mut self, _: &Client, pid: PortId, is_registered: bool) { - if is_registered { - self.port_register_history.push(pid) - } else { - self.port_unregister_history.push(pid) - } - } - - fn xrun(&mut self, _: &Client) -> Control { - self.xruns_count += 1; - Control::Continue - } -} - -impl ProcessHandler for Counter { - fn process(&mut self, _: &Client, ps: &ProcessScope) -> Control { - self.frames_processed += ps.n_frames() as usize; - self.last_frame_time = ps.last_frame_time(); - self.frames_since_cycle_start = ps.frames_since_cycle_start(); - let _cycle_times = ps.cycle_times(); - if self.induce_xruns { - thread::sleep(time::Duration::from_millis(100)); - self.induce_xruns = false; - } - self.process_thread = Some(thread::current().id()); - Control::Continue - } - - fn buffer_size(&mut self, _: &Client, size: Frames) -> Control { - self.buffer_size_change_history.push(size); - self.buffer_size_thread_history.push(thread::current().id()); - Control::Continue - } -} - -fn open_test_client(name: &str) -> Client { - Client::new(name, ClientOptions::NO_START_SERVER).unwrap().0 -} - -fn active_test_client(name: &str) -> AsyncClient { - let c = open_test_client(name); - c.activate_async(Counter::default(), Counter::default()) - .unwrap() -} - -#[test] -fn client_cback_has_proper_default_callbacks() { - // defaults shouldn't care about these params - let wc = unsafe { Client::from_raw(ptr::null_mut()) }; - let ps = unsafe { ProcessScope::from_raw(0, ptr::null_mut()) }; - // check each callbacks - ().thread_init(&wc); - unsafe { ().shutdown(client_status::ClientStatus::empty(), "mock") }; - assert_eq!(().process(&wc, &ps), Control::Continue); - ().freewheel(&wc, true); - ().freewheel(&wc, false); - assert_eq!(().buffer_size(&wc, 0), Control::Continue); - assert_eq!(().sample_rate(&wc, 0), Control::Continue); - ().client_registration(&wc, "mock", true); - ().client_registration(&wc, "mock", false); - ().port_registration(&wc, 0, true); - ().port_registration(&wc, 0, false); - assert_eq!( - ().port_rename(&wc, 0, "old_mock", "new_mock"), - Control::Continue - ); - ().ports_connected(&wc, 0, 1, true); - ().ports_connected(&wc, 2, 3, false); - assert_eq!(().graph_reorder(&wc), Control::Continue); - assert_eq!(().xrun(&wc), Control::Continue); - - std::mem::forget(wc); -} - -#[test] -fn client_cback_calls_thread_init() { - let ac = active_test_client("client_cback_calls_thread_init"); - let counter = ac.deactivate().unwrap().1; - // IDK why this isn't 1, even with a single thread. - assert!(counter.thread_init_count.load(Ordering::Relaxed) > 0); -} - -#[test] -fn client_cback_calls_process() { - let ac = active_test_client("client_cback_calls_process"); - std::thread::sleep(std::time::Duration::from_secs(1)); - let counter = ac.deactivate().unwrap().2; - assert!(counter.frames_processed > 0); - assert!(counter.last_frame_time > 0); - assert!(counter.frames_since_cycle_start > 0); -} - -#[test] -fn client_cback_calls_buffer_size() { - let ac = active_test_client("client_cback_calls_buffer_size"); - let initial = ac.as_client().buffer_size(); - let second = initial / 2; - let third = second / 2; - if let Err(crate::Error::SetBufferSizeError) = ac.as_client().set_buffer_size(second) { - eprintln!("Client does not support setting buffer size"); - return; - } - ac.as_client().set_buffer_size(third).unwrap(); - ac.as_client().set_buffer_size(initial).unwrap(); - let counter = ac.deactivate().unwrap().2; - let mut history_iter = counter.buffer_size_change_history.iter().cloned(); - assert_eq!(history_iter.find(|&s| s == initial), Some(initial)); - assert_eq!(history_iter.find(|&s| s == second), Some(second)); - assert_eq!(history_iter.find(|&s| s == third), Some(third)); - assert_eq!(history_iter.find(|&s| s == initial), Some(initial)); -} - -/// Tests the assumption that the buffer_size callback is called on the process -/// thread. See issue #137 -#[test] -fn client_cback_calls_buffer_size_on_process_thread() { - let ac = active_test_client("cback_buffer_size_process_thr"); - let initial = ac.as_client().buffer_size(); - let second = initial / 2; - if let Err(crate::Error::SetBufferSizeError) = ac.as_client().set_buffer_size(second) { - eprintln!("Client does not support setting buffer size"); - return; - } - let counter = ac.deactivate().unwrap().2; - let process_thread = counter.process_thread.unwrap(); - assert_eq!(counter.buffer_size_thread_history.len(), 2); - assert_eq!( - // TODO: The process thread should be used on the first and second callback. However, this - // is not the case. Figure out if this is due to a thread safety issue or not. - &counter.buffer_size_thread_history[0..1], - [process_thread], - "Note: This does not hold for JACK2", - ); -} - -#[test] -fn client_cback_calls_after_client_registered() { - let ac = active_test_client("client_cback_cacr"); - let _other_client = open_test_client("client_cback_cacr_other"); - let counter = ac.deactivate().unwrap().1; - assert!(counter - .registered_client_history - .contains(&"client_cback_cacr_other".to_string(),)); - assert!(!counter - .unregistered_client_history - .contains(&"client_cback_cacr_other".to_string(),)); -} - -#[test] -fn client_cback_calls_after_client_unregistered() { - let ac = active_test_client("client_cback_cacu"); - let other_client = open_test_client("client_cback_cacu_other"); - drop(other_client); - let counter = ac.deactivate().unwrap().1; - assert!(counter - .registered_client_history - .contains(&"client_cback_cacu_other".to_string(),)); - assert!(counter - .unregistered_client_history - .contains(&"client_cback_cacu_other".to_string(),)); -} - -#[test] -fn client_cback_reports_xruns() { - let c = open_test_client("client_cback_reports_xruns"); - let counter = Counter { - induce_xruns: true, - ..Counter::default() - }; - let ac = c.activate_async(Counter::default(), counter).unwrap(); - let counter = ac.deactivate().unwrap().1; - assert!(counter.xruns_count > 0, "No xruns encountered."); -} - -#[test] -fn client_cback_calls_port_registered() { - let ac = active_test_client("client_cback_cpr"); - let _pa = ac - .as_client() - .register_port("pa", AudioIn::default()) - .unwrap(); - let _pb = ac - .as_client() - .register_port("pb", AudioIn::default()) - .unwrap(); - let counter = ac.deactivate().unwrap().1; - assert_eq!( - counter.port_register_history.len(), - 2, - "Did not detect port registrations." - ); - assert!( - counter.port_unregister_history.is_empty(), - "Detected false port deregistrations." - ); -} - -#[test] -fn client_cback_calls_port_unregistered() { - let ac = active_test_client("client_cback_cpr"); - let pa = ac - .as_client() - .register_port("pa", AudioIn::default()) - .unwrap(); - let pb = ac - .as_client() - .register_port("pb", AudioIn::default()) - .unwrap(); - ac.as_client().unregister_port(pa).unwrap(); - ac.as_client().unregister_port(pb).unwrap(); - let counter = ac.deactivate().unwrap().1; - assert!( - counter.port_register_history.len() >= 2, - "Did not detect port registrations." - ); - assert!( - counter.port_unregister_history.len() >= 2, - "Did not detect port deregistrations." - ); -} diff --git a/src/lib.rs b/src/lib.rs index 45bb393c9..3dbf3d621 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -68,6 +68,9 @@ mod properties; mod ringbuffer; mod transport; +#[cfg(test)] +mod tests; + static TIME_CLIENT: std::sync::LazyLock = std::sync::LazyLock::new(|| { Client::new("deprecated_get_time", ClientOptions::NO_START_SERVER) .unwrap() diff --git a/src/port/audio.rs b/src/port/audio.rs index 61bceeb97..cb6e7eda2 100644 --- a/src/port/audio.rs +++ b/src/port/audio.rs @@ -96,56 +96,3 @@ impl Port { } } } - -#[cfg(test)] -mod test { - use super::*; - use crate::{Client, ClientOptions, ClosureProcessHandler, Control}; - - fn open_test_client(name: &str) -> Client { - Client::new(name, ClientOptions::NO_START_SERVER).unwrap().0 - } - - #[test] - fn port_audio_can_read_write() { - let c = open_test_client("port_audio_crw"); - let in_a = c.register_port("ia", AudioIn::default()).unwrap(); - let in_b = c.register_port("ib", AudioIn::default()).unwrap(); - let mut out_a = c.register_port("oa", AudioOut::default()).unwrap(); - let mut out_b = c.register_port("ob", AudioOut::default()).unwrap(); - let (success_sender, success_receiver) = std::sync::mpsc::sync_channel(1); - let process_callback = move |_: &Client, ps: &ProcessScope| -> Control { - let exp_a = 0.312_443; - let exp_b = -0.612_120; - let out_a = out_a.as_mut_slice(ps); - let out_b = out_b.as_mut_slice(ps); - for v in out_a.iter_mut() { - *v = exp_a; - } - for v in out_b.iter_mut() { - *v = exp_b; - } - - let in_a = in_a.as_slice(ps); - let in_b = in_b.as_slice(ps); - if in_a.iter().all(|v| (*v - exp_a).abs() < 1E-5) - && in_b.iter().all(|v| (*v - exp_b).abs() < 1E-5) - { - _ = success_sender.try_send(true); - } - Control::Continue - }; - let ac = c - .activate_async((), ClosureProcessHandler::new(process_callback)) - .unwrap(); - ac.as_client() - .connect_ports_by_name("port_audio_crw:oa", "port_audio_crw:ia") - .unwrap(); - ac.as_client() - .connect_ports_by_name("port_audio_crw:ob", "port_audio_crw:ib") - .unwrap(); - assert!(success_receiver - .recv_timeout(std::time::Duration::from_secs(2)) - .unwrap(),); - } -} diff --git a/src/port/midi.rs b/src/port/midi.rs index 774e1a555..604de2953 100644 --- a/src/port/midi.rs +++ b/src/port/midi.rs @@ -208,312 +208,3 @@ impl<'a> MidiWriter<'a> { unsafe { j::jack_midi_max_event_size(self.buffer) } } } - -#[cfg(test)] -mod test { - use super::*; - use crate::client::Client; - use crate::client::ClosureProcessHandler; - use crate::client::ProcessHandler; - use crate::jack_enums::Control; - use crate::primitive_types::Frames; - use crate::ClientOptions; - use lazy_static::lazy_static; - use std::iter::Iterator; - use std::sync::atomic::{AtomicUsize, Ordering}; - - use std::sync::Mutex; - use std::{thread, time}; - - fn open_test_client(name: &str) -> Client { - Client::new(name, ClientOptions::NO_START_SERVER).unwrap().0 - } - - struct Connector { - src: String, - dst: String, - } - - impl Connector { - fn connect(&self, c: &Client) { - c.connect_ports_by_name(&self.src, &self.dst).unwrap(); - } - } - - #[derive(Clone, Debug, PartialEq, Eq)] - struct OwnedRawMidi { - time: Frames, - bytes: Vec, - } - - impl OwnedRawMidi { - fn new(m: &RawMidi) -> OwnedRawMidi { - OwnedRawMidi { - time: m.time, - bytes: m.bytes.to_vec(), - } - } - - fn unowned(&self) -> RawMidi<'_> { - RawMidi { - time: self.time, - bytes: &self.bytes, - } - } - } - - struct IterTest Vec> { - stream: Vec, - collected: Vec, - collector: F, - midi_in: Port, - midi_out: Port, - } - - impl Vec> IterTest { - fn new(client: &Client, stream: Vec, collector: F) -> IterTest { - IterTest { - stream, - collected: Vec::new(), - collector, - midi_in: client.register_port("in", MidiIn).unwrap(), - midi_out: client.register_port("out", MidiOut).unwrap(), - } - } - - fn connector(&self) -> Connector { - Connector { - src: self.midi_out.name().unwrap(), - dst: self.midi_in.name().unwrap(), - } - } - } - - impl Vec> ProcessHandler for IterTest { - fn process(&mut self, _: &Client, ps: &ProcessScope) -> Control { - let (midi_in, mut midi_out) = (self.midi_in.iter(ps), self.midi_out.writer(ps)); - // Write to output. - for m in self.stream.iter() { - _ = midi_out.write(&m.unowned()); - } - // Collect in input. - if self.collected.is_empty() { - self.collected = (self.collector)(midi_in); - } - Control::Continue - } - } - - #[test] - fn port_midi_can_read_write() { - // open clients and ports - let c = open_test_client("port_midi_crw"); - let in_a = c.register_port("ia", MidiIn).unwrap(); - let in_b = c.register_port("ib", MidiIn).unwrap(); - let mut out_a = c.register_port("oa", MidiOut).unwrap(); - let mut out_b = c.register_port("ob", MidiOut).unwrap(); - - // set callback routine - let (signal_succeed, did_succeed) = std::sync::mpsc::sync_channel(1); - let process_callback = move |_: &Client, ps: &ProcessScope| -> Control { - let exp_a = RawMidi { - time: 0, - bytes: &[0b1001_0000, 0b0100_0000], - }; - let exp_b = RawMidi { - time: ps.n_frames() - 1, - bytes: &[0b1000_0000, 0b0100_0000], - }; - let (in_a, in_b) = (in_a.iter(ps), in_b.iter(ps)); - let (mut out_a, mut out_b) = (out_a.writer(ps), out_b.writer(ps)); - _ = out_a.write(&exp_a); - _ = out_b.write(&exp_b); - if in_a.clone().next().is_some() - && in_a.clone().all(|m| m == exp_a) - && in_b.clone().all(|m| m == exp_b) - { - _ = signal_succeed.try_send(true); - } - Control::Continue - }; - - // activate - let ac = c - .activate_async((), ClosureProcessHandler::new(process_callback)) - .unwrap(); - - // connect ports to each other - ac.as_client() - .connect_ports_by_name("port_midi_crw:oa", "port_midi_crw:ia") - .unwrap(); - ac.as_client() - .connect_ports_by_name("port_midi_crw:ob", "port_midi_crw:ib") - .unwrap(); - - // check correctness - assert!(did_succeed - .recv_timeout(std::time::Duration::from_secs(1)) - .unwrap()); - ac.deactivate().unwrap(); - } - - #[test] - fn port_midi_can_get_max_event_size() { - // open clients and ports - let c = open_test_client("port_midi_cglc"); - let mut out_p = c.register_port("op", MidiOut).unwrap(); - - // set callback routine - let (size_sender, size_receiver) = std::sync::mpsc::sync_channel(1); - let process_callback = move |_: &Client, ps: &ProcessScope| -> Control { - let out_p = out_p.writer(ps); - _ = size_sender.try_send(out_p.max_event_size()); - Control::Continue - }; - - // check correctness - let ac = c - .activate_async((), ClosureProcessHandler::new(process_callback)) - .unwrap(); - assert!( - size_receiver - .recv_timeout(std::time::Duration::from_secs(1)) - .unwrap() - > 0 - ); - ac.deactivate().unwrap(); - } - - #[test] - fn port_midi_cant_exceed_max_event_size() { - // Open clients and ports. - let c = open_test_client("port_midi_cemes"); - let mut out_p = c.register_port("midi_out", MidiOut).unwrap(); - - // Set callback routine. - let (result_sender, result_receiver) = std::sync::mpsc::sync_channel(1); - let process_callback = move |_: &Client, ps: &ProcessScope| -> Control { - let mut out_p = out_p.writer(ps); - let msg = RawMidi { - time: 0, - bytes: &[0xF6], - }; - for _ in 0..out_p.max_event_size() { - _ = out_p.write(&msg); - } - _ = result_sender.try_send(out_p.write(&msg)); - - Control::Continue - }; - - // Check correctness. - let ac = c - .activate_async((), ClosureProcessHandler::new(process_callback)) - .unwrap(); - assert_eq!( - result_receiver - .recv_timeout(std::time::Duration::from_secs(1)) - .unwrap(), - Err(Error::NotEnoughSpace) - ); - ac.deactivate().unwrap(); - } - - static PMI_COUNT: AtomicUsize = AtomicUsize::new(0); - lazy_static! { - static ref PMI_NEXT: Mutex)>> = Mutex::default(); - static ref PMI_SIZE_HINT: Mutex<(usize, Option)> = Mutex::new((0, None)); - static ref PMI_LAST: Mutex)>> = Mutex::default(); - static ref PMI_THIRD: Mutex)>> = Mutex::default(); - } - - #[test] - fn port_midi_iter() { - // open clients and ports - let c = open_test_client("port_midi_iter"); - let in_p = c.register_port("ip", MidiIn).unwrap(); - let mut out_p = c.register_port("op", MidiOut).unwrap(); - - // set callback routine - let process_callback = move |_: &Client, ps: &ProcessScope| -> Control { - let in_p = in_p.iter(ps); - let mut out_p = out_p.writer(ps); - - for i in 10..14 { - let msg = RawMidi { - time: i, - bytes: &[i as u8], - }; - out_p.write(&msg).ok(); - } - - let rm_to_owned = |m: &RawMidi| (m.time, m.bytes.to_vec()); - *PMI_NEXT.lock().unwrap() = in_p.clone().next().map(|m| rm_to_owned(&m)); - *PMI_SIZE_HINT.lock().unwrap() = in_p.size_hint(); - PMI_COUNT.store(in_p.clone().count(), Ordering::Relaxed); - *PMI_LAST.lock().unwrap() = in_p.clone().last().map(|m| rm_to_owned(&m)); - *PMI_THIRD.lock().unwrap() = in_p.clone().nth(2).map(|m| rm_to_owned(&m)); - - Control::Continue - }; - - // run - let ac = c - .activate_async((), ClosureProcessHandler::new(process_callback)) - .unwrap(); - ac.as_client() - .connect_ports_by_name("port_midi_iter:op", "port_midi_iter:ip") - .unwrap(); - thread::sleep(time::Duration::from_millis(200)); - ac.deactivate().unwrap(); - - // check correctness - assert_eq!(*PMI_NEXT.lock().unwrap(), Some((10, [10].to_vec()))); - assert_eq!(*PMI_SIZE_HINT.lock().unwrap(), (4, Some(4))); - assert_eq!(PMI_COUNT.load(Ordering::Relaxed), 4); - assert_eq!(*PMI_LAST.lock().unwrap(), Some((13, [13].to_vec()))); - assert_eq!(*PMI_THIRD.lock().unwrap(), Some((12, [12].to_vec()))); - } - - #[test] - fn port_midi_iter_next_if() { - let c = open_test_client("pmi_nib"); - let stream = vec![ - OwnedRawMidi { - time: 0, - bytes: vec![1], - }, - OwnedRawMidi { - time: 10, - bytes: vec![3, 4, 5], - }, - OwnedRawMidi { - time: 11, - bytes: vec![6], - }, - OwnedRawMidi { - time: 12, - bytes: vec![7, 8], - }, - ]; - let collect = |midi_in: MidiIter| { - let mut collected = Vec::with_capacity(midi_in.clone().count()); - let mut iter = midi_in.clone(); - while let Some(m) = iter.next_if(|m| m.time < 11) { - collected.push(OwnedRawMidi::new(&m)); - } - collected - }; - let processor = IterTest::new(&c, stream.clone(), collect); - let connector = processor.connector(); - - let ac = c.activate_async((), processor).unwrap(); - connector.connect(ac.as_client()); - thread::sleep(time::Duration::from_millis(200)); - - let (_, _, processor) = ac.deactivate().unwrap(); - let expected: &[OwnedRawMidi] = &stream[0..2]; - let got: &[OwnedRawMidi] = &processor.collected; - assert_eq!(expected, got); - } -} diff --git a/src/port/mod.rs b/src/port/mod.rs index 76085f8f0..9e66951a1 100644 --- a/src/port/mod.rs +++ b/src/port/mod.rs @@ -9,9 +9,3 @@ pub use self::audio::{AudioIn, AudioOut}; pub use self::midi::{MidiIn, MidiIter, MidiOut, MidiWriter, RawMidi}; pub use self::port_flags::PortFlags; pub use self::port_impl::{Port, PortSpec, Unowned, PORT_NAME_SIZE, PORT_TYPE_SIZE}; - -#[cfg(test)] -mod test_client; - -#[cfg(test)] -mod test_port; diff --git a/src/port/test_client.rs b/src/port/test_client.rs deleted file mode 100644 index 9d63bd8c4..000000000 --- a/src/port/test_client.rs +++ /dev/null @@ -1,388 +0,0 @@ -use super::*; -use crate::Client; -use crate::ClientOptions; -use crate::Error; -use crate::NotificationHandler; -use crate::PortId; -use crate::PORT_NAME_SIZE; -use std::collections::HashSet; -use std::sync::mpsc; -use std::sync::Mutex; -fn open_test_client(name: &str) -> Client { - Client::new(name, ClientOptions::NO_START_SERVER).unwrap().0 -} - -#[test] -fn client_port_can_register_port() { - let c = open_test_client("cp_can_register_port"); - c.register_port("cpcrp_a", AudioIn::default()).unwrap(); -} - -#[test] -fn client_port_register_port_enforces_unique_names() { - let pname = "cprpeun_a"; - let c = open_test_client("cp_can_register_port"); - c.register_port(pname, AudioIn::default()).unwrap(); - assert_eq!( - c.register_port(pname, AudioIn::default()).err(), - Some(Error::PortRegistrationError(pname.to_string())) - ); -} - -#[test] -fn client_port_register_port_enforces_name_length() { - let c = open_test_client("cp_can_register_port"); - let pname = (0..=*PORT_NAME_SIZE) - .map(|_| "a") - .collect::>() - .join("_"); - assert_eq!( - c.register_port(&pname, AudioIn::default()).err(), - Some(Error::PortRegistrationError(pname.to_string())) - ); -} - -#[test] -fn client_port_can_request_monitor_by_name() { - let c = open_test_client("cp_can_request_monitor_by_name"); - let p = c.register_port("cpcrmbn_a", AudioIn::default()).unwrap(); - c.request_monitor_by_name(&p.name().unwrap(), true).unwrap(); - c.request_monitor_by_name(&p.name().unwrap(), false) - .unwrap(); -} - -#[test] -fn client_port_can_get_port_by_name() { - let c = open_test_client("cp_can_get_port_by_name"); - let p = c.register_port("named_port", AudioIn::default()).unwrap(); - let _p = c.port_by_name(&p.name().unwrap()).unwrap(); -} - -pub struct PortIdHandler { - pub reg_tx: Mutex>, -} - -impl NotificationHandler for PortIdHandler { - fn port_registration(&mut self, _: &Client, pid: PortId, is_registered: bool) { - if is_registered { - self.reg_tx.lock().unwrap().send(pid).unwrap() - } - } -} - -#[test] -fn client_port_can_get_port_by_id() { - let (client_name, port_name) = ("cp_can_get_port_by_id", "cp_registered_port_name"); - - // Create handler - let (reg_tx, reg_rx) = mpsc::sync_channel(200); - let h = PortIdHandler { - reg_tx: Mutex::new(reg_tx), - }; - - // Open and activate client - let c = open_test_client(client_name); - let ac = c.activate_async(h, ()).unwrap(); - - // Register port - let _pa = ac - .as_client() - .register_port(port_name, AudioIn::default()) - .unwrap(); - - // Get by id - let c = ac.deactivate().unwrap().0; - let mut registered_ports = reg_rx - .iter() - .flat_map(|i| c.port_by_id(i)) - .map(|p| p.name().unwrap()); - let port_name = format!("{client_name}:{port_name}"); - assert!(registered_ports.any(|n| n == port_name)); - - // Port that doesn't exist - // TODO: Restore when JACK doesn't exit when this happens. - // let nonexistant_port = c.port_by_id(10000); - // assert!( - // nonexistant_port.is_none(), - // format!("Expected None but got: {:?}", nonexistant_port) - // ); -} - -#[test] -fn client_port_fails_to_nonexistant_port() { - let c = open_test_client("cp_can_request_monitor_by_name"); - let p = c.register_port("cpcrmbn_a", AudioIn::default()).unwrap(); - let _p = c.port_by_name(&p.name().unwrap()).unwrap(); -} - -#[test] -fn client_port_recognizes_my_ports() { - let ca = open_test_client("cp_cprmp_ca"); - let cb = open_test_client("cp_cprmp_cb"); - let first = ca.register_port("cpcprmp_pa", AudioIn::default()).unwrap(); - let second = cb.register_port("cpcprmp_pb", AudioIn::default()).unwrap(); - let first_alt = ca.port_by_name(&first.name().unwrap()).unwrap(); - let second_alt = ca.port_by_name(&second.name().unwrap()).unwrap(); - assert!(ca.is_mine(&first)); - assert!(ca.is_mine(&first_alt)); - assert!(!ca.is_mine(&second)); - assert!(!ca.is_mine(&second_alt)); -} - -#[test] -fn client_port_can_connect_ports() { - let client = open_test_client("client_port_ccp"); - - // initialize ports - let in_p = client.register_port("inp", AudioIn::default()).unwrap(); - let out_p = client.register_port("outp", AudioOut::default()).unwrap(); - - // start client - let client = client.activate_async((), ()).unwrap(); - - // connect them - client.as_client().connect_ports(&out_p, &in_p).unwrap(); -} - -#[test] -fn client_port_can_connect_ports_by_name() { - let client = open_test_client("client_port_ccpbn"); - - // initialize ports - let _in_p = client.register_port("inp", AudioIn::default()).unwrap(); - let _out_p = client.register_port("outp", AudioOut::default()).unwrap(); - - // start client - let client = client.activate_async((), ()).unwrap(); - - // connect them - client - .as_client() - .connect_ports_by_name("client_port_ccpbn:outp", "client_port_ccpbn:inp") - .unwrap(); -} - -#[test] -fn client_port_can_connect_unowned_ports() { - let client = open_test_client("client_port_ccup"); - let connector = open_test_client("client_port_ccup_conn"); - - // initialize ports - let _in_p = client.register_port("inp", AudioIn::default()).unwrap(); - let _out_p = client.register_port("outp", AudioOut::default()).unwrap(); - - // start client - let _client = client.activate_async((), ()).unwrap(); - - // connect them - connector - .connect_ports_by_name("client_port_ccup:outp", "client_port_ccup:inp") - .unwrap(); -} - -#[test] -fn client_port_cant_connect_inactive_client() { - let client = open_test_client("client_port_ccic"); - let other = open_test_client("client_port_ccic_other"); - - // initialize ports - let in_p = other - .register_port("inp", AudioIn::default()) - .unwrap() - .name() - .unwrap(); - let out_p = other - .register_port("outp", AudioOut::default()) - .unwrap() - .name() - .unwrap(); - - // Normally we start a client before we begin connecting, but in this case - // we're checking for errors that happen when we connect before activating. - // - // let client = client.activate_async((), ()).unwrap(); - - // connect them - assert_eq!( - client.connect_ports_by_name(&in_p, &out_p).err(), - Some(Error::PortConnectionError(in_p, out_p)) - ); -} - -#[test] -fn client_port_recognizes_already_connected_ports() { - let client = open_test_client("client_port_racp"); - - // initialize ports - let in_p = client.register_port("conna", AudioIn::default()).unwrap(); - let out_p = client.register_port("connb", AudioOut::default()).unwrap(); - - // start client - let client = client.activate_async((), ()).unwrap(); - - // attempt to connect the ports twice - client.as_client().connect_ports(&out_p, &in_p).unwrap(); - assert_eq!( - client.as_client().connect_ports(&out_p, &in_p), - Err(Error::PortAlreadyConnected( - out_p.name().unwrap(), - in_p.name().unwrap(), - )) - ); -} - -#[test] -fn client_port_fails_to_connect_nonexistant_ports() { - let client = open_test_client("client_port_ftcnp") - .activate_async((), ()) - .unwrap(); - assert_eq!( - client - .as_client() - .connect_ports_by_name("doesnt_exist", "also_no_exist"), - Err(Error::PortConnectionError( - "doesnt_exist".to_string(), - "also_no_exist".to_string(), - )) - ); -} - -#[test] -fn client_port_can_disconnect_port_from_all() { - let client = open_test_client("client_port_cdpfa"); - - // initialize ports - let in_p = client.register_port("conna", AudioIn::default()).unwrap(); - let out_p = client.register_port("connb", AudioOut::default()).unwrap(); - - // start client - let client = client.activate_async((), ()).unwrap(); - - // connect and disconnect - client.as_client().connect_ports(&out_p, &in_p).unwrap(); - client.as_client().disconnect(&in_p).unwrap(); -} - -#[test] -fn client_port_can_disconnect_ports() { - let client = open_test_client("client_port_cdp"); - - // initialize ports - let in_p = client.register_port("conna", AudioIn::default()).unwrap(); - let out_p = client.register_port("connb", AudioOut::default()).unwrap(); - - // start client - let client = client.activate_async((), ()).unwrap(); - - // connect and disconnect - client.as_client().connect_ports(&out_p, &in_p).unwrap(); - client.as_client().disconnect_ports(&out_p, &in_p).unwrap(); -} - -#[test] -fn client_port_can_disconnect_ports_by_name() { - let client = open_test_client("client_port_cdpbn"); - - // initialize ports - let in_p = client.register_port("conna", AudioIn::default()).unwrap(); - let out_p = client.register_port("connb", AudioOut::default()).unwrap(); - - // start client - let client = client.activate_async((), ()).unwrap(); - - // connect and disconnect - client - .as_client() - .connect_ports_by_name(&out_p.name().unwrap(), &in_p.name().unwrap()) - .unwrap(); - client - .as_client() - .disconnect_ports_by_name(&out_p.name().unwrap(), &in_p.name().unwrap()) - .unwrap(); -} - -#[test] -fn client_port_can_disconnect_unowned_ports() { - let client = open_test_client("client_port_cdup"); - let disconnector = open_test_client("client_port_cdup_disc"); - - // initialize ports - let in_p = client.register_port("conna", AudioIn::default()).unwrap(); - let out_p = client.register_port("connb", AudioOut::default()).unwrap(); - - // start client - let client = client.activate_async((), ()).unwrap(); - - // connect and disconnect - client - .as_client() - .connect_ports_by_name(&out_p.name().unwrap(), &in_p.name().unwrap()) - .unwrap(); - disconnector - .disconnect_ports_by_name(&out_p.name().unwrap(), &in_p.name().unwrap()) - .unwrap(); -} - -#[test] -fn client_port_can_get_existing_ports() { - let client = open_test_client("client_port_cgep"); - let port_getter = open_test_client("client_port_cgep_getter"); - - // initialize ports - let in_p = client.register_port("conna", AudioIn::default()).unwrap(); - let out_p = client.register_port("connb", AudioOut::default()).unwrap(); - - // retrieve - let known_ports = [ - in_p.name().unwrap(), - out_p.name().unwrap(), - "system:playback_2".to_string(), - "system:playback_1".to_string(), - "system:capture_1".to_string(), - "system:capture_2".to_string(), - ]; - let exp: HashSet = known_ports.iter().cloned().collect(); - let got: HashSet = port_getter - .ports(None, None, PortFlags::empty()) - .into_iter() - .collect(); - let intersection: HashSet = exp.intersection(&got).cloned().collect(); - assert_eq!(exp, intersection); -} - -#[test] -fn client_port_can_get_port_by_name_pattern() { - let client = open_test_client("client_port_cgpbnp"); - - // retrieve - let known_ports = [ - "system:playback_2".to_string(), - "system:capture_2".to_string(), - ]; - let exp: HashSet = known_ports.iter().cloned().collect(); - let got: HashSet = client - .ports(Some("2"), None, PortFlags::empty()) - .into_iter() - .collect(); - assert_eq!(got, exp); -} - -#[test] -fn client_port_can_get_port_by_type_pattern() { - let c_name = "client_port_cgpbtp"; - let p_name = "midip"; - let full_name = format!("{c_name}:{p_name}"); - let client = open_test_client(c_name); - - // register port with type name, like midi - let _p = client.register_port(p_name, MidiIn); - - // retrieve - let ports = client.ports(None, Some("midi"), PortFlags::empty()); - assert!( - ports.contains(&full_name), - "{:?} does not contain {}", - &ports, - &full_name - ); -} diff --git a/src/port/test_port.rs b/src/port/test_port.rs deleted file mode 100644 index a6b253ea2..000000000 --- a/src/port/test_port.rs +++ /dev/null @@ -1,201 +0,0 @@ -use crate::AudioIn; -use crate::AudioOut; -use crate::Client; -use crate::ClientOptions; -use crate::Port; -use crate::PortFlags; -use crate::PortSpec; -use crate::Unowned; - -fn open_test_client(name: &str) -> Client { - Client::new(name, ClientOptions::NO_START_SERVER).unwrap().0 -} - -fn open_client_with_port(client: &str, port: &str) -> (Client, Port) { - let c = open_test_client(client); - let p = c.register_port(port, AudioIn::default()).unwrap(); - (c, p) -} - -#[test] -fn port_can_be_cast_to_unowned() { - let (_c, p) = open_client_with_port("port_cwpn", "the_port_name"); - let p_alt: Port = p.clone_unowned(); - assert_eq!(p.short_name(), p_alt.short_name()); - assert_eq!(p.name(), p_alt.name()); -} - -#[test] -fn port_created_with_proper_names() { - let (_c, p) = open_client_with_port("port_cwpn", "the_port_name"); - assert_eq!(p.short_name().unwrap(), "the_port_name"); - assert_eq!(p.name().unwrap(), "port_cwpn:the_port_name"); -} - -#[test] -fn port_can_rename() { - let client_name = "port_rename"; - let original_name = "port_to_rename"; - let new_name = "port_that_was_renamed"; - - // initial port - let (_c, mut p) = open_client_with_port(client_name, original_name); - assert_eq!(p.name().unwrap(), format!("{client_name}:{original_name}")); - assert_eq!(p.short_name().unwrap(), original_name); - - // renamed port - p.set_name(new_name).unwrap(); - assert_eq!(p.name().unwrap(), format!("{client_name}:{new_name}")); - assert_eq!(p.short_name().unwrap(), new_name); -} - -#[test] -fn port_connected_count() { - let c = open_test_client("port_connected_count"); - let pa = c - .register_port("port_connected_count_a", AudioIn::default()) - .unwrap(); - let pb = c - .register_port("port_connected_count_b", AudioOut::default()) - .unwrap(); - let pc = c - .register_port("port_connected_count_c", AudioOut::default()) - .unwrap(); - let pd = c - .register_port("port_connected_count_d", AudioOut::default()) - .unwrap(); - let c = c.activate_async((), ()).unwrap(); - c.as_client().connect_ports(&pb, &pa).unwrap(); - c.as_client().connect_ports(&pc, &pa).unwrap(); - assert_eq!(pa.connected_count().unwrap(), 2); - assert_eq!(pb.connected_count().unwrap(), 1); - assert_eq!(pc.connected_count().unwrap(), 1); - assert_eq!(pd.connected_count().unwrap(), 0); -} - -#[test] -fn port_knows_connections() { - let c = open_test_client("port_knows_connections"); - let pa = c.register_port("pa", AudioIn::default()).unwrap(); - let pb = c.register_port("pb", AudioOut::default()).unwrap(); - let pc = c.register_port("pc", AudioOut::default()).unwrap(); - let pd = c.register_port("pd", AudioOut::default()).unwrap(); - let c = c.activate_async((), ()).unwrap(); - c.as_client().connect_ports(&pb, &pa).unwrap(); - c.as_client().connect_ports(&pc, &pa).unwrap(); - - // pa - assert!(pa.is_connected_to(&pb.name().unwrap()).unwrap()); - assert!(pa.is_connected_to(&pc.name().unwrap()).unwrap()); - assert!(!pa.is_connected_to(&pd.name().unwrap()).unwrap()); - - // pb - assert!(pb.is_connected_to(&pa.name().unwrap()).unwrap()); - assert!(!pb.is_connected_to(&pc.name().unwrap()).unwrap()); - assert!(!pb.is_connected_to(&pd.name().unwrap()).unwrap()); - - // pc - assert!(pc.is_connected_to(&pa.name().unwrap()).unwrap()); - assert!(!pc.is_connected_to(&pb.name().unwrap()).unwrap()); - assert!(!pc.is_connected_to(&pd.name().unwrap()).unwrap()); - - // pd - assert!(!pd.is_connected_to(&pa.name().unwrap()).unwrap()); - assert!(!pd.is_connected_to(&pb.name().unwrap()).unwrap()); - assert!(!pd.is_connected_to(&pc.name().unwrap()).unwrap()); -} - -#[test] -fn port_can_ensure_monitor() { - let (_c, p) = open_client_with_port("port_can_ensure_monitor", "maybe_monitor"); - - for should_monitor in [true, false].iter().cycle().take(10) { - p.ensure_monitor(*should_monitor).unwrap(); - assert_eq!(p.is_monitoring_input().unwrap(), *should_monitor); - } -} - -#[test] -fn port_can_request_monitor() { - let (_c, p) = open_client_with_port("port_can_ensure_monitor", "maybe_monitor"); - - for should_monitor in [true, false].iter().cycle().take(10) { - p.request_monitor(*should_monitor).unwrap(); - assert_eq!(p.is_monitoring_input().unwrap(), *should_monitor); - } -} - -#[test] -fn port_can_set_alias() { - let (_c, mut p) = open_client_with_port("port_can_set_alias", "will_get_alias"); - - // no alias - assert!(p.aliases().unwrap().is_empty()); - - // 1 alias - p.set_alias("first_alias").unwrap(); - assert_eq!(p.aliases().unwrap(), vec!["first_alias".to_string()]); - - // 2 alias - p.set_alias("second_alias").unwrap(); - assert_eq!( - p.aliases().unwrap(), - vec!["first_alias".to_string(), "second_alias".to_string()] - ); -} - -#[test] -fn port_can_unset_alias() { - let (_c, mut p) = open_client_with_port("port_can_unset_alias", "will_unset_alias"); - - // set aliases - p.set_alias("first_alias").unwrap(); - p.set_alias("second_alias").unwrap(); - assert_eq!( - p.aliases().unwrap(), - vec!["first_alias".to_string(), "second_alias".to_string()] - ); - - // unset alias - p.unset_alias("first_alias").unwrap(); - assert_eq!(p.aliases().unwrap(), vec!["second_alias".to_string()]); -} - -#[test] -fn port_unowned_no_port_type() { - assert_eq!("", Unowned.jack_port_type()); -} - -#[test] -fn port_unowned_no_port_flags() { - assert_eq!(PortFlags::empty(), Unowned.jack_flags()); -} - -#[test] -#[should_panic] -fn port_unowned_no_port_size() { - Unowned.jack_buffer_size(); -} - -#[test] -fn port_debug_printing() { - let (_c, mut p) = open_client_with_port("port_has_debug_string", "debug_info"); - p.set_alias("this_port_alias").unwrap(); - let got = format!("{p:?}"); - let parts = [ - ("name", "Ok(\"port_has_debug_string:debug_info\")"), - ("connections", "0"), - ("port_type", "Ok(\"32 bit float mono audio\")"), - ("port_flags", "PortFlags(IS_INPUT)"), - ("aliases", "[\"this_port_alias\""), - ]; - for &(k, v) in parts.iter() { - let p = format!("{k}: {v}"); - assert!( - got.contains(&p), - "Output:\n{}\nDoes not contain:\n\t{}", - got, - p - ); - } -} diff --git a/src/ringbuffer.rs b/src/ringbuffer.rs index d27d2343f..75c0ddaa7 100644 --- a/src/ringbuffer.rs +++ b/src/ringbuffer.rs @@ -322,137 +322,3 @@ impl Drop for RingBufferWriter { } } } - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn ringbuffer_can_create() { - let ringbuf = RingBuffer::new(1024); - ringbuf.unwrap(); - } - - #[test] - fn ringbuffer_can_space() { - const SIZE: usize = 1024; - const ADVANCE: usize = 5; - let ringbuf = RingBuffer::new(SIZE).unwrap(); - let (mut reader, mut writer) = ringbuf.into_reader_writer(); - - assert_eq!(writer.space(), SIZE - 1); - assert_eq!(reader.space(), 0); - - writer.advance(ADVANCE); - - assert_eq!(writer.space(), SIZE - 1 - ADVANCE); - assert_eq!(reader.space(), ADVANCE); - - reader.advance(ADVANCE); - assert_eq!(writer.space(), SIZE - 1); - assert_eq!(reader.space(), 0); - } - - #[test] - fn ringbuffer_write_read() { - let ringbuf = RingBuffer::new(1024).unwrap(); - let (mut reader, mut writer) = ringbuf.into_reader_writer(); - - let buf = [0_u8, 1, 2, 3]; - let num = writer.write_buffer(&buf); - assert_eq!(num, buf.len()); - - let mut outbuf = [0_u8; 8]; - let num = reader.read_buffer(&mut outbuf); - assert_eq!(num, buf.len()); - - assert_eq!(outbuf[..num], buf[..]); - } - - #[test] - fn ringbuffer_peek_write() { - let ringbuf = RingBuffer::new(1024).unwrap(); - let (reader, mut writer) = ringbuf.into_reader_writer(); - - let buf = [0_u8, 1, 2, 3]; - writer.write_buffer(&buf); - - let data: Vec = reader.peek_iter().copied().collect(); - - assert_eq!(data.len(), buf.len()); - assert_eq!(data[..], buf[..]); - } - - #[test] - fn ringbuffer_write_read_split() { - const BUFSIZE: usize = 10; - let ringbuf = RingBuffer::new(BUFSIZE).unwrap(); - let (mut reader, mut writer) = ringbuf.into_reader_writer(); - - let buf = [0_u8, 1, 2, 3]; - - let advancedsize = BUFSIZE / (buf.len() / 2); - writer.advance(advancedsize); - reader.advance(advancedsize); - { - let (_, v2) = writer.get_vector(); - assert_ne!(v2.len(), 0); - } - - writer.write_buffer(&buf); - - { - let (v1, _) = reader.get_vector(); - assert_ne!(v1.len(), 0); - } - - let data: Vec = reader.peek_iter().copied().collect(); - - assert_eq!(data.len(), buf.len()); - assert_eq!(data[..], buf[..]); - } - - #[test] - fn ringbuffer_peek_read() { - let ringbuf = RingBuffer::new(1024).unwrap(); - let (mut reader, mut writer) = ringbuf.into_reader_writer(); - - let buf = [0_u8, 1, 2, 3]; - for (item, bufitem) in writer.peek_iter().zip(buf.iter()) { - *item = *bufitem; - } - - writer.advance(buf.len()); - - let mut outbuf = [0_u8; 8]; - let num = reader.read_buffer(&mut outbuf); - assert_eq!(num, buf.len()); - - assert_eq!(outbuf[..num], buf[..]); - } - - #[test] - fn ringbuffer_threaded() { - use std::thread; - - let ringbuf = RingBuffer::new(1024).unwrap(); - let (mut reader, mut writer) = ringbuf.into_reader_writer(); - - let buf = [0_u8, 1, 2, 3]; - thread::spawn(move || { - for (item, bufitem) in writer.peek_iter().zip(buf.iter()) { - *item = *bufitem; - } - - writer.advance(buf.len()); - }) - .join() - .unwrap(); - - let mut outbuf = [0_u8; 8]; - let num = reader.read_buffer(&mut outbuf); - assert_eq!(num, buf.len()); - - assert_eq!(outbuf[..num], buf[..]); - } -} diff --git a/src/tests/client.rs b/src/tests/client.rs new file mode 100644 index 000000000..0d32e430c --- /dev/null +++ b/src/tests/client.rs @@ -0,0 +1,7 @@ +#[test] +fn can_open_client() { + let (client, status) = + crate::Client::new("my new client", crate::ClientOptions::empty()).unwrap(); + assert_eq!(status, crate::ClientStatus::empty()); + assert_eq!(client.name(), "my new client"); +} diff --git a/src/tests/mod.rs b/src/tests/mod.rs new file mode 100644 index 000000000..f2cfdf56d --- /dev/null +++ b/src/tests/mod.rs @@ -0,0 +1,7 @@ +mod client; + +#[cfg(test)] +#[ctor::ctor] +fn init() { + crate::set_logger(crate::LoggerType::Stdio); +} diff --git a/src/transport.rs b/src/transport.rs index de9692d57..915b5d9b0 100644 --- a/src/transport.rs +++ b/src/transport.rs @@ -496,318 +496,3 @@ impl Default for TransportBBT { } } } - -#[cfg(test)] -mod test { - mod position { - use crate::{TransportBBT, TransportPosition}; - #[test] - fn default() { - let p: TransportPosition = Default::default(); - assert!(!p.valid_bbt()); - assert!(!p.valid_bbt_frame_offset()); - assert_eq!(p.frame(), 0); - assert_eq!(p.bbt(), None); - assert_eq!(p.bbt_offset(), None); - assert_eq!(p.frame_rate(), None); - assert_eq!(p.usecs(), None); - } - - #[test] - fn usecs() { - let mut p: TransportPosition = Default::default(); - assert_eq!(p.usecs(), None); - p.0.usecs = 1; - assert_eq!(p.usecs(), Some(1)); - p.0.usecs = 0; - assert_eq!(p.usecs(), None); - p.0.usecs = 2084; - assert_eq!(p.usecs(), Some(2084)); - } - - #[test] - fn frame_rate() { - let mut p: TransportPosition = Default::default(); - assert_eq!(p.frame_rate(), None); - p.0.frame_rate = 44100; - assert_eq!(p.frame_rate(), Some(44100)); - p.0.frame_rate = 0; - assert_eq!(p.frame_rate(), None); - p.0.frame_rate = 48000; - assert_eq!(p.frame_rate(), Some(48000)); - } - - #[test] - fn bbt_invalid() { - let mut i: TransportPosition = Default::default(); - let mut v: TransportPosition = Default::default(); - let def: TransportBBT = Default::default(); - - assert!(!i.valid_bbt()); - assert_eq!(i.set_bbt(None), Ok(())); - assert!(!i.valid_bbt()); - - assert!(!v.valid_bbt()); - assert_eq!(v.set_bbt(Some(def)), Ok(())); - assert_eq!(v.bbt(), Some(def)); - - let mut t = |b| { - assert!(i.set_bbt(Some(b)).is_err()); - assert!(v.set_bbt(Some(b)).is_err()); - assert!(!i.valid_bbt()); - assert!(v.valid_bbt()); - assert_eq!(i.bbt(), None); - assert_eq!(v.bbt(), Some(def)); - }; - - let mut bbt = TransportBBT { - bar: 0, - ..Default::default() - }; - t(bbt); - - bbt = Default::default(); - bbt.beat = 0; - t(bbt); - - bbt.beat = 5; - t(bbt); - - bbt = Default::default(); - bbt.tick = 1921; - t(bbt); - bbt.tick = 1920; - t(bbt); - - bbt = Default::default(); - bbt.bpm = -1.0; - t(bbt); - - bbt = Default::default(); - bbt.ticks_per_beat = -1.0; - t(bbt); - bbt.ticks_per_beat = 0.0; - t(bbt); - - bbt = Default::default(); - bbt.sig_num = 0.0; - t(bbt); - bbt.sig_num = -1.0; - t(bbt); - - bbt = Default::default(); - bbt.sig_denom = 0.0; - t(bbt); - bbt.sig_denom = -1.0; - t(bbt); - - bbt = Default::default(); - bbt.sig_num = 7.0; - bbt.beat = 8; - t(bbt); - - bbt = Default::default(); - bbt.ticks_per_beat = 96.0; - bbt.tick = 96; - t(bbt); - } - - #[test] - fn bbt_valid() { - let mut p: TransportPosition = Default::default(); - let mut b: TransportBBT = Default::default(); - let i = TransportBBT { - beat: 5, //invalid - ..Default::default() - }; - - assert!(!i.valid()); - - assert!(!p.valid_bbt()); - assert_eq!(p.set_bbt(Some(b)), Ok(())); - assert!(p.valid_bbt()); - assert_eq!(p.bbt(), Some(b)); - - let mut t = |b: TransportBBT| { - assert!(b.valid()); - assert_eq!(p.set_bbt(Some(b)), Ok(())); - assert_eq!(p.bbt(), Some(b)); - assert!(p.set_bbt(Some(i)).is_err()); - assert_eq!(p.bbt(), Some(b)); - }; - - for i in 1..10 { - b.bar = i; - t(b); - } - - for i in 1..=4 { - b.beat = i; - t(b); - } - - b.sig_num = 7.; - for i in 1..=7 { - b.beat = i; - t(b); - } - - b.beat = 1; - b.sig_num = 4.; - b.ticks_per_beat = 96.0; - for i in 0..96 { - b.tick = i; - t(b); - } - - for i in (10..300).step_by(7) { - b.bpm = i as _; - t(b); - } - } - } - mod bbt { - use crate::{TransportBBT, TransportBBTValidationError}; - - fn approx_eq(a: f32, b: f32) -> bool { - (a - b).abs() < f32::EPSILON - } - - #[test] - fn default() { - let bbt: TransportBBT = Default::default(); - assert_eq!(bbt.bar, 1); - assert_eq!(bbt.beat, 1); - assert_eq!(bbt.tick, 0); - assert!(approx_eq(bbt.sig_num, 4.0), "{} != {}", bbt.sig_num, 4.0); - assert!( - approx_eq(bbt.sig_denom, 4.0), - "{} != {}", - bbt.sig_denom, - 4.0 - ); - assert!( - approx_eq(bbt.ticks_per_beat as f32, 1920.0), - "{} != {}", - bbt.ticks_per_beat, - 1920.0 - ); - assert!(approx_eq(bbt.bpm as f32, 120.0), "{} != {}", bbt.bpm, 120.0); - assert!( - approx_eq(bbt.bar_start_tick as f32, 0.0), - "{} != {}", - bbt.bar_start_tick, - 0.0 - ); - } - - #[test] - fn builder_valid() { - let mut bbt = TransportBBT::default(); - assert_eq!( - TransportBBT::default().with_bbt(1, 1, 0).validated(), - Ok(bbt) - ); - - bbt.bar = 100; - bbt.beat = 2; - bbt.tick = 230; - assert_eq!( - TransportBBT::default().with_bbt(100, 2, 230).validated(), - Ok(bbt) - ); - - bbt = Default::default(); - bbt.sig_num = 7.0; - bbt.sig_denom = 8.0; - assert_eq!( - TransportBBT::default().with_timesig(7.0, 8.0).validated(), - Ok(bbt) - ); - - bbt = Default::default(); - bbt.ticks_per_beat = 2000.0; - assert_eq!( - TransportBBT::default() - .with_ticks_per_beat(2000.0) - .validated(), - Ok(bbt) - ); - - bbt = Default::default(); - bbt.bar_start_tick = 1023.0; - assert_eq!( - TransportBBT::default() - .with_bar_start_tick(1023.0) - .validated(), - Ok(bbt) - ); - - bbt = Default::default(); - bbt.bar = 2; - bbt.beat = 3; - bbt.tick = 20; - bbt.bpm = 23.0; - bbt.ticks_per_beat = 96.0; - bbt.sig_num = 12.0; - bbt.sig_denom = 5.0; - bbt.bar_start_tick = 4.3; - - assert_eq!( - TransportBBT::default() - .with_bbt(bbt.bar, bbt.beat, bbt.tick) - .with_bpm(bbt.bpm) - .with_ticks_per_beat(bbt.ticks_per_beat) - .with_timesig(bbt.sig_num, bbt.sig_denom) - .with_bar_start_tick(bbt.bar_start_tick) - .validated(), - Ok(bbt) - ); - - //can simply use setters, could create invalid data.. - bbt = TransportBBT::default(); - bbt.with_bpm(120.0); - assert!( - approx_eq(bbt.bpm as f32, 120.0), - "{} != {},", - bbt.bpm, - 120.0 - ); - } - - #[test] - fn builder_invalid() { - let mut bbt = TransportBBT { - bpm: -1023.0, - ..TransportBBT::default() - }; - assert_eq!( - TransportBBT::default().with_bpm(bbt.bpm).validated(), - Err(TransportBBTValidationError::BPMRange) - ); - - bbt = Default::default(); - bbt.bar = 0; - assert_eq!( - TransportBBT::default().with_bbt(0, 1, 0).validated(), - Err(TransportBBTValidationError::BarZero) - ); - - bbt = Default::default(); - bbt.tick = bbt.ticks_per_beat as usize; - assert_eq!( - TransportBBT::default().with_bbt(1, 1, bbt.tick).validated(), - Err(TransportBBTValidationError::TickRange) - ); - - for beat in &[0, 7] { - bbt = Default::default(); - bbt.beat = *beat; - assert_eq!( - TransportBBT::default().with_bbt(1, bbt.beat, 0).validated(), - Err(TransportBBTValidationError::BeatRange) - ); - } - } - } -}