use fluxion_core::StreamItem;
use fluxion_stream::prelude::*;
use fluxion_stream::{CombinedState, WithPrevious};
use fluxion_test_utils::{
helpers::{assert_no_element_emitted, unwrap_stream},
test_channel,
test_data::{person_alice, person_bob, person_charlie, person_dave, person_diane, TestData},
unwrap_value, Sequenced,
};
use futures::StreamExt;
#[tokio::test]
async fn test_ordered_merge_combine_with_previous_emit_when() -> anyhow::Result<()> {
let (person1_tx, person1_rx) = test_channel::<Sequenced<TestData>>();
let (person2_tx, person2_rx) = test_channel::<Sequenced<TestData>>();
let (threshold_tx, threshold_rx) = test_channel::<Sequenced<TestData>>();
let person1_stream = person1_rx;
let person2_stream = person2_rx;
let threshold_stream = threshold_rx;
let filter_fn = |state: &CombinedState<TestData>| -> bool {
let values = state.values();
let current_age = match &values[0] {
TestData::Person(p) => p.age,
_ => return false,
};
let threshold_age = match &values[1] {
TestData::Person(p) => p.age,
_ => return false,
};
current_age >= threshold_age
};
let threshold_mapped =
threshold_stream.map(|seq| StreamItem::Value(WithPrevious::new(None, seq.unwrap())));
let mut output_stream = person1_stream
.ordered_merge(vec![person2_stream])
.combine_with_previous()
.emit_when(threshold_mapped, filter_fn);
threshold_tx.unbounded_send(Sequenced::new(person_bob()))?;
person1_tx.unbounded_send(Sequenced::new(person_alice()))?;
assert_no_element_emitted(&mut output_stream, 100).await;
person2_tx.unbounded_send(Sequenced::new(person_charlie()))?;
let emitted = unwrap_value(Some(unwrap_stream(&mut output_stream, 500).await));
assert_eq!(
&emitted.current.value,
&person_charlie(),
"Expected Charlie (35) to be emitted when >= threshold (30)"
);
person1_tx.unbounded_send(Sequenced::new(person_dave()))?;
assert_no_element_emitted(&mut output_stream, 100).await;
person2_tx.unbounded_send(Sequenced::new(person_diane()))?;
let emitted = unwrap_value(Some(unwrap_stream(&mut output_stream, 500).await));
assert_eq!(
&emitted.current.value,
&person_diane(),
"Expected Diane (40) to be emitted when >= threshold (30)"
);
threshold_tx.unbounded_send(Sequenced::new(person_alice()))?;
let emitted = unwrap_value(Some(unwrap_stream(&mut output_stream, 500).await));
assert_eq!(
&emitted.current.value,
&person_diane(),
"Expected Diane (40) to be re-emitted when threshold changes to 25"
);
person1_tx.unbounded_send(Sequenced::new(person_bob()))?;
let emitted = unwrap_value(Some(unwrap_stream(&mut output_stream, 500).await));
assert_eq!(
&emitted.current.value,
&person_bob(),
"Expected Bob (30) to be emitted when >= threshold (25)"
);
Ok(())
}
#[tokio::test]
async fn test_combine_with_previous_emit_when_map_ordered() -> anyhow::Result<()> {
let (source_tx, source_rx) = test_channel::<Sequenced<TestData>>();
let (threshold_tx, threshold_rx) = test_channel::<Sequenced<TestData>>();
let source_stream = source_rx;
let threshold_stream = threshold_rx;
let filter_fn = |state: &CombinedState<TestData, u64>| -> bool {
let values = state.values();
let current_age = match &values[0] {
TestData::Person(p) => p.age,
_ => return false,
};
let threshold_age = match &values[1] {
TestData::Person(p) => p.age,
_ => return false,
};
current_age >= threshold_age
};
let mut stream = source_stream
.combine_with_previous()
.map_ordered(|wp| wp.current)
.emit_when(threshold_stream, filter_fn);
threshold_tx.unbounded_send(Sequenced::new(person_bob()))?; source_tx.unbounded_send(Sequenced::new(person_alice()))?; assert_no_element_emitted(&mut stream, 100).await;
source_tx.unbounded_send(Sequenced::new(person_charlie()))?; let result = unwrap_value(Some(unwrap_stream(&mut stream, 500).await));
assert_eq!(result.value, person_charlie());
Ok(())
}