Skip to content

Commit 8535a10

Browse files
authored
chore: add a regression test to ensure correct behavior for keyed store fields (see discussion in #4473) (#4483)
1 parent 7864a12 commit 8535a10

File tree

1 file changed

+141
-0
lines changed

1 file changed

+141
-0
lines changed

reactive_stores/src/keyed.rs

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -713,3 +713,144 @@ where
713713
.map(|key| AtKeyed::new(self.inner.clone(), key))
714714
}
715715
}
716+
717+
#[cfg(test)]
718+
mod tests {
719+
use crate::{self as reactive_stores, tests::tick, AtKeyed, Store};
720+
use reactive_graph::{
721+
effect::Effect,
722+
traits::{GetUntracked, ReadUntracked, Set, Track, Write},
723+
};
724+
use std::sync::{
725+
atomic::{AtomicUsize, Ordering},
726+
Arc,
727+
};
728+
729+
#[derive(Debug, Store, Default)]
730+
struct Todos {
731+
#[store(key: usize = |todo| todo.id)]
732+
todos: Vec<Todo>,
733+
}
734+
735+
#[derive(Debug, Store, Default, Clone, PartialEq, Eq)]
736+
struct Todo {
737+
id: usize,
738+
label: String,
739+
}
740+
741+
impl Todo {
742+
pub fn new(id: usize, label: impl ToString) -> Self {
743+
Self {
744+
id,
745+
label: label.to_string(),
746+
}
747+
}
748+
}
749+
750+
fn data() -> Todos {
751+
Todos {
752+
todos: vec![
753+
Todo {
754+
id: 10,
755+
label: "A".to_string(),
756+
},
757+
Todo {
758+
id: 11,
759+
label: "B".to_string(),
760+
},
761+
Todo {
762+
id: 12,
763+
label: "C".to_string(),
764+
},
765+
],
766+
}
767+
}
768+
#[tokio::test]
769+
async fn keyed_fields_can_be_moved() {
770+
_ = any_spawner::Executor::init_tokio();
771+
772+
let store = Store::new(data());
773+
assert_eq!(store.read_untracked().todos.len(), 3);
774+
775+
// create an effect to read from each keyed field
776+
let a_count = Arc::new(AtomicUsize::new(0));
777+
let b_count = Arc::new(AtomicUsize::new(0));
778+
let c_count = Arc::new(AtomicUsize::new(0));
779+
780+
let a = AtKeyed::new(store.todos(), 10);
781+
let b = AtKeyed::new(store.todos(), 11);
782+
let c = AtKeyed::new(store.todos(), 12);
783+
784+
Effect::new_sync({
785+
let a_count = Arc::clone(&a_count);
786+
move || {
787+
a.track();
788+
a_count.fetch_add(1, Ordering::Relaxed);
789+
}
790+
});
791+
Effect::new_sync({
792+
let b_count = Arc::clone(&b_count);
793+
move || {
794+
b.track();
795+
b_count.fetch_add(1, Ordering::Relaxed);
796+
}
797+
});
798+
Effect::new_sync({
799+
let c_count = Arc::clone(&c_count);
800+
move || {
801+
c.track();
802+
c_count.fetch_add(1, Ordering::Relaxed);
803+
}
804+
});
805+
806+
tick().await;
807+
assert_eq!(a_count.load(Ordering::Relaxed), 1);
808+
assert_eq!(b_count.load(Ordering::Relaxed), 1);
809+
assert_eq!(c_count.load(Ordering::Relaxed), 1);
810+
811+
// writing at a key doesn't notify siblings
812+
*a.label().write() = "Foo".into();
813+
tick().await;
814+
assert_eq!(a_count.load(Ordering::Relaxed), 2);
815+
assert_eq!(b_count.load(Ordering::Relaxed), 1);
816+
assert_eq!(c_count.load(Ordering::Relaxed), 1);
817+
818+
// the keys can be reorganized
819+
store.todos().write().swap(0, 2);
820+
let after = store.todos().get_untracked();
821+
assert_eq!(
822+
after,
823+
vec![Todo::new(12, "C"), Todo::new(11, "B"), Todo::new(10, "Foo")]
824+
);
825+
826+
tick().await;
827+
assert_eq!(a_count.load(Ordering::Relaxed), 2);
828+
assert_eq!(b_count.load(Ordering::Relaxed), 1);
829+
assert_eq!(c_count.load(Ordering::Relaxed), 1);
830+
831+
// and after we move the keys around, they still update the moved items
832+
a.label().set("Bar".into());
833+
let after = store.todos().get_untracked();
834+
assert_eq!(
835+
after,
836+
vec![Todo::new(12, "C"), Todo::new(11, "B"), Todo::new(10, "Bar")]
837+
);
838+
tick().await;
839+
assert_eq!(a_count.load(Ordering::Relaxed), 3);
840+
assert_eq!(b_count.load(Ordering::Relaxed), 1);
841+
assert_eq!(c_count.load(Ordering::Relaxed), 1);
842+
843+
// we can remove a key and add a new one
844+
store.todos().write().pop();
845+
store.todos().write().push(Todo::new(13, "New"));
846+
let after = store.todos().get_untracked();
847+
assert_eq!(
848+
after,
849+
vec![Todo::new(12, "C"), Todo::new(11, "B"), Todo::new(13, "New")]
850+
);
851+
tick().await;
852+
assert_eq!(a_count.load(Ordering::Relaxed), 3);
853+
assert_eq!(b_count.load(Ordering::Relaxed), 1);
854+
assert_eq!(c_count.load(Ordering::Relaxed), 1);
855+
}
856+
}

0 commit comments

Comments
 (0)