Skip to content

Commit

Permalink
feat: handle return error
Browse files Browse the repository at this point in the history
  • Loading branch information
mrchantey committed Jan 13, 2025
1 parent 8fe7783 commit 2ef4610
Show file tree
Hide file tree
Showing 9 changed files with 109 additions and 63 deletions.
2 changes: 1 addition & 1 deletion crates/sweet_rsx/src/sweet_loader/sweet_loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,5 @@ mod test {
use sweet::prelude::*;

#[test]
fn works() { expect(true).to_be_false(); }
fn works() {}
}
21 changes: 19 additions & 2 deletions crates/sweet_test/src/wasm/js_runtime_extern.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ pub mod js_runtime {
#[wasm_bindgen(catch)]
/// Just run the function outside of the wasm boundary
/// ie `const panic_to_error = (f)=>f()`
pub fn panic_to_error(f: &mut dyn FnMut()) -> Result<(), JsValue>;
pub fn panic_to_error(
f: &mut dyn FnMut() -> Result<(), String>,
) -> Result<(), JsValue>;
#[wasm_bindgen]
/// Read a file from the filesystem, ie `Deno.read_file()`
pub fn read_file(path: &str) -> Option<String>;
Expand All @@ -29,9 +31,24 @@ mod test {
use crate::prelude::*;

#[test]
fn works() {
fn cwd() { expect(js_runtime::cwd()).to_contain("sweet"); }

#[test]
#[ignore = "take hook shenanigans"]
// #[should_panic]
fn panic_to_error() {
let result = js_runtime::panic_to_error(&mut || panic!("it panicked"));
expect(&format!("{:?}", result))
.to_start_with("Err(JsValue(RuntimeError: unreachable");
}
#[test]
fn read_file() {
expect(js_runtime::read_file("foobar")).to_be_none();
expect(js_runtime::read_file("Cargo.toml")).to_be_some();
// expect(js_runtime::read_file("Cargo.lock")).to_be_some();
}
#[test]
fn sweet_root() {
expect(js_runtime::sweet_root().unwrap()).to_end_with("sweet/");
}
}
59 changes: 57 additions & 2 deletions crates/sweet_test/src/wasm/panic_store.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,67 @@
use crate::prelude::*;
use core::fmt;
use flume::Sender;
use std::cell::RefCell;
use std::panic::PanicHookInfo;
use std::rc::Rc;
use test::TestDesc;
use wasm_bindgen::JsValue;


/// A completed test that maybe panicked
pub enum PanicStoreOut<T> {
Panicked(TestDescAndResult),
Ok(T),
/// maybe returned error
NoPanic(T),
}

impl<T> PanicStoreOut<T> {
pub fn panicked(&self) -> bool {
match self {
PanicStoreOut::Panicked(_) => true,
PanicStoreOut::NoPanic(_) => false,
}
}
}

impl<T: fmt::Debug> fmt::Debug for PanicStoreOut<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
PanicStoreOut::Panicked(result) => {
write!(f, "Panicked({:?})", result)
}
PanicStoreOut::NoPanic(result) => {
write!(f, "NoPanic({:?})", result)
}
}
}
}

impl<T> PanicStoreOut<Result<T, JsValue>> {
pub fn send(self, result_tx: &Sender<TestDescAndResult>, desc: &TestDesc) {
match self {
PanicStoreOut::Panicked(result) => {
result_tx.send(result).expect("channel was dropped");
}
PanicStoreOut::NoPanic(Err(err)) => {
let test_result = TestResult::from_test_result(
Err(err
.as_string()
.expect("all test errors should be strings")),
desc,
);
result_tx
.send(TestDescAndResult::new(desc.clone(), test_result))
.expect("channel was dropped");
}
PanicStoreOut::NoPanic(Ok(_)) => {
let test_result = TestResult::from_test_result(Ok(()), desc);
result_tx
.send(TestDescAndResult::new(desc.clone(), test_result))
.expect("channel was dropped");
}
}
}
}


