-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add/move tests for Vc generics (#8843)
## Description - Move the tests out of `all_in_one` so that we can see exactly which parts are failing more easily. - Add a few more tests. **The newly added `test_read_ref_round_trip` fails** (and is ignored), indicating a bug in the generics implementation!!! This is fixed in #8845. ## Why does `test_read_ref_round_trip` fail? The theory is that Vcs are supposed to be stored as `<<T as VcValueType>::Read as VcRead<T>>::Repr`. However, it looks like due to an oversight, `ReadRef::cell` is trying to store the value as `T`. ## Why add these tests at all? The plan (as of yesterday) is to remove support for generics, but I'd feel more confident if I can fix the casting issues in my local Vc PRs before I do that. These tests should help me understand what's happening and debug things. ## Testing Instructions ``` cargo nextest r -p turbo-tasks -p turbo-tasks-memory ```
- Loading branch information
Showing
2 changed files
with
204 additions
and
57 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<Option<Vc<u32>>> = 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<Option<Vc<u32>>> = 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<Vec<Vc<u32>>> = 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<Vec<Vc<u32>>> = 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<Vec<Vc<Vec<Vc<u32>>>>> = 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<IndexSet<Vc<u32>>> = 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<IndexSet<Vc<u32>>> = Default::default(); | ||
assert_eq!(*set.len().await.unwrap(), 0); | ||
assert_eq!(*set.is_empty().await.unwrap(), true); | ||
assert_eq!(&*set.await.unwrap(), &IndexSet::<Vc<u32>>::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<IndexMap<Vc<u32>, _>> = 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<IndexMap<Vc<u32>, Vc<u32>>> = Default::default(); | ||
assert_eq!(*map.len().await.unwrap(), 0); | ||
assert_eq!(*map.is_empty().await.unwrap(), true); | ||
assert_eq!( | ||
&*map.await.unwrap(), | ||
&IndexMap::<Vc<u32>, Vc<u32>>::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<Option<Vc<u8>>> = 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<Mutex<StateInner>>, | ||
} | ||
|
||
#[derive(Default)] | ||
struct StateInner { | ||
branch: bool, | ||
last_invalidator: Option<Invalidator>, | ||
last_task_id: Option<TaskId>, | ||
} | ||
|
||
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<State>) { | ||
let state = state.await.unwrap(); | ||
let mut state_inner = state.inner.lock().unwrap(); | ||
|
||
let task_id = if state_inner.branch { | ||
let c: Vc<Option<Vc<u8>>> = Vc::cell(Some(Vc::cell(1))); | ||
println!("u8 branch"); | ||
Vc::into_raw(c).get_task_id() | ||
} else { | ||
let c: Vc<Option<Vc<u32>>> = 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()); | ||
} |