From 03dd222fe886bf285e4928360c661430eb5366ea Mon Sep 17 00:00:00 2001 From: Benjamin Woodruff Date: Thu, 25 Jul 2024 14:24:58 -0700 Subject: [PATCH] Add and move tests for Vc generics --- crates/turbo-tasks-memory/tests/all_in_one.rs | 58 +---- crates/turbo-tasks-memory/tests/generics.rs | 203 ++++++++++++++++++ 2 files changed, 204 insertions(+), 57 deletions(-) create mode 100644 crates/turbo-tasks-memory/tests/generics.rs diff --git a/crates/turbo-tasks-memory/tests/all_in_one.rs b/crates/turbo-tasks-memory/tests/all_in_one.rs index b58ea58964bff..91f2cf36980af 100644 --- a/crates/turbo-tasks-memory/tests/all_in_one.rs +++ b/crates/turbo-tasks-memory/tests/all_in_one.rs @@ -1,8 +1,7 @@ #![feature(arbitrary_self_types)] use anyhow::{anyhow, bail, Result}; -use indexmap::{IndexMap, IndexSet}; -use turbo_tasks::{debug::ValueDebug, RcStr, Value, ValueToString, Vc}; +use turbo_tasks::{RcStr, Value, ValueToString, Vc}; use turbo_tasks_testing::{register, run, Registration}; static REGISTRATION: Registration = register!(); @@ -55,61 +54,6 @@ async fn all_in_one() { let c_erased_invalid: Vc> = a_erased.add(b_erased_other); assert!(c_erased_invalid.resolve().await.is_err()); - // Testing generic types. - - let vc_42 = Vc::cell(42); - - let option: Vc>> = Vc::cell(Some(vc_42)); - assert_eq!(*option.is_some().await?, true); - assert_eq!(*option.is_none().await?, false); - assert_eq!(&*option.await?, &Some(vc_42)); - assert_eq!(option.dbg().await?.to_string(), "Some(\n 42,\n)"); - - let option: Vc>> = Default::default(); - assert_eq!(*option.is_some().await?, false); - assert_eq!(*option.is_none().await?, true); - assert_eq!(&*option.await?, &None); - assert_eq!(option.dbg().await?.to_string(), "None"); - - let vec: Vc>> = Vc::cell(vec![vc_42]); - assert_eq!(*vec.len().await?, 1); - assert_eq!(*vec.is_empty().await?, false); - assert_eq!(&*vec.await?, &[vc_42]); - assert_eq!(vec.dbg().await?.to_string(), "[\n 42,\n]"); - - let vec: Vc>> = Default::default(); - assert_eq!(*vec.len().await?, 0); - assert_eq!(*vec.is_empty().await?, true); - assert_eq!(vec.dbg().await?.to_string(), "[]"); - - let vec: Vc>>>> = Default::default(); - assert_eq!(*vec.len().await?, 0); - assert_eq!(vec.dbg().await?.to_string(), "[]"); - - let set: Vc>> = Vc::cell(IndexSet::from([vc_42])); - assert_eq!(*set.len().await?, 1); - assert_eq!(*set.is_empty().await?, false); - assert_eq!(&*set.await?, &IndexSet::from([vc_42])); - assert_eq!(set.dbg().await?.to_string(), "{\n 42,\n}"); - - let set: Vc>> = Default::default(); - assert_eq!(*set.len().await?, 0); - assert_eq!(*set.is_empty().await?, true); - assert_eq!(&*set.await?, &IndexSet::>::default()); - assert_eq!(set.dbg().await?.to_string(), "{}"); - - let map: Vc> = Vc::cell(IndexMap::from([(vc_42, vc_42)])); - assert_eq!(*map.len().await?, 1); - assert_eq!(*map.is_empty().await?, false); - assert_eq!(&*map.await?, &IndexMap::from([(vc_42, vc_42)])); - assert_eq!(map.dbg().await?.to_string(), "{\n 42: 42,\n}"); - - let map: Vc, Vc>> = Default::default(); - assert_eq!(*map.len().await?, 0); - assert_eq!(*map.is_empty().await?, true); - assert_eq!(&*map.await?, &IndexMap::, Vc>::default()); - assert_eq!(map.dbg().await?.to_string(), "{}"); - anyhow::Ok(()) }) .await diff --git a/crates/turbo-tasks-memory/tests/generics.rs b/crates/turbo-tasks-memory/tests/generics.rs new file mode 100644 index 0000000000000..9df0a75b0f537 --- /dev/null +++ b/crates/turbo-tasks-memory/tests/generics.rs @@ -0,0 +1,203 @@ +#![feature(arbitrary_self_types)] + +use std::sync::{Arc, Mutex}; + +use indexmap::{IndexMap, IndexSet}; +use turbo_tasks::{debug::ValueDebug, Invalidator, ReadRef, TaskId, Vc}; +use turbo_tasks_testing::{register, run, Registration}; + +static REGISTRATION: Registration = register!(); + +#[tokio::test] +async fn test_option_some() { + run(®ISTRATION, async move { + let vc_42 = Vc::cell(42); + let option: Vc>> = Vc::cell(Some(vc_42)); + assert_eq!(*option.is_some().await.unwrap(), true); + assert_eq!(*option.is_none().await.unwrap(), false); + assert_eq!(&*option.await.unwrap(), &Some(vc_42)); + assert_eq!(option.dbg().await.unwrap().to_string(), "Some(\n 42,\n)"); + }) + .await +} + +#[tokio::test] +async fn test_option_none() { + run(®ISTRATION, async move { + let option: Vc>> = Default::default(); + assert_eq!(*option.is_some().await.unwrap(), false); + assert_eq!(*option.is_none().await.unwrap(), true); + assert_eq!(&*option.await.unwrap(), &None); + assert_eq!(option.dbg().await.unwrap().to_string(), "None"); + }) + .await +} + +#[tokio::test] +async fn test_vec() { + run(®ISTRATION, async move { + let vc_42 = Vc::cell(42); + let vec: Vc>> = Vc::cell(vec![vc_42]); + assert_eq!(*vec.len().await.unwrap(), 1); + assert_eq!(*vec.is_empty().await.unwrap(), false); + assert_eq!(&*vec.await.unwrap(), &[vc_42]); + assert_eq!(vec.dbg().await.unwrap().to_string(), "[\n 42,\n]"); + }) + .await +} + +#[tokio::test] +async fn test_empty_vec() { + run(®ISTRATION, async move { + let vec: Vc>> = Default::default(); + assert_eq!(*vec.len().await.unwrap(), 0); + assert_eq!(*vec.is_empty().await.unwrap(), true); + assert_eq!(vec.dbg().await.unwrap().to_string(), "[]"); + }) + .await +} + +#[tokio::test] +async fn test_nested_empty_vec() { + run(®ISTRATION, async move { + let vec: Vc>>>> = Default::default(); + assert_eq!(*vec.len().await.unwrap(), 0); + assert_eq!(vec.dbg().await.unwrap().to_string(), "[]"); + }) + .await +} + +#[tokio::test] +async fn test_index_set() { + run(®ISTRATION, async move { + let vc_42 = Vc::cell(42); + let set: Vc>> = Vc::cell(IndexSet::from([vc_42])); + assert_eq!(*set.len().await.unwrap(), 1); + assert_eq!(*set.is_empty().await.unwrap(), false); + assert_eq!(&*set.await.unwrap(), &IndexSet::from([vc_42])); + assert_eq!(set.dbg().await.unwrap().to_string(), "{\n 42,\n}"); + }) + .await +} + +#[tokio::test] +async fn test_empty_index_set() { + run(®ISTRATION, async move { + let set: Vc>> = Default::default(); + assert_eq!(*set.len().await.unwrap(), 0); + assert_eq!(*set.is_empty().await.unwrap(), true); + assert_eq!(&*set.await.unwrap(), &IndexSet::>::default()); + assert_eq!(set.dbg().await.unwrap().to_string(), "{}"); + }) + .await +} + +#[tokio::test] +async fn test_index_map() { + run(®ISTRATION, async move { + let vc_42 = Vc::cell(42); + let map: Vc, _>> = Vc::cell(IndexMap::from([(vc_42, vc_42)])); + assert_eq!(*map.len().await.unwrap(), 1); + assert_eq!(*map.is_empty().await.unwrap(), false); + assert_eq!(&*map.await.unwrap(), &IndexMap::from([(vc_42, vc_42)])); + assert_eq!(map.dbg().await.unwrap().to_string(), "{\n 42: 42,\n}"); + }) + .await +} + +#[tokio::test] +async fn test_empty_index_map() { + run(®ISTRATION, async move { + let map: Vc, Vc>> = Default::default(); + assert_eq!(*map.len().await.unwrap(), 0); + assert_eq!(*map.is_empty().await.unwrap(), true); + assert_eq!( + &*map.await.unwrap(), + &IndexMap::, Vc>::default() + ); + assert_eq!(map.dbg().await.unwrap().to_string(), "{}"); + }) + .await +} + +// Simulate a non-deterministic function that stores different generic types in +// it's cells each time it runs. +#[tokio::test] +async fn test_changing_generic() { + run(®ISTRATION, async move { + let state_vc = State::default().cell(); + let state_ref = state_vc.await.unwrap(); + for _i in 0..10 { + let _ = non_deterministic(state_vc) + .resolve_strongly_consistent() + .await + .unwrap(); + state_ref + .inner + .lock() + .unwrap() + .last_invalidator + .take() + .unwrap() + .invalidate(); + } + }) + .await +} + +// Test that we can convert a `Vc` to a `ReadRef`, and then back to a `Vc`. +#[tokio::test] +#[ignore = "TODO: This panics! There's a casting bug in the generics implementation."] +async fn test_read_ref_round_trip() { + run(®ISTRATION, async move { + let c: Vc>> = Vc::cell(Some(Vc::cell(1))); + let _ = ReadRef::cell(c.await.unwrap()).await.unwrap(); + }) + .await +} + +#[turbo_tasks::value(eq = "manual")] +#[derive(Default)] +struct State { + #[turbo_tasks(debug_ignore, trace_ignore)] + #[serde(skip)] + inner: Arc>, +} + +#[derive(Default)] +struct StateInner { + branch: bool, + last_invalidator: Option, + last_task_id: Option, +} + +impl PartialEq for State { + fn eq(&self, other: &Self) -> bool { + std::ptr::eq(self as *const _, other as *const _) + } +} + +impl Eq for State {} + +#[turbo_tasks::function] +async fn non_deterministic(state: Vc) { + let state = state.await.unwrap(); + let mut state_inner = state.inner.lock().unwrap(); + + let task_id = if state_inner.branch { + let c: Vc>> = Vc::cell(Some(Vc::cell(1))); + println!("u8 branch"); + Vc::into_raw(c).get_task_id() + } else { + let c: Vc>> = Vc::cell(Some(Vc::cell(1))); + println!("u32 branch"); + Vc::into_raw(c).get_task_id() + }; + + state_inner.branch = !state_inner.branch; + if let Some(last_task_id) = state_inner.last_task_id { + assert_eq!(last_task_id, task_id); + } + state_inner.last_task_id = Some(task_id); + state_inner.last_invalidator = Some(turbo_tasks::get_invalidator()); +}