Skip to content

Commit 162d68e

Browse files
committed
tests: add tests for playback/record stream channel invariants
1 parent 7aaec49 commit 162d68e

File tree

3 files changed

+175
-0
lines changed

3 files changed

+175
-0
lines changed

src/protocol/command/playback_stream.rs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ pub struct PlaybackStreamParams {
1313
pub sample_spec: SampleSpec,
1414

1515
/// Channel map for the stream.
16+
///
17+
/// Number of channels should match `sample_spec.channels`.
1618
pub channel_map: ChannelMap,
1719

1820
/// Index of the sink to connect to.
@@ -28,6 +30,8 @@ pub struct PlaybackStreamParams {
2830
pub sync_id: u32,
2931

3032
/// Volume of the stream.
33+
///
34+
/// Number of channels should match `sample_spec.channels`.
3135
pub cvolume: Option<ChannelVolume>,
3236

3337
/// Additional properties for the stream.
@@ -370,4 +374,61 @@ mod integration_tests {
370374

371375
Ok(())
372376
}
377+
378+
/// Tests that PlaybackStreamParams maintains consistent
379+
/// channel counts across its implicitly set fields.
380+
#[test]
381+
fn create_playback_stream_channel_count_invariants() -> anyhow::Result<()> {
382+
let (mut sock, protocol_version) = connect_and_init()?;
383+
384+
// Arbitrarily chosen number of channels that should be kept in sync
385+
// across fields (chosen to test beyond the usual 1 or 2).
386+
const CHANNEL_COUNT: u8 = 3;
387+
388+
// Explicitly set case (for reference).
389+
{
390+
write_command_message(
391+
sock.get_mut(),
392+
0,
393+
&Command::CreatePlaybackStream(PlaybackStreamParams {
394+
sample_spec: SampleSpec {
395+
format: SampleFormat::S16Le,
396+
channels: CHANNEL_COUNT,
397+
..Default::default()
398+
},
399+
sync_id: 0,
400+
channel_map: ChannelMap::with_n_channels(CHANNEL_COUNT),
401+
cvolume: Some(ChannelVolume::norm(CHANNEL_COUNT)),
402+
..Default::default()
403+
}),
404+
protocol_version,
405+
)?;
406+
407+
let _ = read_reply_message::<CreatePlaybackStreamReply>(&mut sock, protocol_version)?;
408+
}
409+
410+
// Implicitly set case (on fields that allow it).
411+
{
412+
write_command_message(
413+
sock.get_mut(),
414+
1,
415+
&Command::CreatePlaybackStream(PlaybackStreamParams {
416+
sample_spec: SampleSpec {
417+
format: SampleFormat::S16Le,
418+
channels: CHANNEL_COUNT,
419+
..Default::default()
420+
},
421+
sync_id: 1,
422+
channel_map: ChannelMap::with_n_channels(CHANNEL_COUNT),
423+
cvolume: None,
424+
..Default::default()
425+
}),
426+
protocol_version,
427+
)?;
428+
429+
let _ = read_reply_message::<CreatePlaybackStreamReply>(&mut sock, protocol_version)?;
430+
}
431+
432+
Ok(())
433+
}
373434
}

src/protocol/command/record_stream.rs

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ pub struct RecordStreamParams {
1313
pub sample_spec: SampleSpec,
1414

1515
/// Channel map for the stream.
16+
///
17+
/// Number of channels should match `sample_spec.channels`.
1618
pub channel_map: ChannelMap,
1719

1820
/// Index of the source to connect to.
@@ -32,6 +34,8 @@ pub struct RecordStreamParams {
3234
pub direct_on_input_index: Option<u32>,
3335

3436
/// Volume of the stream.
37+
///
38+
/// Number of channels should match `sample_spec.channels`.
3539
pub cvolume: Option<ChannelVolume>,
3640

3741
/// Additional properties for the stream.
@@ -304,3 +308,98 @@ mod tests {
304308
test_serde(&reply)
305309
}
306310
}
311+
312+
#[cfg(test)]
313+
#[cfg(feature = "_integration-tests")]
314+
mod integration_tests {
315+
use super::*;
316+
use crate::integration_test_util::*;
317+
use crate::protocol::*;
318+
319+
#[test]
320+
fn create_playback_stream() -> anyhow::Result<()> {
321+
let (mut sock, protocol_version) = connect_and_init()?;
322+
323+
write_command_message(
324+
sock.get_mut(),
325+
0,
326+
&Command::CreatePlaybackStream(PlaybackStreamParams {
327+
sample_spec: SampleSpec {
328+
format: SampleFormat::S16Le,
329+
sample_rate: 44100,
330+
channels: 2,
331+
},
332+
channel_map: ChannelMap::stereo(),
333+
cvolume: Some(ChannelVolume::norm(2)),
334+
flags: StreamFlags {
335+
start_corked: true,
336+
start_muted: Some(true),
337+
..Default::default()
338+
},
339+
sink_index: None,
340+
sink_name: Some(CString::new("@DEFAULT_SINK@")?),
341+
..Default::default()
342+
}),
343+
protocol_version,
344+
)?;
345+
346+
let _ = read_reply_message::<CreatePlaybackStreamReply>(&mut sock, protocol_version)?;
347+
348+
Ok(())
349+
}
350+
351+
/// Tests that RecordStreamParams maintains consistent
352+
/// channel counts across its implicitly set fields.
353+
#[test]
354+
fn create_record_stream_channel_count_invariants() -> anyhow::Result<()> {
355+
let (mut sock, protocol_version) = connect_and_init()?;
356+
357+
// Arbitrarily chosen number of channels that should be kept in sync
358+
// across fields (chosen to test beyond the usual 1 or 2).
359+
const CHANNEL_COUNT: u8 = 3;
360+
361+
// Explicitly set case (for reference).
362+
{
363+
write_command_message(
364+
sock.get_mut(),
365+
0,
366+
&Command::CreateRecordStream(RecordStreamParams {
367+
sample_spec: SampleSpec {
368+
format: SampleFormat::S16Le,
369+
channels: CHANNEL_COUNT,
370+
..Default::default()
371+
},
372+
channel_map: ChannelMap::with_n_channels(CHANNEL_COUNT),
373+
cvolume: Some(ChannelVolume::norm(CHANNEL_COUNT)),
374+
..Default::default()
375+
}),
376+
protocol_version,
377+
)?;
378+
379+
let _ = read_reply_message::<CreateRecordStreamReply>(&mut sock, protocol_version)?;
380+
}
381+
382+
// Implicitly set case (on fields that allow it).
383+
{
384+
write_command_message(
385+
sock.get_mut(),
386+
1,
387+
&Command::CreateRecordStream(RecordStreamParams {
388+
sample_spec: SampleSpec {
389+
format: SampleFormat::S16Le,
390+
channels: CHANNEL_COUNT,
391+
..Default::default()
392+
},
393+
channel_map: ChannelMap::with_n_channels(CHANNEL_COUNT),
394+
cvolume: None,
395+
..Default::default()
396+
}),
397+
protocol_version,
398+
)?;
399+
400+
let _ = read_reply_message::<CreateRecordStreamReply>(&mut sock, protocol_version)?;
401+
}
402+
403+
Ok(())
404+
}
405+
}

src/protocol/serde/channel_map.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,21 @@ impl ChannelMap {
129129
map
130130
}
131131

132+
/// Creates a channel map with N (arbitrarily chosen) channels.
133+
///
134+
/// Intended for testing cases where only the number of channels matters.
135+
#[cfg(test)]
136+
#[cfg(feature = "_integration-tests")]
137+
pub(crate) fn with_n_channels(channels: u8) -> Self {
138+
let mut map = ChannelMap::empty();
139+
for pos in
140+
(1..=channels).map(|idx| ChannelPosition::from_u8(idx).expect("known channel index"))
141+
{
142+
map.push(pos);
143+
}
144+
map
145+
}
146+
132147
/// Tries to append another `ChannelPosition` to the end of this map.
133148
///
134149
/// Panics if the map already has MAX_CHANNELS channels.

0 commit comments

Comments
 (0)