Expand Down Expand Up @@ -58,7 +113,7 @@ impl PanicStore {
(Some(panic_result), _) => PanicStoreOut::Panicked(
TestDescAndResult::new(desc.clone(), panic_result),
),
(None, result) => PanicStoreOut::Ok(result),
(None, result) => PanicStoreOut::NoPanic(result),
}
})
}
Expand Down
3 changes: 1 addition & 2 deletions crates/sweet_test/src/wasm/run_libtest_wasm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,7 @@ pub async fn run_with_pending() -> Result<(), JsValue> {

let futs = futures.into_iter().map(|fut| async {
TestFuture::new(fut.desc, result_tx.clone(), async move {
(fut.fut)().await.ok();
Ok(JsValue::NULL)
(fut.fut)().await
})
.await;
});
Expand Down
42 changes: 6 additions & 36 deletions crates/sweet_test/src/wasm/run_wasm_tests.rs
Original file line number Diff line number Diff line change
@@ -1,61 +1,31 @@
use crate::prelude::*;
use flume::Sender;
use forky::web::ClosureFnMutT2Ext;
use test::TestDescAndFn;
use wasm_bindgen::prelude::Closure;
use wasm_bindgen::JsCast;
use wasm_bindgen::JsValue;


/// Run sync tests, and return async tests
pub fn run_wasm_tests_sync(
tests: Vec<TestDescAndFn>,
result_tx: &Sender<TestDescAndResult>,
) -> Vec<TestDescAndFuture> {
tests
.into_iter()
.filter_map(|test| {
let func = TestDescAndFnExt::func(&test);
let mut func = TestDescAndFnExt::func(&test);

let result = SweetTestCollector::with_scope(&test.desc, || {
PanicStore::with_scope(&test.desc, || {
// dont worry if it returned error, we will catch the panic
run_no_abort(func)
js_runtime::panic_to_error(&mut func)
})
});

match result {
Ok(PanicStoreOut::Panicked(result)) => {
result_tx.send(result).expect("channel was dropped");
None
}
Ok(PanicStoreOut::Ok(_)) => {
let test_result =
TestResult::from_test_result(Ok(()), &test.desc);
result_tx
.send(TestDescAndResult::new(
test.desc.clone(),
test_result,
))
.expect("channel was dropped");
Ok(panic_out) => {
panic_out.send(result_tx, &test.desc);
None
}
Err(val) => Some(val),
}
})
.collect()
}

/// this function may panic. In js that will abort execution
/// so we send it out of the wasm boundary
/// TODO try the wb_test func might be cheaper than closure
fn run_no_abort(func: fn() -> Result<(), String>) {
// fn run_no_abort(func: fn() -> Result<(), String>) -> Result<(), String> {
let closure = Closure::from_func_no_args(move || {
TestDescExt::result_to_panic(func());
});
let func: &js_sys::Function = closure.as_ref().unchecked_ref();
func.call0(&JsValue::NULL).ok();
// match func.call0(&JsValue::NULL) {
// Ok(_) => Ok(()),
// Err(err) => Err(format!("{:?}", err)),
// }
}
37 changes: 18 additions & 19 deletions crates/sweet_test/src/wasm/test_future.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ impl<F> TestFuture<F> {
}
}

impl<F: Future<Output = Result<JsValue, JsValue>>> Future for TestFuture<F> {
impl<F: Future<Output = Result<(), String>>> Future for TestFuture<F> {
type Output = ();

fn poll(
Expand All @@ -46,37 +46,36 @@ impl<F: Future<Output = Result<JsValue, JsValue>>> Future for TestFuture<F> {
let result_tx = &self_mut.result_tx;
let mut future_poll_output = None;

// did it panic during this poll
// this should only be used if poll::ready!
let panic_output = PanicStore::with_scope(desc, || {
let mut test = Some(test);
js_runtime::panic_to_error(&mut || {
let test = test.take().unwrap_throw();
future_poll_output = Some(test.poll(cx))
let out = test.poll(cx);
future_poll_output = Some(match &out {
Poll::Ready(_) => Poll::Ready(()),
Poll::Pending => Poll::Pending,
});
match out {
Poll::Ready(Err(err)) => Err(err),
_ => Ok(()),
}
})
});

match panic_output {
PanicStoreOut::Panicked(test_desc_and_result) => {
result_tx
.send(test_desc_and_result)
.expect("channel was dropped");
return Poll::Ready(());
}
PanicStoreOut::Ok(_) => {
// could be pending
}
// panicked futures will never be ready
if panic_output.panicked() {
panic_output.send(result_tx, desc);
return Poll::Ready(());
}

match future_poll_output {
Some(Poll::Pending) => Poll::Pending,
_ => {
let test_result = TestResult::from_test_result(Ok(()), &desc);
result_tx
.send(TestDescAndResult::new(desc.clone(), test_result))
.expect("channel was dropped");

Some(Poll::Ready(())) => {
panic_output.send(result_tx, desc);
Poll::Ready(())
}
None => Poll::Pending,
}
}
}
6 changes: 5 additions & 1 deletion crates/sweet_test/tests/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,13 @@ fn it_panics_sync() { panic!("foo") }
async fn it_passes() {}
#[sweet::test]
async fn it_returns_ok() -> Result<(), String> { Ok(()) }
#[test]
#[ignore = "it returns error"]
fn it_returns_err() -> Result<(), String> { Err("foo".to_string()) }

#[sweet::test]
#[ignore = "it returns error"]
async fn it_returns_err() -> Result<(), String> { Err("foo".to_string()) }
async fn it_returns_err_async() -> Result<(), String> { Err("foo".to_string()) }

#[sweet::test]
#[should_panic]
Expand Down
1 change: 1 addition & 0 deletions crates/sweet_test/tests/sweet_macro.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
//! used for cargo expand
#![cfg_attr(test, feature(test, custom_test_frameworks))]
#![cfg_attr(test, test_runner(sweet::test_runner))]

Expand Down
1 change: 1 addition & 0 deletions justfile
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ test-all *args:
cargo test --workspace -- {{args}}
cargo test -p sweet_rsx --lib --target wasm32-unknown-unknown -- {{args}}
cargo test -p sweet_test --lib --target wasm32-unknown-unknown -- {{args}}
cargo test -p sweet_test --test macros --target wasm32-unknown-unknown -- {{args}}

expand-wasm test *args:
just watch 'cargo expand --test {{test}} --target wasm32-unknown-unknown {{args}}'
Expand Down

0 comments on commit 2ef4610

Please sign in to comment.