Skip to content

Commit 021d9c4

Browse files
committed
test: clean up async boundary test
1 parent ce56465 commit 021d9c4

File tree

3 files changed

+151
-279
lines changed

3 files changed

+151
-279
lines changed

crates/cli/src/tests.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
mod async_context_test;
1+
mod async_boundary_test;
22
mod corpus_test;
33
mod detect_language;
44
mod helpers;
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
use std::{
2+
future::Future,
3+
pin::Pin,
4+
ptr,
5+
task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
6+
};
7+
8+
use tree_sitter::Parser;
9+
10+
use super::helpers::fixtures::get_language;
11+
12+
#[test]
13+
fn test_node_across_async_boundaries() {
14+
let mut parser = Parser::new();
15+
let language = get_language("bash");
16+
parser.set_language(&language).unwrap();
17+
let tree = parser.parse("#", None).unwrap();
18+
let root = tree.root_node();
19+
20+
let (result, yields) = simple_async_executor(async {
21+
let root_ref = &root;
22+
23+
// Test node captured by value
24+
let fut_by_value = async {
25+
yield_once().await;
26+
root.child(0).unwrap().kind()
27+
};
28+
29+
// Test node captured by reference
30+
let fut_by_ref = async {
31+
yield_once().await;
32+
root_ref.child(0).unwrap().kind()
33+
};
34+
35+
let result1 = fut_by_value.await;
36+
let result2 = fut_by_ref.await;
37+
38+
assert_eq!(result1, result2);
39+
result1
40+
});
41+
42+
assert_eq!(result, "comment");
43+
assert_eq!(yields, 2);
44+
}
45+
46+
#[test]
47+
fn test_cursor_across_async_boundaries() {
48+
let mut parser = Parser::new();
49+
let language = get_language("c");
50+
parser.set_language(&language).unwrap();
51+
let tree = parser.parse("#", None).unwrap();
52+
let mut cursor = tree.walk();
53+
54+
let ((), yields) = simple_async_executor(async {
55+
cursor.goto_first_child();
56+
57+
// Test cursor usage across yield point
58+
yield_once().await;
59+
cursor.goto_first_child();
60+
61+
// Test cursor in async block
62+
let cursor_ref = &mut cursor;
63+
let fut = async {
64+
yield_once().await;
65+
cursor_ref.goto_first_child();
66+
};
67+
fut.await;
68+
});
69+
70+
assert_eq!(yields, 2);
71+
}
72+
73+
#[test]
74+
fn test_node_and_cursor_together() {
75+
let mut parser = Parser::new();
76+
let language = get_language("javascript");
77+
parser.set_language(&language).unwrap();
78+
let tree = parser.parse("#", None).unwrap();
79+
let root = tree.root_node();
80+
let mut cursor = tree.walk();
81+
82+
let ((), yields) = simple_async_executor(async {
83+
cursor.goto_first_child();
84+
85+
let fut = async {
86+
yield_once().await;
87+
let _ = root.to_sexp();
88+
cursor.goto_first_child();
89+
};
90+
91+
yield_once().await;
92+
fut.await;
93+
});
94+
95+
assert_eq!(yields, 2);
96+
}
97+
98+
fn simple_async_executor<F>(future: F) -> (F::Output, u32)
99+
where
100+
F: Future,
101+
{
102+
let waker = noop_waker();
103+
let mut cx = Context::from_waker(&waker);
104+
let mut yields = 0;
105+
let mut future = Box::pin(future);
106+
107+
loop {
108+
match future.as_mut().poll(&mut cx) {
109+
Poll::Ready(result) => return (result, yields),
110+
Poll::Pending => yields += 1,
111+
}
112+
}
113+
}
114+
115+
async fn yield_once() {
116+
struct YieldOnce {
117+
yielded: bool,
118+
}
119+
120+
impl Future for YieldOnce {
121+
type Output = ();
122+
123+
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
124+
if self.yielded {
125+
Poll::Ready(())
126+
} else {
127+
self.yielded = true;
128+
cx.waker().wake_by_ref();
129+
Poll::Pending
130+
}
131+
}
132+
}
133+
134+
YieldOnce { yielded: false }.await;
135+
}
136+
137+
const fn noop_waker() -> Waker {
138+
const VTABLE: RawWakerVTable = RawWakerVTable::new(
139+
// Cloning just returns a new no-op raw waker
140+
|_| RAW,
141+
// `wake` does nothing
142+
|_| {},
143+
// `wake_by_ref` does nothing
144+
|_| {},
145+
// Dropping does nothing as we don't allocate anything
146+
|_| {},
147+
);
148+
const RAW: RawWaker = RawWaker::new(ptr::null(), &VTABLE);
149+
unsafe { Waker::from_raw(RAW) }
150+
}

0 commit comments

Comments
 (0)